Closed simevidas closed 8 months ago
See https://github.com/w3c/csswg-drafts/issues/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 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?
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.
Also related: https://github.com/w3c/csswg-drafts/issues/5232
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?
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.
@emilio Okay so why not create a new unit (or modify vw
) that resolves at layout like percentage?
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.
Also related: https://github.com/w3c/csswg-drafts/issues/4329
@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.
Also related: https://github.com/w3c/csswg-drafts/issues/4691
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:always
set on the root.
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.
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
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
yep! exactly!
I'm thinking we should go back to making them work with
overflow: scroll
and also withscrollbar-gutter:stable
andscrollbar-gutter:always
set 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 https://github.com/w3c/csswg-drafts/issues/4329#issuecomment-863677668
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:
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.
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?
@brunoais Yes, that's a different (and possibly clearer) way of saying the same thing.
Whatever we're able to do here should likely also apply to container (cq*
) units. I like @mor10's summary of expected behavior here. It would also potentially be useful to have the ability to do something like calc(100vw - scrollgutter)
.
Whatever we're able to do here should likely also apply to container (
cq*
) units. I like @mor10's summary of expected behavior here. It would also potentially be useful to have the ability to do something likecalc(100vw - scrollgutter)
.
100dvw
😉 ?
Whatever we're able to do here should likely also apply to container (
cq*
) units. I like @mor10's summary of expected behavior here. It would also potentially be useful to have the ability to do something likecalc(100vw - scrollgutter)
.
100dvw
😉 ?
It is still behaving the same. on Chrome (108) and Safari, 100vw is still the same as 100dvw when scrollbars exist.
Whatever we're able to do here should likely also apply to container (
cq*
) units. I like @mor10's summary of expected behavior here. It would also potentially be useful to have the ability to do something likecalc(100vw - scrollgutter)
.
100dvw
😉 ?It is still behaving the same. on Chrome (108) and Safari, 100vw is still the same as 100dvw when scrollbars exist.
Then it's a browser bug. Complain to its maker
It is still behaving the same. on Chrome (108) and Safari, 100vw is still the same as 100dvw when scrollbars exist.
Then it's a browser bug. Complain to its maker
It’s not a browser bug. All browsers are doing what the spec says here (“any scrollbars are assumed not to exist”), hence this issue.
To be clear, the spec says this because the browser vendors asked for it to match their implementations. It didn't originally say this.
I specifically specified to consider the scrollbars in my proposal so this wouldn't happen!
So just to make sure I've understood this correctly...
I can't speak for @brunoais, but I know that if I was in their position I'd be bloody furious about this process. To this outsider it's really not a good look for the treatment of external contributions.
I come across sites and apps with unintended horizontal scrollbars like this almost daily. (Edit: I even saw it on just the second link I opened after originally posting this comment.) The most frustrating thing for me is that some browser vendors have previously said taking the scrollbars into account is close to impossible. Except Firefox has previously implemented that behaviour, so it's clearly possible to some extent. And as noted above, the original proposal outlined what to do to avoid infinite cycles.
Thank you. That was very well picked up and explained. Thankfully, due to how I am, I'm not furious. However, I'm seriously disappointed. Feels like right to repair in USA's NY state.
Edit:
tells the original author of the proposal that the author doesn't know how the units are meant to work
BTW, that's not how I interpreted it. I interpreted it as "The spec states this ``, so there's no browser bug"
(Now bramus answered... It's what he wrote. So I assume I interpreted it correctly)
4. A representative from a browser vendor effectively tells the original author of the proposal that the author doesn't know how the units are meant to work: [css-values] Use of 100vw is causing pointless horizontal scrollbars on some websites #6026 (comment)
FWIW, I was trying to point out that – at this moment – it is not considered a browser bug, as the browsers follow what the spec says. You could say it’s a spec issue, though. Apologies if this came across differently.
You could say it’s a spec issue, though. Apologies if this came across differently.
Fair enough, seems like it was my misinterpretation, apologies in return. I think it was the "hence this issue" that twisted my interpretation of the comment, as it seemed (to me) to be a circular argument regarding dv*
units. I've edited my comment accordingly.
Has anyone ever suggested a dynamic environment variable that would return the current viewport size reduction caused by a classic scrollbar on the page? Would that be possible? Would that make sense?
.full-width {
width: calc(100vw - env(viewport-reduction-inline));
}
So if the page does not have a vertical classic scrollbar, env(viewport-reduction-inline)
returns 0px
, and the element is 100vw
wide, but if the page does have such a scrollbar, the environment variable returns how much inline space this scrollbar consumes in the inline direction (usually 15 to 17 pixels), and the page can subtract that length from 100vw
to get the actual viewport width and then set the element to that width.
This does not seem like a good solution to me, but I wanted to put it out there, since I haven’t seen this suggested yet.
Has anyone ever suggested a dynamic environment variable that would return the current viewport size reduction caused by a classic scrollbar on the page? Would that be possible? Would that make sense?
In https://github.com/web-platform-tests/interop-2022-viewport/issues/15#issuecomment-1268596477 this was discussed, and @emilio noted that you can’t have a dynamic value because it depends on layout and can cause layout cycles: “Only reasonable thing to expose is the default size” … which brings us back to env(scrollbar-inline-size)
.
I think exposing scrollbar-inline-size
plus a media query for overlay scrollbars is the most straight-forward solution. Those are things you can trivially determine via script anyways.
Those are things you can trivially determine via script anyways.
The idea is to solve layout problems with CSS, not with js. Js is for interactivity. Layout with Js is and will always be a hack
In our product we're currently essentially calculating the scrollbar-inline-size
via JS, creating an invisible block with an overflow, and retrieving its width if it has one, then storing it as a custom property on root, to be used in calculations.
Being able to use a keyword for this, alongside a query to detect if scrollbars are present on a container would be very helpful.
Why I'm mentioning “keyword” and “container” rather than an “environment variable” and “media query”: we have scrollbar-width
which can control if we have the scrollbar, and we can have a container that can be scrolled programmatically when it has overflow: hidden
. That means that authors could want to a) detect if a certain scrollport has a visible scrollbar, and b) get the width of a scrollbar in that case, which can be different for different containers (scrollbar-width
and also current webkit scrollbar pseudo-elements).
@emilio I don’t think scrollbar-inline-size
is a solution to the 100vw
problem that’s being discussed in this issue. See my comment in https://github.com/w3c/csswg-drafts/issues/4691#issuecomment-1715038961 for why I think that is.
If CSS won’t answer the question “Is a vertical classic scrollbar currently present on the page?”, then I think the best way to deal with the 100vw
problem would be to reduce the size of 100vw
when scrollbar-gutter: stable
or overflow-y: scroll
is set on <html>
, as proposed in https://github.com/w3c/csswg-drafts/issues/5254. With that change, width: 100vw
would no longer cause horizontal overflow on pages with stable gutters. That seems to be the best we can do.
As @kizu’s pointed out in https://github.com/w3c/csswg-drafts/issues/4691#issuecomment-1715388016, container query units can help with this problem. After turning <body>
* into a query container, 100cqw
can be used as a substitute for 100vw
to get the desired behavior. Unlike 100vw
, 100cqw
becomes smaller when a classic scrollbar appears on the page.
(*I use <body>
because it didn’t work on <html>
in Safari. I filed a WebKit issue.)
For example:
body {
margin: 0;
container-type: inline-size;
}
.full-width {
position: relative;
left: calc(50% - 50cqw);
width: 100cqw;
}
Demo 1: https://codepen.io/simevidas/pen/LYMrPZo?editors=0100
As far as I can see, 100cqw
behaves the way developers wanted 100vw
to behave with regards to classic scrollbars. In that case, I guess this issue can be closed. Developers can use 100cqw
instead of 100vw
for the “full-width” use-case, and in other situations where they need the actual viewport width in CSS.
One limitation of 100cqw
is that it represents the width of the closest ancestor query container, which may not necessarily be <body>
if the page contains other, nested query containers. In that case, developers can store the “page width” value in a registered custom property, and then use that property instead of 100cqw
.
@property --page-width {
syntax: "<length>";
initial-value: 0px;
inherits: true;
}
body {
margin: 0;
container-type: inline-size;
}
article {
/* store <body> width in registered custom property */
--page-width: 100cqw;
/* <article> is nested query container for demo purposes */
container-type: inline-size;
}
.full-width {
position: relative;
left: calc(50% - var(--page-width) / 2);
width: var(--page-width);
}
Demo 2: https://codepen.io/simevidas/pen/KKbJgBR?editors=0100
Why can a custom property registered with @property save "page width"? When I tried with "100%", it did not work.
<style>
@property --page-width {
syntax: '<length-percentage>';
inherits: true;
initial-value: 0%;
}
body {
--page-width:100%;
}
.child {
width: var(--page-width); /*Width of parent element(1000px), not page width*/
}
</style>
<div class="parent" style="max-width:1000px;">
<p class="child">Hello</p>
</div>
Demo: https://codepen.io/mikiprogram/pen/QWzzvMR
Is there a statement on this in the following W3C page? URL: https://www.w3.org/TR/css-properties-values-api-1/ I would be glad to know!
@yuito-git Sorry, there was a mistake in my code. The --page-width: 100cqw
declaration needs to be in a child of <body>
. It doesn’t work if the declaration is in <body>
itself. I’ve corrected my code and provided a second demo that shows that this solution works in browsers (Chrome and Safari, for now).
@simevidas Thank you very much! I found that the fix works for "100cqw". However, if I change the value of the CSS variable "page-width" from "100cqw" to "100%", I get the width of the parent element, not the page width. Do you know anything about this behavior?
@yuito-git In my demo 2, if you just replace --page-width: 100cqw;
with --page-width: 100%;
, the value of --page-width
will be 0px
because that custom property is registered as a <length>
, so trying to assign a percentage results in the declaration being ignored by the browser. You can change the custom property’s type to <length-percentage>
.
@simevidas In my demo, I have specified <length-percentage>
for syntax,
but it is not the page width. Why is this?
Is the unit "cqw" special?
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: if overflow:scroll is set on the root element (not propagated from body), account for the default scrollbar width in the size of vw. Also take scrollbar-gutter (and scrollbar-width, the property with "normal" and "thin"?) into account on the root. Ignore all of these in MQs. and also ignore all of these when using vw/vh units on the root element, if necessary
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))
was this discussed?
Why not move that resolution to 100 dvw
& 100 dvh
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 for100vw
are full-width elements: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?