Making a 3D Parallax Effect with CSS
Tags: html, css, webdev, tutorial
Published: 2023-07-27 17:32:26

While it may seem complicated at first, making a 3D parallax effect with CSS is pretty easy and straightforward.

Let's say we have a `div` element with two nested `div` elements (children) and we want to apply the 3D parallax effect to them:
### - HTML

```html
<div id="container">
  <div id="child1" />
  <div id="child2" />
</div>
```
### - CSS
```css
#container {
  width: 150px;
  height: 150px;
  background-color: green;
  display: grid;
  place-items: center;
  animation: rotate 5s ease-in-out infinite;
}
#child1 {
  width: 70%;
  height: 70%;
  background-color: blue;
  grid-area: 1/1/1/1;
}
#child2 {
  width: 30%;
  height: 30%;
  background-color: yellow;
  grid-area: 1/1/1/1;
}
```

After applying a simple CSS [@keyframes](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes) animation for demonstration purposes, it looks like this:

{% codesandbox affectionate-panini-np4yxh %}

you can add the 3D parallax effect by following these steps:

## 1. Add `transform-style: preserve-3d` to the parent/container

For the 3D effect to work, you first need to set the [`transform-style: preserve-3d`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style) on the parent/container element. This will let the browser know that it should render the element and it's children in 3D space.

```css
#container {
  ...
  transform-style: preserve-3d
}
```

## 2. Add the `perspective` property to the parent/container (optional)

The next step is adding the [`perspective`](https://developer.mozilla.org/en-US/docs/Web/CSS/perspective) property to the parent/container element. the value of this property determines how close/far the elements are from the user. you can set the value using 'px', 'em', 'rem', etc. units.

```css
#container {
  ...
  perspective: 1000px;
}
```


## 3. Move/Translate the children along the `Z` axis

Even though the elements are now rendered in 3D space, all of the elements are on the same plane ( they all have `translateZ` of `0` which means they are stacked on top of each other). to really see the 3D effect you need to move them back and forth along the `Z` axis. you can do it in different ways:

###- The [`translate`](https://developer.mozilla.org/en-US/docs/Web/CSS/translate) property
```
translate: 0 0 100px;
```

###- The[`translateZ()`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateZ) function of the [`transform`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform) property

```
transform: translateZ(100px);
```

###- The [`translate3d`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate3d) function of the [`transform`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform) property

```
transform: translate3d(0, 0, 100px);
```
---

After following these steps, our CSS will look like this:

```css
#container {
  ...
  transform-style: preserve-3d
  perspective: 1000px;
}
#child1 {
  ...
  translate: 0 0 50px;
}
#child2 {
  ...
  translateZ: 0 0 100px;
}
```
And this is what it looks like in action:

{% codesandbox zen-babbage-zstyz7 %}

---

While the 3D parallax effect is easy to set up, there are a few caveats.

When applying some CSS properties, the browser has to flatten the layers (remove the 3D effect), which means if you use these properties, the effect will not work. these properties include:

### - [`overflow`](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow)

### - [`mix-blend-mode`](https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode)

### - [`opacity`](https://developer.mozilla.org/en-US/docs/Web/CSS/opacity)

### - [`filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter)

### - [`clip-path`](https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path)

To read more about these properties and possible workarounds, you can read [this article](https://css-tricks.com/things-watch-working-css-3d/#aa-things-that-break-3d-or-cause-flattening).