The Problem
When content overflows the page and the scrollbar shows up, the content is pushed/shifted to the left and vice versa, when the scrollbar disappears, the content is pushed/shifted to the right:
This annoying layout shift can be prevented in multiple ways. In this article, I will go over them one by one:
1. Always showing the scrollbars
This is the easiest and ugliest solution.
body {
overflow-y: scroll;
}
2. The scrollbar-gutter
property
The scrollbar-gutter
property has been made for this exact purpose. setting it to stable
will preserve the space for the scrollbar and prevent the layout shift.
html {
scrollbar-gutter: stable;
}
BUT... it doesn't work in Safari and the scrollbar track will always be visible on your page which is not desirable.
*. A little note about 100vw
and 100%
Before continuing to the next points, it is necessary to understand the difference between 100vw
and 100%
:
- 100vw : Full width including the scrollbar.
- 100% : Full width excluding the scrollbar.
3. Shifting the content to the right
When the scrollbar is not showing, 100vw
and 100%
are equal, and when the scrollbar is showing, the difference between them is equal to the width of the scrollbar.
So if we shift the content to the right by the difference of 100vw
and 100%
, we can prevent the layout shift. To achieve it we can use padding-left
on the parent/container element:
.container {
padding-left: calc(100vw - 100%);
}
4. Positioning inside a 100vw
width parent
Since scrollbars don't affect the vw
unit, we can fix the problem by setting the width of the parent/container in the vw
unit and centering/positioning our elements inside of it:
.container {
width: 100vw;
/* elements inside won't be affected by scrollbars */
display: flex;
align-items: center;
justify-content: center;
}
The result after applying the 4th method:
Top comments (7)
In a few cases,
display: flex;
can destroy the entire layout.padding-left
can be ineffective if the white space on the left side is too large.I tried this rule:
The result was as desired. A stable layout with or without scrollbar.
Thank you so much, I've tried it and this is truly magic.
Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍
Thanks for featuring my article :)
Great share! Thanks for this, I was missing using
100vw
instead of 100%.Keep in mind things like
padding-left: calc(100vw - 100%);
are not a good solution because a browser can display the toolbar on the left side instead of right due to preferences or for users that use languages that go right to left etc.After a lot of tinkering with this I'm not sure if its worth implementing at all. My CSS and HTML structure plus logic was getting quite complicated for something this trivial. My use case was I have a nav header and footer that should be styled all the way to the edge of the screen but I wanted to prevent layout shift as users navigated around the website.
However, styling to the edge and using
scrollbar-gutter
seems to be quite the challenge. I kept running into the issue that the preserved scrollbar space would be styled differently, then I used100vw
to try and address this but then it introduced a new horizontal scrollbar I would have to hide withoverflow-x
hidden. Then this would cause issues as the window was resized (made smaller) in responsive theme where the scrollbar would overlap with the edge of the text before continuing to resize. Lots of headaches!From what I can tell almost all major / huge websites don't bother implementing this and just allow the minor layout shift due to resizing window or navigating to another page. Some sites (like dev.to) opt to always show the scrollbar. This is for the main page / body scrollbar of course, I'd try to avoid layout shift when interacting with the same page of course.
100vw vs 100% is a problem when your scrollbar applies only to part of screen, for example you have a static menu and only the content scrolls. 100vw means the whole width including the menu, 100% means content view, excluding menu.
It seems impossible to prevent content shifting and horizontal scrollbar appearing at the same time.