How to create a parallax effect with CSS only

The parallax effect is one of the niftiest little tricks that you can use on your landing page to attract the attention of your visitors. CSS has matured a lot over the past few years, and this means that there’s a lot of flexibility as to how something should be done. Hacky tricks like background-position are quite difficult to maintain however. This article will demonstrate how you can use modern CSS to create a easy to maintain beautiful parallax effect.

The theory behind the parallax effect

Understanding the conditions required to create a parallax effect helps to implement it correctly. However, if you want to skip and get to writing some code instead, head on over to the next topic. The parallax effect is to make two (for the sake of explaining) layers on top of each other moving at a constant speed appear like the layer on top is moving relatively faster than the one beneath it.

You might have seen applications of the parallax effect as early as 2D games where the background appears to shift slower in comparison to the foreground. You might have observed the parallax effect while you’re in the car where objects further away seem to move slower than other cars in the road.

firewatch website scrolling down

So putting it simply, the conditions that have to be satisfied for a parallax effect to be created are:

  • Alter the way the parallax layer is perceived in such a way that it looks like it's moving relatively faster or slower, without deviating from its original size.
  • Do not alter the position or speed.

To achieve both these conditions, we have to increase the perceivable distance between the user and the layer, then shift it along the negative Z-axis. Because perceivable distance is increased, the layer may appear smaller. To counter this decrease in size we can scale it back to its original size. This means we will be making use of mainly two CSS properties: perspective and transform. We will be making use of translateZ() and scale() transformations.

Putting together some markup

First off, we need some HTML. Create a file named index.html and copy/paste the following code:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pure CSS Parallax Effect</title>
</head>
<body>
<main>
<section class="no-parallax">
<h1>Fun fact:</h1>
</section>
<section class="parallax bg">
<h1>
The sound that occurs when you snap your fingers is made by your
middle finger hitting your palm!
</h1>
</section>
<section class="no-parallax">
<h1>Have a nice day!</h1>
</section>
</main>
</body>
</html>

This will create 3 sections of which only the 2nd will have the parallax effect. It is easier to notice the difference when there are 2 static/non-parallax sections to compare against. Now, create a styles.css file and then link it to the html file by putting the following code in the <head> tag:

<link rel="stylesheet" href="styles.css" />

Implementing parallax using CSS

The markup doesn't look all that appealing right now, so before implementing the parallax effect, paste the following code in your previously created styles.css file:

body {
margin: 0;
}

main {
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
}

section {
position: relative;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: white;
}

.no-parallax {
background-color: #111;
}

section h1 {
text-align: center;
font-size: 4rem;
font-family: sans-serif;
}

.parallax h1 {
width: 60%;
font-size: 2rem;
}

The <main> and section elements will both take at least the same height of the viewport. The section element makes use of CSS3 Flexbox in order to center the elements inside it vertically and horizontally.

The next step is to increase the perceivable distance between the user and the main element, for which we will use the perspective property. The smaller the value the more subtle and natural the parallax effect will seem.

main {
/*...Collapsed...*/
overflow-y: auto;
perspective: 2px; /* <-- This line */
}

Now, we have to transform the parallax layer along the negative Z-axis, and then increase its scale to counter for the decrease in size because we previously altered the perspective. This is because when perspective is applied to a parent, the children of that parent will be affected. If the child has a Z value greater than 0, it will appear larger, and if it is smaller than 0, it will appear smaller. We will make use of the pseudo-selector ::after here to apply the necessary transformations to the background-image that we will add later.

.parallax::after {
content: ' ';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transform: translateZ(-1px) scale(1.5);
background-size: 100%;
z-index: -1;
}

Below we add the background-image, which is randomly picked from picsum.photos. In order to make sure that the text is relatively readable, we make use of a linear-gradient to add a darkened effect to the image.

.bg::after {
background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)),
url('https://picsum.photos/1080/720');
background-size: cover;
}

With that done, we should be able to notice the parallax effect when scrolling up and down. It will appear as if the font is fixed and the background image is moving beneath it slowly. If it doesn't look like it's working, take a look at the following codepen and cross-reference your code with the code in it:

See the Pen on CodePen.

The effect that we’ve implemented is fairly simple and appealing but if you need more control over how the effect should look like then you should try out the fullPage.js parallax extension! Whether you plan on creating a single page site with snap scroll or you just want a fancy parallax effect that works both vertically and horizontally, the extension’s got your back. It also comes with built-in support for CMS’ like WordPress via editors like Elementor and Gutenberg.

Conclusion

Effects like the parallax effect are a relatively simple method to boost the appeal and grab the user's attention. It is however important to remember that to make things look good, you should never sacrifice user experience, or in other words, you should use effects sparingly where you can maximize its potential.