3D✨ Premium

Layered Parallax 3D

Three translucent indigo, violet and magenta plates stacked at 0, 30 and 60 px of depth, with a pink "3D" badge even further forward: the whole stack tilts toward the pointer up to 10° and the layers shift over one another like a cross-section you turn in your hand — a finger or the arrow keys work too, and it freezes face-on for anyone who chose to limit animation.

JS3DParallax

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. 3D has 50 effects, including 8 free. Explore the category →

3 usage examples

What lies under the road — "Roadworks" page of a metropolitan area — Layered Parallax 3D example 1

① What lies under the road — "Roadworks" page of a metropolitan area

WhenThe page about the Rue Pasteur roadworks shows the road cross-section: 6 cm of asphalt surface, 12 cm of bitumen-bound gravel, 30 cm of sub-base, with the "Rue Pasteur: 3 weeks" badge in front; the cross-section turns under the mouse.
WhyLayers that shift as they turn show a real build-up that nobody ever sees; residents understand why the work takes time, without a technical drawing. Mouse Parallax Scene slides a backdrop around, it would not show thicknesses.
SettingsArea enlarged to 400 × 220 px; layers recolored gravel rgba(146, 132, 112, .92), brown rgba(88, 62, 42, .92) and black rgba(34, 37, 42, .95), same width and decreasing heights (bottom left free by 0, 56 and 112 px) so each caption stays visible; badge widened (width: auto, 13 px) and placed top right with top and right.
The coats of a facade paint — data sheet of a paint maker — Layered Parallax 3D example 2

② The coats of a facade paint — data sheet of a paint maker

WhenThe "Siloxane facade system" sheet shows primer, undercoat and finish stacked, the "10 years" badge in front, and a numbered legend under the stack: "Three coats, one system".
WhyThe tilting cross-section makes visible a build-up you never see on the finished wall. The original shape, each layer a little smaller than the one behind, leaves a rim of every coat around the finish.
Settings330 × 190 px area, original shape (90% and 80%); primer rgba(214, 206, 190, .55), undercoat rgba(255, 255, 255, .85), terracotta finish rgba(196, 98, 64, .92); 64 px round green badge; legend with color chips under the stack.
The layers of a double glazing — simulator of a window maker — Layered Parallax 3D example 3

③ The layers of a double glazing — simulator of a window maker

WhenThe simulator details a 4/16/4 glazing: "Glass 4 mm", "Argon gap 16 mm", "Low-emissivity glass 4 mm", with the "Uw 1.1" badge in front; you turn the cross-section to see the space between the two panes.
WhyTranslucent planes stacked on top of each other are the very substance of glazing; as the stack turns, the two panes separate and the argon gap appears as a real volume between them.
Settings380 × 216 px area; all three layers the same size (inset: 0, no scaling) to stand for panes; bluish and sea-green glass at 30% with a 2 px light edge, argon at 7% with a dashed edge; captions at the top, middle and bottom of each layer; yellow badge top right.

How it works

In the middle of .fx-0007-root, a near-black area 300 px tall or more, the .demo-3d frame (280 × 200 px) hosts the stack. .parallax-container (200 × 140 px) holds the perspective (perspective: 1000px) and listens to the pointer; its child .lp3d-scene is set to transform-style: preserve-3d and holds the layers. The back layer is indigo (rgba(99, 102, 241, .3)) at 0 px; the second one violet (rgba(139, 92, 246, .4)), pushed 30 px forward and scaled to 90%; the third one magenta (rgba(217, 70, 239, .5)) at 60 px and 80%. The badge .lp3d-layer-4, 60 × 60 px, #f43f5e → #ec4899 gradient, sits at 90 px; with inset: auto it stays in its natural place, in the top left corner of the stack.

Every stack on the page has its own instance of the script. When the pointer crosses .parallax-container, its position (0 to 1) rotates .lp3d-scene (rotateX, rotateY): the side under the pointer comes toward you, up to 10° at the edges (9.1° and 8.9° read at 5% from the corner, alike in Chromium 151 and Firefox 153). Since the layers sit at different depths, they do not turn around the same plane: with the pointer at the right edge, the magenta layer slides 10.9 px against the back layer and the badge 15.3 px; with the pointer at the top, the badge drops 17 px. That shift, not the tilt alone, is what reads as thickness. The turn is damped over 0.1 s; as soon as the pointer goes away, the stack swings back face-on.

With a finger or a pen the stack turns the same way (pointer events); touch-action: none stops the page from scrolling during the gesture, and the stack straightens when the finger lifts. From the keyboard, the area takes focus (tabindex="0", named by role="group" and aria-label): each arrow nudges by a tenth the point the stack turns toward, and Escape or tabbing on brings it face-on. The angle is computed as a fraction of the area, not in pixels: a stack enlarged to 400 × 220 px, as in the scenes, still tilts 10° at most. Watch out: on .lp3d-scene, clipped overflow, a filter or any opacity under 1 flattens the 3D and kills the shift between layers.

Accessibility

  • Reduced motion: if the system asks for less animation (prefers-reduced-motion: reduce), a rule of its own under .fx-0007-root cancels the rotation of .lp3d-scene and its transition. The stack stays face-on and still; its layers read as three nested frames with the badge in the corner. The three engines tested (Chromium, Firefox, WebKit) give 0° under the mouse, against 9° normally.
  • Keyboard: tabbing lands on the stack, marked by a 2 px pink #f9a8d4 ring held 6 px off (:focus-visible, 10.9:1 on the background). → ×4 then ↑ ×2 turn it by 8.0° and 4.0°; Escape, or moving on to the next element, straightens it.
  • Screen readers: the stack is announced as a group named "Layered stack: the arrow keys tilt it" (aria-label). The empty layers are not read, the badge is ("3D"). If your layers carry meaning (materials, steps), write it as text in the layers or next to them, like the captions of the road and glazing scenes, and translate the aria-label.
  • Contrast: "3D" in 24 px bold white on the badge: 3.7:1 on #f43f5e and 3.5:1 on #ec4899, enough for large text (3:1 threshold). For smaller text in the badge, darken its gradient.

Browser compatibility

CSS (perspective, transform-style: preserve-3d, translateZ, touch-action, :focus-visible) + JS with pointer events, no dependencies. Measured in Chromium 151 and Firefox 153: same tilt, same shifts between layers (10.9 px for the magenta layer at the right edge), two independent copies on one page, face-on stack under reduced motion, finger rotation (Chromium in touch mode). Playwright's WebKit (26.5) flattens all nested 3D, even on a reference cube: its captures show the stack with no shift between layers, which says nothing about the real Safari, not checked.

Chrome 55+✓ Full
Firefox 59+✓ Full
Safari 13+✓ Not checked on a real Safari
Edge 79+✓ Full
Mobile iOS 13+✓ Not checked on a real iPhone
Android Chrome✓ Full, with the finger

Without preserve-3d (or if a parent flattens it), the stack turns as one block and the layers no longer shift: you keep three nested frames that tilt. Without :focus-visible, the browser's default focus ring shows instead.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0007-root">
  <div class="demo-3d">
    <div class="parallax-container" tabindex="0" role="group" aria-label="…">
      <div class="lp3d-scene">
        <div class="lp3d-layer lp3d-layer-1"></div>
        <div class="lp3d-layer lp3d-layer-2"></div>
        <div class="lp3d-layer lp3d-layer-3"></div>
        <div class="lp3d-layer lp3d-layer-4">3D</div>
      </div>
    </div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Maximum tilt (JS — MAX_TILT = 10) 10° Angle reached at the edges, whatever the stack size. At 6 the layers barely shift; at 15 the shift is much more pronounced.
Layer depth (CSS — translateZ of .lp3d-layer-2, -3, -4) 30, 60 and 90 px The shift between layers is proportional to this gap: double all three values (60, 120, 180) and the magenta layer slides about twice as far at the same angle.
Layer size (CSS — scale(.9) and scale(.8)) 90% and 80% Without scaling, the layers have the same size and overlap like panes; with different heights (inset), they form bands, as in the road scene.
Colors (CSS — background of .lp3d-layer-1 to -4) rgba(99, 102, 241, .3), rgba(139, 92, 246, .4), rgba(217, 70, 239, .5), #f43f5e → #ec4899 Keep the back and middle layers transparent: that transparency is what reveals the stack.
Badge (CSS — .lp3d-layer-4) 60 × 60 px, top left corner width: auto and a padding for a label; top and right to place it elsewhere; inset: 0; margin: auto to center it.
Area size (CSS — .parallax-container, .demo-3d) 200 × 140 px in a 280 × 200 px frame Enlarge .demo-3d as well, or remove its dimensions. The angle does not change with the size.
Perspective (CSS — perspective: 1000px on .parallax-container) 1000px 600px stresses the depth (front layers clearly larger); 2000px flattens the whole thing.

FAQ

With inset: auto, the badge keeps the natural place of a positioned element: the top left corner of the stack, which makes it stick out like a label. To center it, give it inset: 0; margin: auto; to put it top right, top: -16px; right: -14px, as in the scenes.
Here a stack of layers turns in real 3D, and that rotation is what creates the shift. Mouse Parallax Scene slides the planes of a landscape flat, at different speeds, with no rotation. Immersive Depth Scroll slides three nested frames, the deepest one traveling farthest. To show thicknesses: Layered Parallax 3D; for a backdrop: Mouse Parallax Scene.
Three properties on .lp3d-scene make the browser flatten its content: overflow: hidden, filter, and an opacity under 1. The stack then turns as one block. Put those properties on the root or on the layers themselves, never on .lp3d-scene. Also check that .parallax-container keeps its perspective.