Go to homepage

Projects /

Parallax Hero Image

A full-width figure element, with floating images distributed in a 3D space.

Parallax Hero Image
Check our new component library →

What you can achieve through CSS 3D Transforms is limitless. With power comes responsibility, though. There will be cases when you’ll take full advantage of CSS 3D capabilities. In most projects, though, you can just spice things up a little.

Today's nugget is an effect which is getting quite popular and relies on 3D Transforms. In a nutshell, we distributed some images on the z-axis, then we used the mouse as a (fake) 3D camera so that perspective changes while you move the mouse cursor. What we really do is rotating the images in the 3D space according to the mouse position.

Since this effect relies on mouse movement, on mobile devices it won't be visible.

You can see this cool effect in action on websites like Squarespace and HelloMonday.

Image credits: Unsplash and Subtle Patterns.

👋 A new version of this component is available. Download now →.

Creating the structure

The main HTML structure is a <figure> element containing our hero image (we used 3 different <img>s) and wrapped in a .cd-background-wrapper element.

<div class="cd-background-wrapper">
   <figure class="cd-floating-background">
      <img src="img/cd-img-1.jpg" alt="image-1">
      <!-- images here -->

The images used should have the same dimensions.

Adding style

To create the hero image we put the <img> elements one on top of the others: the first one has a static position, while the others are in absolute position; a different translateZ value is assigned to each of them.

The idea behind the parallax effect: when user moves his mouse over the hero image, the .cd-floating-background element is rotated (along the X and Y axises)  according to the mouse position. Since the <img> elements  have different translateZ values, a different rotation is perceived for each of them.


To properly achieve this effect, we have to make sure that our <img>s are properly positioned in a 3D-space: first, we assign a perspective value to the .cd-background-wrapper, which creates a 3D-space shared by its children; then we assign a transform-style: preserve-3d to the .cd-floating-background so that its children are positioned in a 3D space rather than flattened (as default). TranslateZ does the rest!

.cd-background-wrapper {
  overflow: hidden;
  perspective: 4000px;

.cd-floating-background {
  transform-style: preserve-3d;

.cd-floating-background img:first-child {
  transform: translateZ(50px);

.cd-floating-background img:nth-child(2) {
  transform: translateZ(290px);

.cd-floating-background img:nth-child(3) {
  transform: translateZ(400px);

About IE: IE9 doesn't support CSS3 3D Transforms while IE10+ doesn't support the transform-style: preserve-3d property. So the parallax effect won't be visible in IE and you'll see a standard image.

Events handling

We bind the initBackground() function to the image load event: this function changes the position property value of the <figure> element from relative to absolute (the  'is-absolute' class is used). At that point, we need to assign a proper height to the .cd-background-wrapper element (since its child is in absolute position, its default height is 0) and proper dimensions to the .cd-floating-background (it has to be bigger than its wrapper - this way rotation won't reveal empty borders).

We evaluate the image aspect ratio and the viewport width and assign to the .cd-background-wrapper a height equal to viewportWidth/heroAspectRatio. The .cd-floating-background height and width are proportional to the .cd-background-wrapper ones and its left and top parameters are set so that the image is centered inside its parent.

We then bind the mousemove event to the .cd-background-wrapper: the mouse position is evaluated using event.pageX and event.pageY and a corresponding rotateX and rotateY value is assigned to .cd-floating-background.

Note: Modernizr doesn't detect preserve-3d support yet. So, in order to target browsers that don't, we used the getPerspective function which assigns a preserve-3d/no-preserve-3d class to the <html> according to browser support (Modernizr - issue 762).

Project duplicated

Project created

Globals imported

There was an error while trying to export your project. Please try again or contact us.