Side-Scrolling Parallax Background Effect Using Only CSS3

View Demo

The parallax effect, or using multiple moving images to give the illusion of depth, is increasingly being used on sites across the web. So its worth exploring how we can create this effect using CSS, without the need for any JavaScript.

Let’s start out with this:

.bg {
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  right:0;
  background:url('front.png') 0 0, url('middle.png') 40% 0, url('back.png') 80% 0, #000;
}

<div class="bg"></div>

This styles the element to stretch to the size of the first non statically-positioned parent element, and layers three different background images on top of each other. Note that the x-positioning of each image is offset a certain percentage, so as the element size changes the images move disproportionately to each other, creating that sweet depth effect.

parallax

Now to get them moving we have a number of options. First option is to use the transition declaration, and add it to the .bg class. Vendor prefixes are still needed for some browser versions— check out Can I Use for the latest details on which browsers support CSS transitions.

.bg {
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  right:0;
  background:url('front.png') 0 0, url('middle.png') 40% 0, url('back.png') 80% 0, #000;
  -webkit-transition: left 300s linear;
     -moz-transition: left 300s linear;
       -o-transition: left 300s linear;
          transition: left 300s linear;
}

What that transition declaration says here is: when the element’s left declaration changes, move it linearly (as opposed to any of the other easing options) for a period of 300 seconds. So in order to actually see something move we need to change the value of left on .bg. There are a number of pseudo-classes we can use to do this; for example on hover of the element:

.bg:hover {
  left:-9999px;
}

View Demo

This means that when the mouse pointer is over the element, it will move 9999 pixels to the left, and because of the transition declaration, it will do it over a period of 300 seconds. Of course, using :hover requires the user to actually take an action for the movement to start, and to continue. To make it begin automatically, we can instead use the :target pseudo-class, which is triggered whenever the hash in the URL matches the ID of an element. So we do this:

#bg-target {
  left:-9999px;
}
<div class=”bg” id=”bg-target”></div>

And the element will move whenever the #bg-target hash is in the URL (ex: index.html#bg-target)

View Demo

Now there are two main problems with using the transition declaration. First, without using any JavaScript the animation can’t be started unless there is a trigger (like :hover or :target), which is terribly inelegant. Second, once the transition completes, it stops, and if the trigger is removed it moves back to its original position.

So an alternate way we can get those background images moving the way we want them (without a trigger) is to use CSS animation. Note the browser support as well. We end up with this:

.bg {
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  right:0;
  background:url('front.png') 0 0, url('middle.png') 40% 0, url('back.png') 80% 0, #000;
  -webkit-animation: moving-images 400s ease infinite;
     -moz-animation: moving-images 400s ease infinite;
       -o-animation: moving-images 400s ease infinite;
          animation: moving-images 400s ease infinite;
}

It’s that same .bg class but with an animation declaration this time. The moving-images bit is the animation name which you can set to whatever you want, 400 seconds is the length of animation, ease movement gently slows the animation before and after it changes position, and infinite refers to the amount of times it should loop.

Now to define what actually animates:

@keyframes moving-images {
  0%   {left:0;}
  50%  {left:-9999px;}
  100% {left:0;}
}
@-moz-keyframes moving-images {
  0%   {left:0;}
  50%  {left:-9999px;}
  100% {left:0;}
}
@-webkit-keyframes moving-images {
  0%   {left:0;}
  50%  {left:-9999px;}
  100% {left:0;}
}
@-o-keyframes moving-images {
  0%   {left:0;}
  50%  {left:-9999px;}
  100% {left:0;}
}

This says that the animation should start at its original left:0 position, move to -9999 pixels halfway through, and then move back to 0 at the end, so that when the animation loops over it doesn’t jarringly start from 0. This allows us to get that parallax effect moving back and forth, automatically and infinitely.

View Demo

The practical uses of what we’ve done here are admittedly limited (perhaps to spice up a site header?), but it does serve to show how many different possibilities CSS allows for, and that there are times when JavaScript isn’t the only answer.

Posted by Ron Radu @ronradu ·

Ron's role at Palomino Labs finds him working with developers to manage and guide the products they build. He has experience working on a broad swath of web and mobile projects, often wearing many different hats. Ron spends the rest of his time designing and assembling pretty and usable interfaces for clients, and making regular code commits.

About Palomino Labs

Palomino Labs unlocks the potential of software to change people and industries. Our team of experienced software developers, designers, and product strategists can help turn any idea into reality.

See the Palomino Labs website for more information, or send us an email and let's start talking about how we can work together.