w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 666 forks source link

[css-values] Use of 100vw is causing pointless horizontal scrollbars on some websites #6026

Closed simevidas closed 8 months ago

simevidas commented 3 years ago

Windows users and macOS users that have enabled “Show scroll bars: Always” are seeing pointless horizontal scrollbars on some websites that use the 100vw value. One common use-case for 100vw are full-width elements:

.full-width {
    width: 100vw;
    position: relative;
    left: 50%;
    right: 50%;
    margin-left: -50vw;
    margin-right: -50vw;
}

Examples:

If you can’t check for yourself and are not sure what a pointless horizontal scrollbar is, watch this video that I posted on Twitter.

The authors of these websites are most likely not aware of this issue because they developed the website on macOS with default (overlaid) scrollbars, where this issue does not occur.

As a result, many people are experiencing these pointless horizontal scrollbars, and a fair share of these people probably find them annoying (raises hand 🙋‍♂️).

Does the Working Group consider this to be a problem that requires an intervention? Are there any proposed features or changes that could help make this problem go away over time?

emilio commented 11 months ago

@bfgeek those would be less wide than needed, but that seems fine to me, it's already what happens in platforms with overlay scrollbars, right?

tabatkins commented 11 months ago

@brunoais

Why not move that resolution to 100 dvw & 100 dvh

The resolution applies to all of the viewport units.

bfgeek commented 11 months ago

@bfgeek those would be less wide than needed, but that seems fine to me, it's already what happens in platforms with overlay scrollbars, right?

@emilio Lots of enterprise like apps use ::-webkit-scrollbar to force a scrollbar to exist.

kizu commented 11 months ago

This resolution might be a little scary for existing sites who are already working around this problem via something like: width: calc(100vw - var(--scrollbar-width))

I might confirm that in our product we have at least 12 places where we have almost exactly this: we detect the current scrollbar width, apply it as a variable, and then subtract when necessary from the 100vw.

That said, we're not using overflow: scroll or scrollbar-gutter: stable on the root scroller, so for us this should be safe. And, overall, that requirement would probably reduce the potential impact.

Then, the impact itself would usually not be very drastic, in most cases resulting in something being a bit narrower than necessary. Still a concern, though.

tabatkins commented 11 months ago

Yeah, scrollbar-gutter has relatively low usage right now, as does overflow:scroll on the root (as opposed to auto). And the failure mode is "things are slightly narrower than they should be", which is generally pretty okay (as opposed to the current failure mode of people naively using 100vw and testing on overlay-scrollbar browsers, which is "horizontal scrollbars on everything that just barely wiggle back and forth", a much more annoying failure mode).

bramus commented 11 months ago

Some situation that came to mind today:

  1. Say the window’s innerWidth is 1000px. After subtracting the scrollbar-width (assuming a classic 16px) that would have 100vw be computed to 984px.
  2. Now say on the page you have a scrollable <div> with a width of 50vw. Taking half of 984px, that would give it a width of 492px. Because of its scrollbar, there’s “only” 476px available space inside of it left though.
  3. Now comes the part where authors might get tripped up: if they then size something inside that <div> to be 50vw, they will end up with a horizontal scrollbar again, as the computed width is 492px and not the leftover 476px.

If you know what’s happening that is expected behavior, yet it might trip up some authors. It also underlines that this automatic subtraction only solves the 100vw case on the root scroller. A solution with an envvar would allow fixing all those cases, but puts the burden on the author to take it into account.

Related to the third bullet point above: in that case, maybe we should also do the same for 100cqi with the same conditions on the container? Demo: https://codepen.io/bramus/pen/rNPqOZe

brunoais commented 11 months ago

Some situation that came to mind today:

That's part of why I think this should be applied only to dvh and dvw. I think we shouldn't break such year long used variables and let's just break the ones that were already designed from the ground up to work like that.

simevidas commented 11 months ago

maybe we should also do the same for 100cqi with the same conditions on the container?

This kind-of makes it look like it’s not a good idea to turn scroll containers into inline-size query containers in general. We might be seeing a repeat of the 100vw problem in the future where developers test their CSS only in browsers with overlay scrollbars, and they’re not aware that their container query units are causing horizontal scrollbars.

markcellus commented 11 months ago

I think this should be applied to dvh and dvw.

Agree. It would be surprising if not. In fact, I was already assuming in other talks that everywhere we were saying "vw", it was assumed to also apply to "dvw". :laughing:

brunoais commented 11 months ago

@markcellus I wasn't explicit enough, sorry. I fixed it.

tabatkins commented 11 months ago

Now comes the part where authors might get tripped up: if they then size something inside that

to be 50vw, they will end up with a horizontal scrollbar again, as the computed width is 492px and not the leftover 476px.

I'm confused. That would happen regardless - if the 50vw-wide div has scrollbars, its inner width is going to be less than 50vw no matter how we define vw.

A solution with an envvar would allow fixing all those cases, but puts the burden on the author to take it into account.

Also not sure what you mean here. How would an env() make this case work?

astearns commented 11 months ago

I removed the Agenda+ tag for now because the debate here seems ongoing.

bfgeek commented 11 months ago

@astearns I think we still want to undo the previous resolution to reconsider

astearns commented 11 months ago

I have not yet seen that you have convinced anyone else about this. From my personal perspective some loss of usable width in some (fixable?) cases is preferable to an unwanted horizontal scrollbar

bfgeek commented 11 months ago

I have not yet seen that you have convinced anyone else about this.

I think I have?

brunoais commented 11 months ago

I request to consider not adding the latest resolution to 100vw and 100vh but all the other vw and vh is OK.

simevidas commented 11 months ago

I request to consider not adding the latest resolution to 100vw and 100vh but all the other vw and vh is OK.

@brunoais What’s the risk here? Are there websites with overflow: scroll (or scrollbar-gutter: stable) on <html> that don’t want 100vw to shrink by a very small amount? What exactly could break?

brunoais commented 11 months ago

The issue is mostly on the designers. They are SUPER picky about even a pixel off. Where I work at, there's an idea about background coloring on <html> and they are already using a hack with 100vw. This will cause inconsistency among the tested environments with a mix of older browsers (because our clients don't update as often. Some are still using browsers from 2021 for some reason).

If my request is rejected, so be it but that's my reality.

simevidas commented 11 months ago

@brunoais Most of them probably don’t set overflow: scroll on <html> to begin with, but even if they do, they can opt out of the new behavior by switching to overflow: auto. So the only problem are websites that need to set overflow: scroll for whatever reason and use calc(100vw - 16px) hacks at the same time. There’s probably not many such websites.

mdmoreau commented 11 months ago

Is it possible to create a property similar to box-sizing (viewport-sizing?) that only works on :root? That way people could explicitly opt in to the behavior, similar to the way most sites use box-sizing: border-box instead of the default content-box.

bramus commented 11 months ago

Now comes the part where authors might get tripped up: if they then size something inside that to be 50vw, they will end up with a horizontal scrollbar again, as the computed width is 492px and not the leftover 476px.

(#) I'm confused. That would happen regardless - if the 50vw-wide div has scrollbars, its inner width is going to be less than 50vw no matter how we define vw.

I know that will happen regardless, but it might trip up authors as vw on root does account for the root scrollbar but when used elsewhere it does not take the (direct) parent scroller’s scrollbar into account.

That confusion could be solved by doing something similar for cqi/cqw under the same conditions which I also suggested) and @mirisuzanne also hinted at this before.

(This looks like food for a follow-up issue)

A solution with an envvar would allow fixing all those cases, but puts the burden on the author to take it into account.

(#) Also not sure what you mean here. How would an env() make this case work?

The env() proposal would allow authors to manually take the size of the scrollbar into account. It is a fixed value that represents the default scrollbar size. This would work for both the viewport and containers.

width: calc(100vw) - env(scrollbar-inline-size);
width: calc(100cqw) - env(scrollbar-inline-size);

This mimics what authors are currently doing, with the different that the scrollbar-width is reported by the browser here.

But, as @emilio mentioned, this would also require a way to detect classic scrollbars. It would also require a way to detect if something is scrolling or not … which would make this all very complicated for authors to implement, as demonstrated in this snippet I presented at the 2023 summer F2F.

So yeah, maybe this envvar() route isn’t the preferable path indeed … too much jumping through hoops.


Winging back to @bfgeek’s concern: I’ve asked some colleagues to query the HTTP archive to see:

  1. How often the width: calc(100vw - var(--scrollbar-width)) pattern is used.
  2. How often overflow: scroll or scrollbar-gutter: stable on the :root is used.
  3. How often both are used together

I’m still waiting on the results of these queries.

coreyworrell commented 11 months ago

Some use cases: most of our sites uses overflow: scroll on the root to avoid layout shift between pages (first page does not cause overflow, next page does) or between UI states (toggling a details summary item causes scrollbar to appear).

These sites often have modal UI that hides overflow on root (overscroll-behavior: contain will not work if modal itself is not large enough to cause scrolling, and only applies if pointer is inside the modal anyways), and extra padding equal to the scrollbar width must be applied to avoid layout shift when showing/hiding the modal (as the scollbar hides and shows respectively).

Dropdown menus with absolutely positioned children (ie: full width dropdown that "breaks out" of it's parent), rely on using the width: calc(100vw - var(--scrollbar-width)) pattern.

bramus commented 9 months ago

Winging back to @bfgeek’s concern: I’ve asked some colleagues to query the HTTP archive to see:

  1. How often the width: calc(100vw - var(--scrollbar-width)) pattern is used.
  2. How often overflow: scroll or scrollbar-gutter: stable on the :root is used.
  3. How often both are used together

I’m still waiting on the results of these queries.

I ran some tests and here are the results: In total 12,089,606 root pages found in the HTTP Archive November 2023 Dataset were scanned. Out of those 12 million scanned pages:

Of those 72 pages, only 38 seem to use the calc() expression to cater for scrollbars (0.0003143195899%). The ignored 34 pages did a calculation with a <length> greater than 50px which seems like an unlikely width for a scrollbar to have.

Conclusion: If we change how 100vw computes when overflow: scroll is set on root, 0.0003143195899% of the pages found in the HTTP Archive November 2023 Dataset will be affected by the change we resolved on.

css-meeting-bot commented 8 months ago

The CSS Working Group just discussed [css-values] Use of 100vw is causing pointless horizontal scrollbars on some websites, and agreed to the following:

The full IRC log of that discussion <TabAtkins> iank_: I think now, with Bramus's data, this is likely fine
<TabAtkins> iank_: Bramus did a lot of analysis on it. still a little concerned, but someone can take the risk and see what happens
<fantasai> Bramus wins MVP of the issue! \^_^/
<fantasai> TabAtkins: When overflow is set on the root element (specifically; not body), we will take the scrollbars into account when calculating viewport unit sizes
<TabAtkins> iank_: Yes, specifying overflow:scroll on the root is sufficiently rare that people shouldn't run into this
<TabAtkins> iank_: Probably won't solve the general case on existing sites, but people can fix it moving forward
<TabAtkins> iank_: One caveat is that enterprise is always hidden in this type of analysis, so if someone rolls it out there might be a hidden part that changes our resolution
<TabAtkins> TabAtkins: +1
<TabAtkins> fantasai: Why didn't we want to do it for body propagation? Too common?
<TabAtkins> iank_: yes, I think itwould break way too many sites
<TabAtkins> fantasai: Other thing in the thread is having the dv* units respond to scrollbar
<astearns> previous resolution: https://github.com/w3c/csswg-drafts/issues/6026#issuecomment-1832443514
<TabAtkins> fantasai: So I guess it would make sense to say that dv* would respond to scrollbar...
<TabAtkins> TabAtkins: dv* units are always between small and large units, right now; we should be careful about losing that
<TabAtkins> astearns: I linked to the existing resolution that already covers this, this discussion is about us not undoing that
<TabAtkins> Rossen_: so keep no change?
<TabAtkins> Rossen_: Objections?
<TabAtkins> RESOLVED: No change, keep with the existing resolution
<TabAtkins> Rossen_: do we need something for the dv units?
<TabAtkins> fantasai: No, we should do that in a separate issue
<miriam> q+
<TabAtkins> miriam: do we also need, in the new issue, to mention CQ units?
<Rossen_> ack miriam
<TabAtkins> fantasai: would need to be a more separate issue
fantasai commented 8 months ago

Edits are done for the WG resolution in https://github.com/w3c/csswg-drafts/issues/6026#issuecomment-1832443514 and filed follow-up wrt dv* etc in https://github.com/w3c/csswg-drafts/issues/10059