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.
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; }
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)
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.
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.