Create an auto-scrolling parallax effect without JavaScript

Here’s another quick CSS3/WebKit tran­si­tions project in the con­tro­ver­sial realm of CSS ani­ma­tion. This time I have opted to recre­ate the pop­u­lar par­al­lax effect using mul­ti­ple back­ground images on a sin­gle ele­ment and the -webkit-transition prop­erty (doc­u­men­ta­tion). I have based this on Chris Coyier’s par­al­lax tuto­r­ial, reusing the star images with per­mis­sion, the tech­nique itself was coined by Paul Annett (expla­na­tion on Think Vit­a­min). If you’re not quite sure what par­al­lax is, then Chris and Paul both go into some depth to explain it and Wikipedia is always help­ful.

Result

Exper­i­ment: Auto-scrolling CSS3 Par­al­lax Effect
Exper­i­ment works in Safari 4 Beta and Google Chrome. No JavaScript necessary.

Exper­i­ment updated. Tran­si­tions are now widely sup­ported. Sup­port includ­es Opera, Fire­fox and IE10.

Correctly rendered background images for parallax effect

How To

The HTML markup is fairly sim­ple, one DIV for the back­ground and another for the con­tent, the exam­ple uses CSS3’s mul­ti­ple back­grounds, so no need for extra markup to accom­mo­date all those other images:

<div id="background"></div>
<div id="content">
	Content
</div>

For the CSS the back­ground con­tainer is set to a fixed posi­tion (for con­ve­nience more than any­thing) and spread across the bot­tom of the page using the top, left, bot­tom and right prop­er­ties. The back­ground images are defined using the back­ground short­hand prop­erty with mul­ti­ple dec­la­ra­tions being comma delim­ited, the first being the top-most. Each of the images has a dif­fer­ent posi­tion defined in per­cent­age, so as the size of the con­tainer changes (e.g. on win­dow resize) the images move dis­pro­por­tion­ately to each other; cre­at­ing the impres­sive par­al­lax effect.

#background {
	background: url('../images/foreground.png') 5% 5%,
		url('../images/midground.png') 20% 20%,
		url('../images/background.png') 90% 110%;
}

Ordi­nar­ily this effect is only seen when the page is re-sized or JavaScript is used for ani­ma­tion. My first approach to ani­ma­tion via CSS was to apply the tran­si­tion to the background-positions, with background-position being an ani­mat­able prop­erty as defined in the pro­posed spec­i­fi­ca­tion. How­ever this doesn’t yet work in the lat­est WebKit nightly build (r42142), it is a known bug.

As an alter­nate route, albeit a tem­po­rary one, I have opted to use tran­si­tions to ani­mate the left-most edge of the back­ground con­tainer (for instance from 0px to –100px). This grad­u­ally alters the over­all width of the con­tainer caus­ing the back­grounds to shift dis­pro­por­tion­ately as per their per­cent­ages, cre­at­ing the par­al­lax effect. With a large enough dura­tion and left posi­tion the effect appears to be continuous.

#background {
	left: 0;
	-webkit-transition: left 300s linear;
}

#experiment:target #background {
	left: -5000px;
}

To make things a bit more fun I’ve increased the ‘fly­ing speed’ when the mouse hov­ers over the back­ground area. The final CSS looks like this:

#background {
	background: url('../images/foreground.png') 5% 5%,
		url('../images/midground.png') 20% 20%,
		url('../images/background.png') 90% 110%;
	top: 218px;
	left: 0;
	right: 0;
	bottom: 0;
	position: fixed;
	-webkit-transition: left 300s linear;
}

#experiment:target #background {
	left: -5000px;
}

#experiment:hover #background {
	left: -9999px;
}
Paul Hayes

Paul Hayes is a developer at Last.fm. You should follow him on Twitter, where he talks about UX, HTML, CSS and JavaScript, amongst other cool stuff.