Rob O'Leary Rob is a solution architect, fullstack developer, technical writer, and educator. He is an active participant in non-profit organizations supporting the underprivileged and promoting equality. He is travel-obsessed (one bug he cannot fix). You can find him at roboleary.net.

Create parallax scrolling with CSS

13 min read 3698

CSS Logo Over Swirly Background

Parallax scrolling can improve the browsing experience of a website by making it more dynamic and immersive. In the simplest of terms, parallax scrolling is a three-dimensional effect for adding more depth to a webpage. There is some nuance to this that we’ll clarify later.

In this article, we’ll discuss reasons to consider using parallax scrolling. We’ll demonstrate how to implement the parallax scrolling effect with CSS, and we’ll share some benefits of using CSS to create a parallax effect instead of JavaScript. Throughout this tutorial, we’ll share several CSS parallax effect examples and use cases.

A famous, well-executed example of parallax scrolling is the Firewatch computer game website. The hero section contains a rural scene of a hiker peering across a valley to a hill station. The parallax effect makes the scene fall away to reveal the content below as the user scrolls down:

Parallax Scrolling Example From Firewatch Website
Parallax scrolling effect example from the Firewatch; Firewatch is a trademark of Campo Santo.

Looks like magic, right?🪄🎩

Let’s go backstage and see how the magic happens! 🧐⚙️

Jump ahead:

What is parallax scrolling?

Parallax scrolling is a computer graphics technique in which background images move past the camera more slowly than foreground images, creating an illusion of depth in a 2D scene. The technique grew out of the multiplane camera technique used in traditional animation in the 1930s:

Example of 2.5D scrolling that simulates the appearance of a 3D scene. Produced by Wikipedia user Janke. Public domain, via Wikipedia.

The above example is often referred to as 2.5D (two-and-a-half dimensional) or pseudo-3D perspective because it simulates the appearance of a three-dimensional scene.

Parallax scrolling was popularized in 2D computer graphics and was included in video games starting in the early 1980s. Many people credit the arcade game Moon Patrol as being the first use of the effect in side-scrolling games. Parallax scrolling made it into many popular platform games throughout the 80s and 90s, such as Sonic the Hedgehog.

The game The Whispered World implemented the parallax effect through the compositing of layers. Below is an isometric view of the game’s layers, with each distinguished by a colored frame:

Side View of The Whispered World
A side view of the layers used for parallax scrolling in The Whispered World. Claas Paletta, PR & New Business Manager of Daedalic Entertainment GmbH (rights owner). Free use, via Wikimedia Commons.

When viewed from the front, the layers form a complete scene:

Front View of The Whispered World
A front view of the layers used for parallax scrolling in The Whispered World. Claas Paletta, PR & New Business Manager of Daedalic Entertainment GmbH (rights owner). Free use, via Wikimedia Commons.

This technique was incorporated into web design but did not become popular until the 2011 introduction of HTML5 and CSS 3. As CSS has matured, it has become easier to pull off the effect without JavaScript and hacks.

One unfortunate outcome is that many treat the parallax effect as a blanket term; it has become synonymous with “gratuitous scrolling effects”. But in fact, the parallax effect does not require any animation or scroll-triggered events. It is purely based on elements moving at different speeds to give a perception of depth.

In web design, this is achieved by grouping elements into “layers”, and controlling how fast each layer moves. The elements are laid out vertically in a typical webpage, and the movement is a result of the user scrolling through the page.

Why use a parallax scrolling effect?

It’s important to consider why you’d want to use the parallax scrolling effect before you drop it into a website! Here are a couple of reasons.

Improved user engagement

Parallax graphics can grab a user’s attention and improve engagement. This can reduce the percentage of users who either hit the back button or close the tab after checking out just one page of your website. An improved (or reduced) bounce rate can be beneficial if the success of your site depends on users viewing more than one page!

Serves as a storytelling aid

Good design speaks to the user. Parallax graphics can help take users on an immersive journey. You can use parallax scrolling to produce a one-page website where visitors can read an entire story about your product or brand without navigating to multiple pages. Check out Matterday made by Netlify for a great example; this site tells a compelling story about how Netlify can save time and offers suggestions for how that extra time could be used!

How to implement the parallax effect in CSS

Broadly speaking, there are two methods for implementing a parallax effect with CSS. Let’s explore and compare both methods.

Method 1: Fixing the position of the background

Fixing the position of the background was the earliest method for creating a parallax effect with CSS. You can think of it as a 2.5D parallax implementation.



The secret to this method is to use a background image for a section and fix its position, typically with background-attachment:fixed. When the user scrolls through a particular section, the background does not scroll by, but the other elements do. However, once the user scrolls beyond that section, there is a different background. By having elements moving at different speeds, we create a parallax effect!

One thing to keep in mind with this method is that mobile browser support for background-attachment:fixed still appears to be problematic! We’ll discuss workarounds for this later in this article.

Let’s explore a specific example to get a better understanding of how this method works. Here’s a full-page example showcasing the activities available at Cerro Torre mountain in Argentina:

Laying out the design

When it comes to parallax examples, many developers seem to favor those with mountain scenes. I think this is because it looks kind of cool when you see something rise above a mountain, but don’t let this limit your application of the technique!

Below is an overview of the webpage’s design. We create a kind of banded design in which we interleave a parallax section with a non-parallax section (I call this a “buffer” section):

Webpage Design with Sections For Creating Parallax Scrolling

The “buffer” section is not required for the parallax effect to work, however, it can serve as a margin between parallax sections. Also, it can provide more control of the starting point of the background of the following parallax section.

For example, on a 1920px screen, if we scroll down most of the first parallax section, we see the middle of the mountainous background in the second parallax section:

First Parallax Section, Depicting A Mountainous Background

Without the first “buffer” section, below is what we’ll see at the same position on the page. You’ll notice that the initial view of the mountainous background of the second parallax section is higher:

Mountainous Background in Second Parallax Section

Ultimately, the “buffer” section is a design decision; it’s not an implementation requirement.

Here’s the CodePen for the above example:

See the Pen
Fixed background parallax scroll
by rob2 (@robatronbobby)
on CodePen.

The key to creating the parallax container is to set the background-image property with an image of your choosing and then set the background-attachment property to fixed. The fixed value fixes the position of the background image relative to the viewport.

Scaling the design

It is optional, but generally desirable, to use background-size: cover; to scale the image to the smallest possible size to fill the container while preserving its aspect ratio. In the below code, I also center the position of the background image using background-position: center:

.parallax-container {
  /*  this is where the magic happens:  */
  background-image: url("https://images.unsplash.com/photo-1519120944692-1a8d8cfc107f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=872&q=80");
  background-attachment: fixed;
  background-position: center;
  background-size: cover;

  /* dimensions are important, ensure it is tall enough to scroll */ 
  min-height: 100vh;

  /* you are free to lay out the container items with flexbox or whatever means you wish */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

Also, you must be mindful of the parallax container dimensions. The container should be tall enough to require significant scrolling! A simple way to guarantee this is to set min-height: 100vh on the parallax container, so that it will be at least as tall as the height of the screen, regardless of the elements it contains.

Handling mobile browser compatibility issues

It’s a shame that there are still lingering issues with background-attachment: fixed on mobile browsers. If you want to better understand these issues, read this documentation.

Fortunately, we have some options to overcome any mobile browser incompatibility.

For example, we can take the nuclear approach and ditch parallax completely on mobile devices (smaller screens) using a media query. The CSS would be something like this:

 /* Turn off parallax scrolling for all tablets and phones. Increase/decrease the pixels if needed */
@media only screen and (max-device-width: 1366px) {
  .parallax-container {
    background-attachment: scroll;
  }
} 

Murtuzaali Surti wrote about a fixed background hack and showed how bugs manifest in mobile browsers when background-attachment: fixed is used. In a nutshell, Murtuzaali suggests creating an element with a background image using position: fixed, placing the content into a separate element, and then positioning it absolutely on top of (stacked above) the background element.

Similarly, we could use a pseudo-element for the fixed background image, and it should work the same. I haven’t tried this myself, so I cannot personally vouch for this method!

Pros and cons of fixing the position of the background

There are both advantages and drawbacks to implementing parallax scrolling by fixing the position of the background.

Pros:

  • Relatively easy to understand
  • Straightforward to implement

Cons:

  • Mobile browser support is still problematic, but workarounds are available
  • Only capable of having two layers
  • Cannot control the speed of layers

Method 2: Using 3D translations

In CSS, we can position elements in three dimensions. We can position elements along the z-axis to increase or decrease the perceivable distance between the user and the element:

X, Y, Z Axis to position CSS Elements in 3D

Since 3D translations mimic reality, there are similar physical effects to when we move things in our digital world. Something that is further away (i.e., negative translation on the z-axis), will move slower. Conversely, something that is closer (i.e., positive translation on the z-axis) will move faster. We can kind of hijack the z-axis to control the scroll speed of things!


More great articles from LogRocket:


Another physical effect is scale. If we move something further away, it will appear smaller. If it is closer, it will appear bigger. If you want to counter this adjustment, you’ll need to scale it up or down yourself.

To achieve the parallax effect, we’ll make use of three CSS properties: position, perspective, and transform to lay out and group our elements into layers. Then we’ll use the translateZ() and scale() transformation functions to control the scrolling speed and sizes of layers relative to the perspective set on the parent element.

Before we go further, keep in mind that this is a tricky topic because it goes against the grain of what is typical. So, let’s make a small checklist of topics you should be comfortable with to truly grasp this method:

  • CSS transformations: The transform properties are core to CSS; the 3D aspect is particularly important to understand
  • z-index: Stacking elements through the position and transform properties can lead to situations in which layers are not stacked as you might expect. This is usually because transform creates a new stacking context. You may need to intervene and manage the z-index of the layers depending on your design. I can recommend Ahmad Shadeed’s article on the topic if you want to level up your understanding
  • Overflow: When working in 3D with overlapping elements, you must be mindful of overflow. If you do not understand overflow well, here’s a resource you may find helpful

Keith Clark wrote the seminal tutorial on the 3D translation method in 2014. This tutorial is a great exposition of the method, although it is a bit light on realistic examples that could make the method easier to grasp.

Rather than repeating the same information here, I will walk through a parallax scrolling example, and share some of the finer points not covered in that article. I recommend you read Keith’s article; you can disregard any discussion about browser bugs as those are no longer an issue.

Parallax scrolling demo

Let’s create a basic parallax scrolling example with three layers that have some text as well as different background colors.

Here’s the HTML:

<div class="parallax">
  <!--layer 1 will be the bottom layer, layer 3 will be the top layer-->
  <div class="parallax-layer layer1">LAYER 1</div>
  <div class="parallax-layer layer2">LAYER 2</div>
  <div class="parallax-layer layer3">LAYER 3</div>
</div>

Here’s the base CSS that we can reuse:

/* if you do not remove the margin, you will see a vertical scrollbar on the .parallax div */
body {
  margin: 0;
}

/* parallax "viewport" */
.parallax {
  height: 100vh;

  overflow-x: hidden;
  overflow-y: auto;

  perspective: 1px;
}

.parallax-layer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.layer1 {
  transform: translateZ(0);
}

.layer2 {
  transform: translateZ(-1px);
}

.layer3 {
  transform: translateZ(-2px);
}

There are some things to note about this CSS code.

First, the parallax class is where the magic happens. Defining the height and perspective style properties of an element creates a fixed origin 3D viewport.

The perspective property defines how far away the object is from the user. I have chosen a value of 1px for the perspective property for the parallax class, which means we are very, very close to the div. You can increase this value if you want a more pronounced parallax effect.

The speed of the effect is controlled by the combination of the values provided for perspective and translateZ(). Decreasing the value for translateZ() will push the element further away and that element will scroll slower. The further the value is from zero, the more pronounced the parallax effect i.e. translateZ(-5px) will scroll slower than translateZ(-1px).

Beyond the base CSS, you should always consider the height of the layers. If a layer does not have much content, it may be too small to create appropriately tall scrolling context. Some people like to set a default size in .parallax-layer. That is up to you!

We can change the position of the layers to fulfill our design using the properties: top, right, left, and bottom. Alternatively, we can also use translate3d() to move an element along the x-axis and y-axis.

Now, let’s size, position, and add a background color to each of the layers to demonstrate this all fits together.

Here’s an approximate figure of what we’re doing on the z-axis:

Z Axis Layers Relating to Parallax

Next, we’ll make layer 2 and layer 3 half the height of layer 1, so that we can see each layer distinctly.

Then, we’ll position layer 2 lower on the y-axis with top, so it begins below layer 1. Next, we’ll do the same with layer 3, so that it begins below layer 2:

.parallax-layer.layer1 {
  width: 100%;
  height: 100rem;

  background-color: red;
}

.parallax-layer.layer2 {
  top: 10rem;

  width: 100%;
  height: 50rem;

  background-color: green;
}

.parallax-layer.layer3 {
  top: 20rem;

  width: 100%;
  height: 50rem;

  background-color: blue;
}

div{
  font-size: 50px;
  text-align: center;
}

Here’s the CodePen:

See the Pen
Basic parallax scrolling example
by rob2 (@robatronbobby)
on CodePen.

This is how it looks full screen; it’s kind of like a Russian nesting doll:

Parallax 3D Layers Nesting

Do you find the appearance unexpected in any way? 😕

Do you notice that even though layer 2 and layer 3 have the same height, layer 3 appears to be shorter than layer 2?

This is due to the 3D transformation as we discussed earlier. Layer 3 is further away, so it appears smaller! You can use the scale() function if you want to make them appear equal in size.

Wondering why layer 1 is the bottom layer?

In HTML, the layer 1 div comes before the layer 3 div. These divs are positioned absolutely, meaning that layer 3 should be the layer top as it comes last in the DOM. Well, a transform creates a new stacking context. This promotes each div to sit above what comes before it! So the order of the layers is the reverse of the order in the DOM. 😯

The takeaway is to remember that the first element in the “parallax” container or section will become the bottom layer.

Also, it may be unexpected that our “parallax” div will have a visible scrollbar if you have a margin on the body (as is the default), as shown below. This is because the layers are taller than the container, so they overflow:

Parallax Layers Overflowing

And that’s how the pieces fit together!

If you want to create a design with separate parallax sections, you can consult this section of Keith’s article.

If this all feels a bit overwhelming, don’t worry! Once you explore the core mechanics as we have, you can fill in the missing pieces in your comprehension by exploring some good examples. Let’s gather some!

Good examples using 3D translations

If you would like a guided walkthrough on how to create a parallax hero section, watch this video tutorial. Here’s a CodePen for the example discussed:

See the Pen
CSS
by rob2 (@robatronbobby)
on CodePen.

If you would like to replicate the Firewatch website, here’s a CodePen with a pretty good CSS recreation (the code is written by lemmin):

See the Pen
CSS Only Parallax Example: Firewatch Launch Site
by rob2 (@robatronbobby)
on CodePen.

If you would like to see a version that uses the original Firewatch artwork, Sam Beckham did a short blog post on this topic. Here’s a CodePen of this example:

See the Pen
Firewatch Parallax in CSS
by Sam Beckham (@samdbeckham)
on CodePen.

A next-level exposition of the technique is Lynn’s Fisher work on the Matterday micro website. It is very fun and unique. I think the sticky mini “window” for each background to pass beneath other content is really novel.

Lynn wrote an excellent blog post on how she created this effect. I need to pick through it in more detail to unlock all of the tricks she used! The code is available on GitHub.

Pros and cons of using 3D translations

Pros:

  • Can use multiple layers
  • Can control the speed of layers
  • Cross-browser support is excellent

Cons:

  • More difficult to understand than method 1
  • Implementation can be tricky

Where can you use parallax scrolling?

If you’re looking for some inspiration for where to use parallax scrolling, there are several resources. Adobe wrote an article 10 Best Parallax Website Design Examples that has some excellent designs. Dribble is another good resource. You can search Dribble to find designs from creative folks.

Why use CSS instead of JavaScript?

If you can pull something off in CSS rather than JavaScript, you’ll often get a more performant outcome. As an industry, at one point it seemed that some folks wanted to do everything with JavaScript, but I think there is more enlightenment around this topic now.

Sketch wrote about parallax on their design blog and spoke about how they implemented a subtle parallax scrolling effect on the homepage of their website. They chose to use a JS framework called Stimulus:

And it was simple from a development standpoint, too — as Richárd explains. “We use a super tiny JS framework called Stimulus. It lets us create small JavaScript components that are controlled by HTML data attributes,” he continues. With just a few extra HTML data parameters, the team could control horizontal and vertical velocity based on the speed of scrolling. “So larger objects and elements can move slower and the smaller ones can move faster in the virtual space,” Richárd concludes.

I think it is important to understand that no framework or JavaScript is required! If this blog post was my first introduction to the parallax effect, I could be led to believe that I should implement it with a JavaScript framework too.

Development teams may opt for JavaScript because they are already using a framework and can achieve the same outcome with just a little extra JavaScript. I don’t want to admonish anyone for doing that, it may be justifiable. However, it can be easy to make a habit of shipping more and more JavaScript as you add independent features over time.

Also, remember that it is not a mutually exclusive choice, you can use mostly CSS with some JavaScript. The keyframers did an interesting example of this in a coding stream. Here’s the accompanying CodePen:

See the Pen
Movable Mountains ⛰️ | @keyframers 1.12.0
by Shaw (@shshaw)
on CodePen.

It is important to have a balanced approach like this. You shouldn’t feel polarized and feel it is a CSS vs. JavaScript thing.

There is a time when you will need to reach for JavaScript. If you want an animated scroll experience, this is where JavaScript will be called for. GreenSock is the best JavaScript library for web animation.

Conclusion

A well-crafted parallax scrolling website can help you stand out from the crowd and create a lasting impression on your visitors. But, I would advise caution when using parallax scrolling. You must take care with the design and implementation to ensure that scrolling is not compromised and that the user experience is good on devices of all sizes!

I hope this article demystified the parallax scrolling technique for you and provided insights on how to implement it with CSS. Don’t forget to have fun with it; create something awesome!

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web and mobile apps — .

Rob O'Leary Rob is a solution architect, fullstack developer, technical writer, and educator. He is an active participant in non-profit organizations supporting the underprivileged and promoting equality. He is travel-obsessed (one bug he cannot fix). You can find him at roboleary.net.

One Reply to “Create parallax scrolling with CSS”

Leave a Reply