Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
simevidas opened this issue Feb 22, 2021 · 75 comments

Comments

@simevidas
Copy link
Contributor

simevidas commented Feb 22, 2021

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
Copy link
Collaborator

emilio commented Feb 22, 2021

See #1766. Not very easy to do them auto-magically work because it'd be cyclic (declarations using vw units could cause scrollbars to appear which would change how vw would resolve).

It'd be feasible to make them work with with overflow: scroll, but only Firefox implemented that and nobody else did so we removed that...

@emilio emilio closed this as completed Feb 22, 2021
@simevidas
Copy link
Contributor Author

@emilio I did not suggest to make changes to viewport units. I asked if the Working Group plans to do something about the problem of pointless horizontal scrollbars that appear on some websites, a problem that I predict will not go away on its own. Does this problem require an intervention or can it be ignored?

@emilio
Copy link
Collaborator

emilio commented Feb 22, 2021

I guess we can reopen, but it's hard to say from a web engine when a scrollbar is "useless" if there's content overflowing.

@emilio emilio reopened this Feb 22, 2021
@felipeerias
Copy link

Related: #5254

@felipeerias
Copy link

Also related: #5232

@coreyworrell
Copy link

Not very easy to do them auto-magically work because it'd be cyclic (declarations using vw units could cause scrollbars to appear which would change how vw would resolve).

Percentages are not cyclic now, so why couldn't vw (or new unit) be equivalent to "percentage of root element"? Every single time I've used vw units, I don't care one little bit how wide the viewport is if part of it is being covered by a scrollbar. I only care what part of the viewport I can "draw" the element in without causing horizontal scrolling. If my element is direct child of the body, this is super easy, 100% (or just don't specify any width is element is block).

<body>
  <div class="one" style="width: 100%;"></div>
  <div class="two" style="width: 50%;">
    <div class="two-child" style="width: 100vw;"></div>
  </div>
</body>

.one and .two-child should resolve as same exact width regardless of vertical scrollbar being visible or not. Can we make this happen somehow?

@emilio
Copy link
Collaborator

emilio commented Feb 26, 2021

Percentages are not cyclic now, so why couldn't vw (or new unit) be equivalent to "percentage of root element"?

Because percentages aren't resolved until layout, while viewport units are. More generally, content inside the viewport can't affect the viewport size, but it can affect whether the root element shows scrollbars or not.

@coreyworrell
Copy link

@emilio Okay so why not create a new unit (or modify vw) that resolves at layout like percentage?

@emilio
Copy link
Collaborator

emilio commented Feb 26, 2021

Well, that is one option. Note that that would behave subtly differently than the current viewport units. Adding layout-time relative units is relatively hard (no pun intended) compared to adding units that resolve at computed-value time like vh / vw. Though definitely not impossible.

@bramus
Copy link
Contributor

bramus commented Feb 26, 2021

Also related: #4329

@coreyworrell
Copy link

@emilio I don't know too much about the actual rendering processes, but this description makes it seem like it would be easier to calculate as there wouldn't need to be any tree traversal to compute, there would just be the one root node to be concerned with. But I understand there has to be more to it.

Up to this point we've calculated which nodes should be visible and their computed styles, but we have not calculated their exact position and size within the viewport of the device---that's the "layout" stage, also known as "reflow."

To figure out the exact size and position of each object on the page, the browser begins at the root of the render tree and traverses it.

The body of the above page contains two nested div's: the first (parent) div sets the display size of the node to 50% of the viewport width, and the second div---contained by the parent---sets its width to be 50% of its parent; that is, 25% of the viewport width.

Very confusing as their use of "viewport width" isn't the same as the vw unit, which you would reasonably assume.

@johannesodland
Copy link

Also related: #4691

@simevidas
Copy link
Contributor Author

@frivoal
Copy link
Collaborator

frivoal commented Apr 15, 2021

It'd be feasible to make them work with with overflow: scroll, but only Firefox implemented that and nobody else did so we removed that...

I'm thinking we should go back to making them work with overflow: scroll and also with scrollbar-gutter:stable and scrollbar-gutter:alwaysset on the root.

@hyperfekt
Copy link

hyperfekt commented Jun 8, 2021

Is my understanding correct that there is currently no way to size elements to the viewport minus the scrollbar while also having non-floating elements outside the viewport, since using 100% to size them would give them a size larger than the viewport, and using 100vh/100vw to size them will have part of them obscured by the scrollbar?

EDIT: Apparently it is not. The root element's width can be inherited to any place in the document by having anything outside the viewport overflow it.

@um83
Copy link

um83 commented Jun 8, 2021

I suppose, that a new unit should be implemented, which determine viewport width and height without scrollbars.
Without that it's not possible to make some cool stuff like horizontal document scrolling with sticky headers.
Here's what I'm talking about: https://codepen.io/um83/pen/LYWBEmY

@brunoais
Copy link

brunoais commented Jun 8, 2021

I suppose, that a new unit should be implemented, which determine viewport width and height without scrollbars.
Without that it's not possible to make some cool stuff like horizontal document scrolling with sticky headers.
Here's what I'm talking about: https://codepen.io/um83/pen/LYWBEmY

this? #6113

@um83
Copy link

um83 commented Jun 8, 2021

this? #6113

yep! exactly!

@jonjohnjohnson
Copy link

I'm thinking we should go back to making them work with overflow: scroll and also with scrollbar-gutter:stable and scrollbar-gutter:alwaysset on the root.

@frivoal Do you think you'd still rather go this way instead of having non-overlay scrollbars (both inline and block) affect the new sv* and/or dv* units? See #4329 (comment)

@mor10
Copy link

mor10 commented Jul 15, 2021

To approach this from a "how does someone without in-depth knowledge of the functionings of the browser understand the concept of the viewport" perspective, I've talked to developers frustrated by this issue. The mental model boils down to this:

  • When a scrollbar is fixed (as on Windows), the expectation is for the viewport width to be the width of the active canvas (so viewport minus scrollbar) because the scrollbar is understood as part of the chrome, not the viewport.
  • When a scrollbar is dynamic (as on MacOS), the expectation is for the viewport width to be the width of the full viewport, and the dynamic scrollbar is seen as an overlay on top of the active canvas, so no change should happen to the width value when the scrollbar appears/disappears.

From this perspective, which is the user perspective in this context, the implementation of any new units like dv* should be as close to the visually understood behavior as possible, ie if something looks to be part of the chrome, it is treated as part of the chrome, and if something looks to be an overlay, it is treated as an overlay.

@brunoais
Copy link

Maybe the distinguishing factor is whether the thing (scroll bar, in your example) is visible when the user is idling (I.e. not interacting with the page).
As a preliminary condition: If it disappears when interaction stops, it's non-counted overlay. If it stays (such as the browser toolbar in mobile browsers), it's counted overlay and taken into account with the dv* units.

What do you think?

@mor10
Copy link

mor10 commented Jul 16, 2021

@brunoais Yes, that's a different (and possibly clearer) way of saying the same thing.

@bfgeek
Copy link

bfgeek commented Dec 6, 2023

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

I think I have?

@brunoais
Copy link

brunoais commented Dec 6, 2023

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

@simevidas
Copy link
Contributor Author

simevidas commented Dec 6, 2023

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
Copy link

brunoais commented Dec 6, 2023

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
Copy link
Contributor Author

@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
Copy link

mdmoreau commented Dec 6, 2023

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
Copy link
Contributor

bramus commented Dec 7, 2023

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
Copy link

coreyworrell commented Dec 11, 2023

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
Copy link
Contributor

bramus commented Jan 31, 2024

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:

  • 324,866 use the calc(100vw - <length>) pattern (2.6871512603%)
  • 4,112 have overflow: scroll declared on the root element (0.03401268825%)
  • 72 pages use both (0.0005955529072%)

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.

@astearns astearns added this to Unsorted regular in Feb 2024 Agenda Feb 8, 2024
@astearns astearns moved this from Unsorted regular to Tuesday afternoon in Feb 2024 Agenda Feb 8, 2024
@astearns astearns moved this from Tuesday afternoon to Wednesday afternoon in Feb 2024 Agenda Feb 11, 2024
@w3c w3c deleted a comment from css-meeting-bot Mar 7, 2024
@css-meeting-bot
Copy link
Member

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

  • RESOLVED: No change, keep with the existing resolution
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//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
Copy link
Collaborator

fantasai commented Mar 11, 2024

Edits are done for the WG resolution in #6026 (comment) and filed follow-up wrt dv* etc in #10059

fantasai added a commit to web-platform-tests/wpt that referenced this issue Mar 11, 2024
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Mar 14, 2024
…or scrollbars, a=testonly

Automatic update from web-platform-tests
[css-values-4] Add viewport unit tests for scrollbars

w3c/csswg-drafts#6026

--

wpt-commits: 82a8422a00e43a2327d0f22c5941a23294f2ecb9
wpt-pr: 45036
jamienicol pushed a commit to jamienicol/gecko that referenced this issue Mar 17, 2024
…or scrollbars, a=testonly

Automatic update from web-platform-tests
[css-values-4] Add viewport unit tests for scrollbars

w3c/csswg-drafts#6026

--

wpt-commits: 82a8422a00e43a2327d0f22c5941a23294f2ecb9
wpt-pr: 45036
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment