How to Create Lightweight Parallax Effects

Great progress has been made in the general user experience of the web in recent years. In stark contrast to early popup animations that polluted webpages in the early days of HTML, designers have now caught on to the idea of creating “Natural” experiences. These experiences take inspiration from the physical world – a world where things don’t appear and disappear instantaneously, but instead fade in and fade out, or move in and out of a person’s sight smoothly. Another feature of the physical world is the existence of spatial depth – that is, things are 3D and not 2D as they appear on a computer screen.

While virtual reality is working on overcoming this obstacle, 2D surfaces like webpages can use some tricks to make things seem to have depth. On such trick is “Parallax”, a technique in which different components of a page scroll at varying relative speeds. This method makes it seem as though multiple layers exist on a simple plane, and make things seem more lifelike to users. The added attraction of parallax makes it a great way to grab a user’s attention at the top of a page.

Parallax is most often established by a combination of CSS and JS, and several libraries are available to achieve this effect more easily. The objective of this post, however, is to show how this can be done more minimally.

This codepen marks our starting point. A captivating image has been selected with a bold headline in an attempt to maintain the attention of the user, but parallax could improve it further.


This makes for a good start. One important detail to notice is that a distinct element (hero__backgroundImage) has been created for the background image, and this element has been absolutely positioned within its container. This separation is important because it allows the image to move independently of its container.

With the basic markup in place, the next step is considering how the relative motion is best created. One idea would be setting the background position of the image to vary with the window’s scroll position. A pure JS implementation of this strategy is shown in the following pen. Notice that the browser’s requestAnimationFrame API is used to throttle CSS property writes to a reasonable frequency. Fortunately, this method now has great cross browser support:


While this technique gets the job done nominally, it breaks some performance best practises. Namely, it relies on animating the background-position-y property, which is not ideal. It’s well known that transform and opacity make the best targets for animation if performance is of importance. With this in mind the final solution can be improved to the following (Interestingly, the smoothness of these variations are not noticeable to myself. Perhaps they would be more apparent on more complex sites running on slower computers).