CSS only parallax using perspective and transform3d

When building single-page sites, generally we rely on javascript plugins to create effects for images and animations. Here we are going to look at a simple header parallax effect using only css

To create a parallax effect using css we can utilise 3d transforms combined with perspective to create layers of content. However these layers will stay at the same position and angle unless we can make the perspective relative to the scroll position. That's the trick!

Caveats to this approach:
  • You need to change html scrolling to body/div scrolling, which could affect other plugin/effects
  • If you want fixed elements above your parallax image, you have to put them outside the scrolling area
  • Touch scrolling for iOS devices is not supported in the same area as 3d transform, so you have to pick one or the other
1) 3d transforms are not supported on the html element, so our first step is to disable the scrolling fit the height to 100% to ensure the inner elements can use 100% height.

body {
    height: 100%;
    overflow: hidden;

2) For this example I would like to have a fixed header on top of the parallax image, so we need have the header html outside of the scrolling area:

<div class="header">

And some css for the header:

.header {
    background-color: #fff;
    position: fixed;
    width: 100%;
    z-index: 3;

3) Now we need add the scrollable area below the fixed header

<div class="header">
<div class="container">
    <div class="banner">
        <img src="http://5d48184523c8a489ed05-91a4b8ed85c04e5358f91889505a4163.r43.cf1.rackcdn.com/6/4/large.jpg" alt="" class="image" />
    <div class="content">
        <p>rest of page content</p>

and add some css to make the container scrollable and have start the 3d perspective. Note: using -webkit-overflow-scrolling: touch; will prevent the 3d transforms from working properly.

.container {
    height: 100%;
    -webkit-perspective: 100px;
    perspective: 100px;
    -webkit-perspective-origin: 0 0;
    perspective-origin: 0 0;
    overflow-x: hidden;
    overflow-y: auto;

4) If you have any additional div containers between the scrolling container and the image itself, you will need to use preserve-3d to retain the perspective. So in this case we will add the css to our banner area:

.banner {
    position: relative;
    -webkit-transform-style: preserve-3d;
    transform-style: preserve-3d;
    z-index: -1;

5) Last step is to move the image back in 3d space, and scale it back to fit the view:

.banner .image {
    -webkit-transform: translateZ(-50px) scale(2);
    transform: translateZ(-50px) scale(2);
    width: 100%;

Now you have a working parallax banner. You can see it working here: