I'm a big fan of Keith Clark's pure CSS parallax technique and have been using it with some success on one of my own sites. Recently, however, I noticed that the background parallax elements, even in his own demo, do not abut the left side of the screen, but leave a gap, the size of which depends on how far back in the 3D space they are rendered.
The culprit, as far as I can tell, is the scrollbar. This scrollbar is supposed to be there (inside the parent parallax div), but it creates a difference between the size of the parent container (in which the 3d space is rendered) and the size of the containers' parallax children, which leaves room for that gap. I see it in the latest versions of Chrome, Firefox, and Safari (though I could have sworn I didn't see it there even a year ago).
This can be sort of fixed by applying a width: 100vw
rule to each parallax group or layer. But while this clears the gap, it places the elements out of alignment with the default center of the view (and so with any elements that do not also have the 100vw
rule applied to them). I would also like a solution that holds to the 'pure CSS' principle as much as possible.
HTML taken from the Keith Clark example:
<div class="parallax">
<div class="parallax__group">
<div class="parallax__layer parallax__layer--base">
<div>Base Layer</div>
</div>
<div class="parallax__layer parallax__layer--back">
<div>Background Layer</div>
</div>
</div>
</div>
CSS:
.parallax { // parent, page-level container
height: 500px;
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
-webkit-perspective: 300px;
perspective: 300px;
-webkit-perspective-origin-x: 100%;
perspective-origin-x: 100%;
}
.parallax__group {
position: relative;
height: 500px;
height: 100vh;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.parallax__layer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
-webkit-transform-origin-x: 100%;
transform-origin-x: 100%;
}
.parallax__layer--base {
-webkit-transform: translateZ(0);
transform: translateZ(0);
z-index: 4;
}
.parallax__layer--back {
-webkit-transform: translateZ(-300px) scale(2);
transform: translateZ(-300px) scale(2);
z-index: 3;
}
I came up with some solutions and put them into an example website here: https://dawaltconley.github.io/parallax-gap-fix/.
The problem only seems to arise with certain Mac system scrollbars, which appear when a user plugs in a USB mouse (how I found them) or changes
Show scroll bars
toAlways
in their settings. This scrollbar, unlike the transparent trackpad one, changes the inner width of the parallax page element, but not the total size, in which the 3D space for parallax elements is rendered.Changing the
perspective-origin
andtransform-origin
properties toleft
realigns the parallax elements without resizing anything. This would be the ideal solution, except that Safari seems to calculate the 3D space differently than most modern browsers, and needs those properties set tocenter
to align everything correctly.The best solution I found for all browsers is to add the following rules to the
.parallax__group
element:The difference between
100vw
and100%
, from any immediate child of the.parallax
element, is the width of the scrollbar. Setting a negative right margin to that width expands the parallax elements to the same width as the page, removing the gap at the edge of the screen. Setting this to the left margin stretches the elements a bit more than necessary, but is needed to align the center of the 3D space with that of the rest of the page.It should be possible to offset this bloat by applying similar rules to the
.parallax__layout
class, but Safari's inconsistencies make this difficult, as a non-bloated element would need to be aligned perfectly to avoid gaps in the layout.Incidentally, this solution has the advantage that it does nothing when the problematic scrollbars are absent. In that case, there is no difference between
100vw
and100%
, so the computed style is identical to Kieth Clark's.