Simple EM Parallax Technique

Recently Adam Mustill created a very clever parallax technique through manipulation of the root em unit on a web page. My students are constantly asking how to achieve parallax effects, and I thought this method might be a very good place to start.

Parallax usually involves the complex manipulation of dozens of separate DOM elements, but this technique allows the easy manipulation of elements by changing a single measurement. My variation simplifies and (I think) improves on the technique, taking advantage of a curious feature of the CSS em unit: if both parent and child elements are measured in em, the individual measurements multiply together to affect the children. While this is usually a headache to deal with (and a good reason to use rem, if you can) it has two major advantages in this case:

  1. The em unit has better cross-browser support than rem.
  2. em’s requirement of a parent element means that parallax effects can be restricted to a container; under Adam’s rem method, everything in the <body> is affected by scrolling unless explicit steps are taken to counteract the effect.

I’ve also simplified Adam’s code down to a single line of JavaScript, rather than multiple lines of JQuery, improving performance even more.

The HTML & CSS

The markup for the example is straightforward: just three images and a heading inside a <div> element.

<div id="parallax">
	<h1>Simple EM Parallax Technique</h1>
	<img src="candles.jpg" alt>
	<img src="cherry-tree.jpg" alt>
	<img src="pagoda-surrounded-by-trees.jpg" alt>
</div>

The CSS isn’t much more complicated:

#parallax {
	background-image: url(blurred-background-small.jpg);
	background-size: cover;
	padding-top: 62.5%; 
	overflow: hidden;
	position: relative;
	font-size: .1em;
}
#parallax * { position: absolute; }
#parallax img {
	width: 40%; height: auto;
	box-shadow: 0 .2em 8px 4px rgba(0,0,0,0.5);
}
#parallax h1 { 
	font-size:3rem; color: #fff; z-index: 2;
	top: 0; text-transform: uppercase;
	width: 100%; text-align: center;
	text-shadow: 0 .2em 5px rgba(0,0,0,0.4); 
}
#parallax img:nth-of-type(1) {
	left: 5%; bottom: 22em;
}
#parallax img:nth-of-type(2) {
	left: 28%; z-index: 3; bottom: 8em;
}
#parallax img:nth-of-type(3) {
	left: 55%; bottom: 12em;
}

The important aspects to note are the very small default value for em on the #parallax container, the bottom values for each image, and the fact that the heading text is measured in rem units, rather than em.

The JavaScript

This initial setup is manipulated by a single line of JavaScript:

window.onscroll = function() {
	if (window.pageYOffset > 0) {
		document.getElementById("parallax").style.fontSize = (window.pageYOffset/20)*.1+"em";
		}
	}

Very simply, scrolling the browser window causes the em font size of the #parallax container to change in response. This change is dependent on how many pixels down the user has scrolled, divided by 20, multiplied by the base .1em font size. Scrolling down the page magnifies the bottom values of each image, pushing them upward. Measured in rem units, the heading remains unaffected, with its z-index allowing the images to slide above and below it.

Conclusion

There’s a lot more that could be done with this effect, and I plan to show a grander full page example in the very near future.

Photographs by Hiro R, licensed under Creative Commons.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/PzYrZO