This is a bit of advice for developers on Macs I’ve heard quite a few times, and I’ll echo it: go into System Preferences > General > Show scroll bars and set to always. This isn’t about you, it’s about the web. See, the problem is that without this setting on, you’ll never experience scrollbar-triggered layout shifts, but everyone else with this setting on will. Since you want to design around not causing this type of jank, you should use this setting yourself.
Here’s Stefan Judis demonstrating that usage of viewport units can be one of the causes:
There, 100vw
causes horizontal overflow, because the vertical scrollbar was already in play, taking up some of that space. Feels incredibly wrong to me somehow, but here we are.
Stefan points to Kilian Valkhof’s article about dealing with this. The classic fixes:
The easy fix is to use
width: 100%
instead. Percentages don’t include the width of the scrollbar, so will automatically fit.If you can’t do that, or you’re setting the width on another element, add
Kilian Valkhof, “How to find the cause of horizontal scrollbars”overflow-x: hidden
oroverflow: hidden
to the surrounding element to prevent the scrollbar.
Those are hacks, I’d say, since they are both things that aren’t exact matches for what you were wanting to do.
Fortunately, there is an incoming spec-based solution. Bramus has the scoop:
A side-effect when showing scrollbars on the web is that the layout of the content might change depending on the type of scrollbar. The
Bramus Van Damme, “Prevent unwanted Layout Shifts caused by Scrollbars with thescrollbar-gutter
CSS property —which will soon ship with Chromium — aims to give us developers more control over that.scrollbar-gutter
CSS property”
Sounds like the trick, and I wouldn’t be surprised if this becomes a very common line in reset stylesheets:
body {
scrollbar-gutter: stable both-edges;
}
That makes me wonder though… it’s the <body>
when dealing with this at the whole-page level, right? Not the <html>
? That’s been weird in the past with scrolling-related things.
Are we actually going to get it across all browsers? Who knows. Seems somewhat likely, but even if it gets close, and the behavior is specced, I’d go for it. Feels progressive-enhancement-friendly.
Been having some scrolling issues recently and was sad to see that the overscroll property has poor support. It sure would be nice to be able to choose whether to have that dinky bounce
I’m forever having to fix that with custom properties and JavaScript scrollbar-width detection. Having something in CSS that will just sort it out will be so nice
There’s so much going on in this space! Important cross-reference: https://www.w3.org/TR/css-values-4/#viewport-relative-lengths
While hiding overflow is clearly a hack, I would say 100% is not.
On the top level element 100% behaves similar to 100vw, except it does the thing you expect it to do, which is exclude the scrollbar. As you say, the 100vw behaviour “Feels incredibly wrong to me somehow, but here we are”.
The difference here is that, per specification, the viewport unit uses the initial containing block (which in its size includes the scrollbar) and the percentage unit uses the containing block, which is dynamic and subtracts the scrollbar when it appears.
I’m not sure if scrollbar-gutter is the best solution, as it has the (intended) side effect of always visually having space reserved for the scrollbar even when not needed. It’s kind of like overflow: scroll in that regard.
About which element is the scrollingElement, you can check
document.scrollingElement
. While it used to differ per brower, they have settled on using thehtml
element as the default scroll container.Lastly, just wanted to throw this out here, but the next major version of Polypane will detect the 100vw issue and throw up a warning/notice for devs:
1000% this! I’ve been using “always show scrollbars” ever since I moved to Mac (10 years ago). I never liked not having a visual indicator if content was scrollable. The fun thing about always having scrollbars show is you get to see how many developers never learned the difference between
overflow:auto
andoverflow:scroll
.I completely agree that web developers should test their websites using the default settings, since that is what their users will experience.
I think it’s worth mentioning that hiding the scrollbars by default is not good for usability. It removes affordances, in addition to the layout shifts mentioned in this article. It’s good to remember that just because macOS automatically hides scrollbars, that doesn’t mean we should copy that design in our design work.
Ah, the horizontal overflow horrors…
The roots of this bugs reach back to the IE6 position:absolute vs. position:fixed dilemma^^
Have tro wrap my head around this every now and then, but keeps me focused, too.
I did some experimenting (in Chrome, on a Mac) and found out that the confusion arises from our expectation of what contains the scrollbar.
Setting a fixed width (say
100px
) on adiv
-element and assigning itoverflow: auto
, causes a scrollbar to appear within thediv
‘s bounding box, as we expect. The available horizontal space for thediv
‘s contents is reduced by the width of the scrollbar (for the moment disregardingbox-sizing
and padding).However, setting the width of an element (like
body
, for instance) to100vw
causes a situation analogous to setting the width of one of the aforementioneddiv
‘s contained elements to100px
, in which a horizontal scrollbar would appear. Apparently, the scrollbar we see when we let the contents of thebody
flow normally is actually not contained by thebody
-element itself (nor thehtml
-element for that matter).By messing around a bit, I found out that you can get the visually outermost scrollbar inside the
body
‘s containing box by settingheight: 100%; overflow: auto;
on both thehtml
andbody
elements. However, this doesn’t ‘fix’ anything; an element contained within thebody
and assignedwidth: 100vw
would still cause a horizontal scrollbar to appear (though It might not if it hasposition: absolute
).