A CSS Parallax Scroll Effect For All Modern Browsers
This article will teach you how to create a parallax scroll effect with pure CSS that works in all modern desktop and mobile browsers, including the latest versions of Chrome, Firefox, Edge, Opera, Safari, Chrome for Android, and Chrome and Safari for Mac.
Safari for Mac and Chrome and Safari for iOS have a minor caveat that you can simply workaround using a few CSS tricks. We'll go over that in a bit.
For now, let's get started with a quick explanation of what this is and how it can be used within a website.
What is a Parallax Scroll Effect?
Parallax scrolling is a technique used to make background images appear as if they're moving slower than their surrounding foreground elements when scrolling through a web page.
In this case, the illusion is accomplished by defining a set of 3D perspective and layer transformation CSS rules that will be output in a 2D format on the screen.
The result will be a smooth scroll with the background image scrolling at half the speed of its surrounding content:
Setting up the HTML Code
The below code example represents the markup needed for the background image, page title, and surrounding content:
<div class="parallax">
<h1>This is a Parallax Scroll Example</h1>
</div>
<div class="content-outer">
<div class="content-inner">
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
<p>Paragraph 4</p>
<p>Paragraph 5</p>
</div>
</div>
The .parallax
container is the element where the background image will be stored using a pseudo-selector, and also where the page title will be displayed.
The .content-outer
and .content-inner
containers hold the page content that exists below the background image and page title.
The CSS Parallax Scroll Rules
Now, we'll step through each of the elements and their CSS rules and definitions.
Let's set up the html
and body
selectors.
First, we're removing all padding and margin spacing around the edge of our document. This is just to clean up the display:
html, body {
padding: 0px;
margin: 0px;
}
Second, the html
selector removes all horizontal and vertical scrolling from the page and is required for the effect to work correctly:
html {
overflow: hidden;
}
And, third, we're setting the body width and height to the size of the viewport and enabling vertical scrolling if the page contents exceed the viewport height (which they will in this example) while keeping the horizontal scroll disabled.
The perspective
rule is used to give the element a 3D-space by adjusting the distance between the user and the element on the Z-axis. This output does not affect the element itself, only its child elements and how they will be displayed.
And the transform-style
rule with preserve-3d as its value confirms that the child elements of the body
will maintain its 3D position:
body {
width: 100vw;
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
perspective: 1px;
-webkit-perspective: 1px;
transform-style: preserve-3d;
-webkit-transform-style: preserve-3d;
}
Now, let's get down to the fun part!
The .parallax
container is the element that will hold the background image displayed on the screen, as well as the page title.
Here, we're setting the element's size to 100% of the viewport width and height so that it covers the entire browser window.
Setting its position
to relative ensures that the background image positioning will be retained to its parent's boundaries.
And, again, we're setting transform-style
to preserve-3d to ensure that this container maintains its 3D positioning, as well:
div.parallax {
width: 100vw;
height: 100vh;
position: relative;
transform-style: preserve-3d;
-webkit-transform-style: preserve-3d;
}
Addingtransform-style
to the.parallax
element was required for this effect to work correctly in Firefox only. This is because Firefox doesn't know to maintain 3D transformation rules within additional child elements and must be instructed to do so. You could also set this value to inherit for the same outcome.
And, finally, we have the .parallax:after
pseudo-element definition that creates the rules for our background image and how it will be positioned in the .parallax
container:
div.parallax:after {
background-image: url("/bg.jpg");
background-repeat: no-repeat;
background-position: center;
background-size: cover;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
z-index: -1;
content: "";
transform: translateZ(-1px) scale(2);
-webkit-transform: translateZ(-1px) scale(2);
}
Here, we're setting the background image URL and its position within the .parallax
element. The positioning must be absolute and centered.
Setting the top
, left
, right
, and bottom
rules to 0px sets the bounding box for the element and instructs the browser to fill all available space with the contents of that element. In this case, it will be the background image that fills the container.
Next, we're setting a negative z-index
value for a few reasons: to ensure that there is no overflow of content from other elements within the page, and to slow down the scroll speed which we'll also accomplish with our next CSS rule.
Setting negative Z values with translateZ()
ensures that the scroll speed will be slower than with a positive value by zooming out from its original position on the Z-axis. We then provide depth correction with the scale()
rule, doubling the background image size so it appears rendered at its original size to the user.
The scale factor is calculated as((translateZ * -1) + 1) / perspective
. So, if our viewportperspective
is set to 1px and we translate an element -1px along the Z-axis like we have in this example so far, the correctionscale
factor would be 2.
The Safari and iOS Caveat
Everything should now be working smoothly, at least in most browsers. The caveat is with Safari and iOS browsers where the content below the .parallax
container overlaps the background image.
Generally, with the other browsers, you could set a CSS rule of overflow: hidden
to the .parallax
container to correct this issue. But, with Safari and iOS browsers, we need to take a different approach.
We can correct this by simply increasing the perspective
value of the content below the .parallax
element to 2px, 1 pixel larger than the .parallax
element itself:
div.content-outer {
width: 100%;
background-color: white;
perspective: 2px;
-webkit-perspective: 2px;
}
The content will appear scaled as normal to the user but tricks the browser into thinking the content below the .parallax
element is actually higher in the Z-axis, and therefore covers up the background image as needed.
Conclusion
The article explained how to create a simple parallax scroll effect with CSS in all modern browsers with a single set of rules.
You can download the complete source code from my GitHub repository. This codeset includes the assets from the examples above and will allow you to play around with different values as needed to further understand how each of the CSS rules works and interact with each other.
Created: December 06, 2020
Comments
Andreas
Reply
Josh Rowe
document.addEventListener("scroll", function(event) { ... });
Reply