Closed dbaron closed 7 years ago
(The Gecko bug in question is bug 1393603.)
It's literally the only way to get accurate viewport units in the presence of a root scroller. Use of vw is relatively rare in the first place, and most of the time people don't need precise values, but I suspect there's a subset of authors who are annoyed at 100vw not being the width of the layout area in some browsers.
I just asked our relevant implementor (@bokand) for our impl plans.
Here is an example showing off the functionality - in Firefox all 10 floats correctly sit on the same line, but in Chrome the 10th one wraps to the next line.
The problem is that this introduce styling state that depends on other styling state. In particular, changing the overflow on the scroll root would mean recomputing every viewport unit in the document (even the ones higher up in the tree!).
Gecko relied on reconstructing the whole layout tree when this happenned, which happened to restyle the whole document.
As can be seen in http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=5339, this is now broken since the optimizations in https://bugzilla.mozilla.org/show_bug.cgi?id=1344398 landed, and on the new style system, which decouples styling from layout tree building, it's similarly broken.
(even the ones higher up in the tree!).
This only applies to the root scroller, so at max this means you might be able to change it on body
and have it affect html
(is that right? I forget what all the complexity around root scrollers means). Blame ancient browsers for screwing up "which element styles the canvas/window?" so bad. ^_^
Aside from that one bit of body->html jumping, this is otherwise identical to recomputing em
units based on a font-size
change. Which, I know, requires some complexity to handle in a performant manner, but is a proven mechanism at least.
And again, coming at it from the author side rather than impl, not doing this means that it is impossible to write something that wants to be a % of the viewport when scrollbars appear. That sucks, it's the sort of "are you kidding me" moment that super-frustrates authors. It makes viewport units just a broken feature (since scrollbars are, after all, the rule on pages, rather than the exception).
This is a perfect use-case for the variables-that-don't-vary-except-they-do-sometimes proposal that Dean proposed at the Paris F2F.
By "perfect use-case" you mean "let the viewport units continue to be broken, and assume that authors will be able to write code that listens for viewport-size changes and updates a const-var every time it changes"? Can you even write the code for that? I'm not sure how to do it, at least.
The Working Group just discussed Should viewport units still depend on scrollbar width for overflow:scroll?
.
Summarizing the impl complexity:
overflow
is about as hard as the em
unit, which requires some work to make performant.body
is controlling the window scrollbar.::-webkit-scrollbar-*
pseudo-elements. If this is taken into account, the viewport units become inextricably layout-dependent, which defeats the original effort to make them computed-value-time absolute units.em
units, as it's not dynamically changeable per subtree. You check exactly one element's property value, and the whole tree responds accordingly. Still have to pipe the data around and figure out what needs refreshing, of course.--var
on html
equal to the viewport size minus your custom width. This is an intrinsic restriction of the feature, not an incidental one, and it's okay for it to not have 100% fidelity as a result. It's also quite rare.I don't think your (1) is quite correct, because testing whether your current calculation is correct is more complex than for em
units, and the effect is global rather than local. (The effect with em
units can be a wide effect when font-size
inherits, but everywhere it happens it's a local effect.)
I also tend to think adding viewport units themselves were a mistake -- something that we thought was simple, but really should have been addressed by layout systems rather than units, and now turn out to be not as simple as we thought.
I don't think your (1) is quite correct, because testing whether your current calculation is correct is more complex than for em units,
Only in abstract. In practice, you do the calculations already every layout, to figure out how wide your scrollbar should be. (And if you cache results and only update when necessary, well, that's the exact work you'd need to do for viewport units too.) Once you're already doing the "figure out how wide the scrollbar is" math, checking if you need to update is just a numeric comparison to the current value.
and the effect is global rather than local. (The effect with em units can be a wide effect when font-size inherits, but everywhere it happens it's a local effect.)
font-size almost always inherits; the fact that it's local in application is irrelevant when the entire page gets spammed with "local" updates.
I also tend to think adding viewport units themselves were a mistake -- something that we thought was simple, but really should have been addressed by layout systems rather than units, and now turn out to be not as simple as we thought.
That would have been a huge mistake; one of the big uses of viewport units is piping page-size information into unexpected places, like font-size so your text gets bigger/smaller according to the viewport size. That can't be done with layout systems.
That would have been a huge mistake; one of the big uses of viewport units is piping page-size information into unexpected places, like font-size so your text gets bigger/smaller according to the viewport size. That can't be done with layout systems.
(That said, those use-cases don't need precise values; they're not bothered if 100vw isn't precisely the viewport width, they just care that it approximately maps to the viewport width. And the layout use-cases are, generally, better solved by just using Flexbox/Grid. So, uh, it might be possible to convince me that making the viewport units lower-fidelity is acceptable.)
As can be seen in http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=5339, this is now broken since the optimizations in https://bugzilla.mozilla.org/show_bug.cgi?id=1344398 landed, and on the new style system, which decouples styling from layout tree building, it's similarly broken.
Just noticed I meant to point to http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=5340 (Same test case, just adding body:hover { overflow: hidden }
, to see the effect). This is broken since Firefox 55.
The Working Group just discussed Should viewport units still depend on scrollbar width for overflow:scroll?
, and agreed to the following resolutions:
RESOLVED: Drop the requirement to subtract scrollbar size from vh/vw units for overflow scroll
Edits checked in. https://github.com/w3c/csswg-drafts/commit/c1c2e82ca98a5a88f811e9d165757136d33f9dd4 @dbaron, would you mind verifying?
I have a use case for this currently, and it is very frustrating that vw still does not take the scrollbar into account even when setting html { overflow-y: scroll; }
@coreyworrell -> https://github.com/w3c/csswg-drafts/issues/1958
Hoping scrollbar width/height will solve this issue for us in [css-scrollbars].
Or, if not given the ability to size scrollbars, maybe petition for the ability to access their size with an env() variable??? [css-env-1] list of predefined variables
Then we'll at least be able to derive what would be the scrolling elements "clientWidth" with calc()...
Rossen_: Options are vw always resolved to full viewport ignoring scrollbars. For most scenarios you know how big the iewport is and if you care about scrollbars you can do calc and subtract.
@jonjohnjohnson
I don't think being able to set the width of the scrollbar is related to the issue I'm talking about. Unless I'm not understanding what you're saying. You should be able to have a design depend on the available width and have default scrollbars.
The env()
variable for scrollbar width would be a suitable fix though, even if very annoying.
I'm just not sure why vw
would by default return a value that includes the area taken up by a scrollbar, as web developers avoid causing horizontal scroll at all costs in practice. And if there were a reason to use it, that should be the 'opt-in', not the other way around. But even then, as of now there is no opt-in or opt-out, it just is always included, which is frustrating to say the least.
@coreyworrell the discussion above highlights the factors/limitations for the issue and reasoning behind the current decision.
As far as setting a scrollbars width...
:root {
--valueThatAlsoSetsScrollbarWidth: 20px;
--vw: calc(100vw - var(--valueThatAlsoSetsScrollbarWidth));
scrollbar-width: var(--valueThatAlsoSetsScrollbarWidth);
}
.width-100vw {
width: var(--vw);
}
.width-50vw {
width: calc(var(--vw) * .5) ;
}
Update In https://github.com/w3c/csswg-drafts/issues/1958#issuecomment-409682589 it was agreed to have scrollbar-width
property not accept lengths, so hopefully we can still get the size the browser uses as an env()
? https://github.com/w3c/csswg-drafts/issues/2630#issuecomment-387909043
:root {
--vw-inside-scrollbar: calc(100vw - env(scrollbar-width));
}
It sounds like you're saying that I would need to explicitly set the width of the scrollbars for the site to be able to use vw
in a useable way? How would this make sense when operating systems and browsers all have different default scrollbar widths, I would always prefer to let the OS handle that how they see fit rather than force a set width. Let the OS/UI/browser do its thing and just tell me how much space I have for actual layout without causing horizontal scroll.
Oh well though, at this point the benefit of using vw
is that it is even supported in IE9, but if there were to be some new method/unit/way of handling this I'm not so sure the older browsers would get those patches, which would require authors to use a different method regardless.
@coreyworrell Just trying to offer workarounds for your issue, when the decision that was already made on this topic doesn't give you what you need.
Also, I've resorted to hijacking the rem unit for older browsers creating a "viewport unit" based off clientWidth, which you could also create with a calc() leaving the rem alone for modern browsers. Nevertheless, spec things will always/only impact upcoming versions of browsers. Good luck.
@jonjohnjohnson Understood. I appreciate the help and insight. Overall I'm just expressing my frustration with the spec (or the fact the browsers actually haven't stuck to the spec, ie: overflow-y: scroll
supposedly disabling this behavior).
@coreyworrell In this thread it shows that a decision was made to remove that part of the spec and why.
When the height or width of the initial containing block is changed, they are scaled accordingly. However, any scrollbars are assumed not to exist. https://github.com/w3c/csswg-drafts/commit/c1c2e82ca98a5a88f811e9d165757136d33f9dd4
Making it so browser implementations are actually compliant.
@jonjohnjohnson Doesn't make it okay or the correct decision that they decided to remove it though.
Why would we need this which can be found viewport-relative-lengths:
However, any scrollbars are assumed not to exist.
This will make 100vw
include the width
of scrollbar. I think we don't need this.
So,when we set width:100%
or width:100vw
on html
, they both mean that the width
of html
should be 100% of the width
of initial containing block
according to the specs. However, width:100vw
will get different behavior because of the word above.
If the viewport-relative units are to be defined as independent of whether there are scrollbars, it's much more useful to always subtract a default scrollbar width (or rather even double, accounting for possible scrollbar-gutter). This way there isn't overflow when a single dimension in the layout or a sum thereof reaches 100 of the relevant units. And if there are no scrollbars, some stuff may be smaller, but that's not as big a deal (although authors may want to stretch or repeat backgrounds to cover the extra space).
It makes the most important use case easier when (actually if) the relevant environment variable arrives by not requiring its use along with inelegant calc expressions and possible at all for the near future.
@tabatkins Not to beat a dead horse, but I do think this is important to get right. I just don't understand why viewport units aren't handled exactly the same as percentage units, as if the element is a direct child of the body
for example.
<html style="overflow-y: scroll; /* avoid page shift when scrollbar appears */">
<body style="margin: 0; padding: 0;">
<div style="width: 100%;">This is 100% wide, looks good, yay!</div>
<div style="width: 100vw;">WTF, horizontal scrolling now?</div>
</body>
</html>
That example alone makes no sense to me. The purpose of viewport units was to be able to reference a percentage of the width of the "initial containing block", instead of only being tied to using a percentage of its parent element.
Why would one want to "draw" an element "under" the scrollbar and force a horizontal scrollbar? If you absolutely needed that for whatever reason, that should be the exception, and handling it would simply involve hiding the overflow however you see fit (overflow-x: hidden
or overflow-y-hidden
).
I have read through the IRC discussions and do not see any solid reason this was dropped.
If viewport units act like %s, then they change from being "resolveable at computed-value time" to "resolveable at used-value time". This is a huge change! It means that a lot of uses you might want simply don't work; any place that currently has "% acts like auto
" behavior would give viewport units the same behavior.
We thought it was more useful to have viewport units always be usable.
@tabatkins Sorry, I don't think I follow. Maybe my use of exactly was too broad. I just meant in the aspect of the size that the unit represents.
A viewport unit should always be usable like you said, of course. The definition of "viewport" is the issue though. To website developers, it should mean 1% of the available space I'm given. If a browser draws a scrollbar in that space, it is no longer available, thus the value of 1vw
should adjust accordingly.
Could we reopen this issue? The current viewport units are obviously useless as https://github.com/w3c/csswg-drafts/issues/1766#issuecomment-460470368 and the number of developers complaining show.
The previous resolution in this issue has been reversed in #6026. overflow: scroll
on the root element (or similar things, such as scrollbar-gutter: always
) will now reduce the size of the viewport units.
There's a few wrinkles - setting overflow:scroll
on the body
element will also trigger root scrollbars, but won't change viewport units, because of cyclic issues. And if you manually adjust the size of scrollbars with the WebKit/Blink scrollbar pseudo-elements, that won't be taken into account, again for cyclic reasons. But scrollbar-width
on the root element will be taken into account, so thin
scrollbars will work correctly.
Right now the definition of viewport units says that they shrink for scrollbar sizes when
overflow
on the root isscroll
(which is quite rare, since it's not the default), but not in other cases.Apparently Gecko is the only engine that implements this, and we're wondering whether it's worth the work to maintain that implementation when it seems like nobody else is going to.
Are other engines planning to do this?