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:
- The
emunit has better cross-browser support thanrem. em’s requirement of a parent element means that parallax effects can be restricted to a container; under Adam’sremmethod, 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 very simple: just three images and a heading inside a <div> element.
<div id="parallax">
<h1>Simple EM Parallax Technique</h1>
<img src="candles.jpg" alt id=candles>
<img src="cherry-tree.jpg" alt id=cherry>
<img src="pagoda-surrounded-by-trees.jpg" alt id=pagoda>
</div>
The CSS isn’t much more complicated:
div#parallax {
background-image: url(blurred-background-small.jpg);
background-size: cover; padding-top: 62.5%;
overflow: hidden; position: relative;
font-size: .1em; }
div#parallax * { position: absolute; }
div#parallax img {
width: 40%; height: auto;
box-shadow: 0 .2em 8px 4px rgba(0,0,0,0.5);
}
div#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);
}
#candles { left: 5%; bottom: 22em; }
#cherry { left: 28%; z-index: 3; bottom: 8em; }
#pagoda { 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 emParallax() {
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.
Pro CSS3 Animation, Apress, 2013
Massive Head Canon
The New Defaults
CSSslidy