Parallax Depth Text
Three text layers glide at different speeds with the pointer — the movement differential and opacity hierarchy create 3D depth in pure CSS/JS.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Text has 56 effects, including 4 free. Explore the category →
3 usage examples



How it works
The markup uses three .kt-parallax-layer elements positioned absolutely inside a .kt-parallax-container with perspective: 600px. Each layer declares its speed via data-speed: 0.08 for the background, 0.04 for the middle, 0.01 for the foreground. All share the same text — the speed gap alone creates the 3D illusion without any canvas or WebGL.
A mousemove listener on the .demo-preview wrapper normalizes the pointer position to centered coordinates (−0.5 to 0.5 on each axis). Each layer's translation is tx = x × speed × 800 and ty = y × speed × 400 (2:1 horizontal/vertical ratio): at speed 0.08, the back layer can shift up to ±320 px on X; at speed 0.01, the foreground barely ±40 px.
The CSS property transition: transform .15s ease-out on each layer interpolates to the new position on every event — no requestAnimationFrame, no loop. The mouseleave event resets all transforms to translate(0,0) using the same transition, easing the layers smoothly back to rest.
The visual hierarchy reinforces the spatial reading: the back layer is at 25% opacity and 2.6 rem; the middle at 50% and 2.4 rem; the foreground at full opacity with an indigo text-shadow — the eye reads the least opaque layer as most distant, the brightest as closest.
Accessibility
- prefers-reduced-motion absent: the code does not check this preference — translations fire even when the user has enabled reduced motion. Fix by adding
if (window.matchMedia('(prefers-reduced-motion:reduce)').matches) return;before themousemovelisteners. - No
aria-hiddenorrolein the provided code: if the layers are purely decorative, addaria-hidden="true"to the container; if they carry informational content, addrole="img"andaria-label. - Text is rendered as native HTML (not canvas) — it is selectable, copyable, and read by assistive technologies even without JS.
- Only the foreground layer (white, 2.2 rem) needs to meet WCAG AA contrast (≥ 4.5:1 on a dark background). The back layers (25–50% opacity) are decorative and are not required to meet the threshold.
- The effect has no interactive elements: keyboard navigation is unaffected, no focus trap.
Browser compatibility
Requires CSS transform/transition and DOM mousemove/mouseleave events — universal support since 2015. Zero external dependencies.
Without JS, all three layers display stacked at their natural position — text remains readable. Without CSS transform, the layers overlap without offset, no fatal JS error.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="demo-preview">
<div class="kt-parallax-container" id="parallax1">
<div class="kt-parallax-layer" data-speed="0.08">Text</div>
<div class="kt-parallax-layer" data-speed="0.04">Text</div>
<div class="kt-parallax-layer" data-speed="0.01">Text</div>
</div>
<span class="demo-hint">Move your mouse</span>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| data-speed (per layer) | 0.08 / 0.04 / 0.01 | Translation coefficient per layer. Higher value = faster movement. Widen the gap between layers for a more dramatic depth effect. |
| Color — .kt-parallax-layer:nth-child(1) | rgba(99, 102, 241, 0.25) | Color of the back layer (fastest). Reduce opacity to 0.10–0.15 for a more subtle background; change hue to match your brand. |
| Color — .kt-parallax-layer:nth-child(2) | rgba(139, 92, 246, 0.5) | Color of the middle layer. Adjust opacity between 0.3 and 0.7 to strengthen or soften the depth perception. |
| font-size per layer | 2.6 / 2.4 / 2.2 rem | Decreasing from back to front. Reversing the ratio (larger in front) or equalizing sizes dramatically changes the spatial reading. |
| perspective (container) | 600px | CSS perspective value on .kt-parallax-container. 300 px = stronger 3D distortion; 1200 px = subtler, more restrained effect. |
| transition (layers) | transform .15s ease-out | Mouse-follow delay and easing. 0.25s ease-in-out = organic, fluid movement; 0s = snapped to the pointer, reactive but jittery. |
| Horizontal amplitude — JS constant | 800 | X multiplier in tx = x × speed × 800 (var tx line). Reduce to 500 for less lateral shift, increase to 1200 for a cinematic effect. |
| Vertical amplitude — JS constant | 400 | Y multiplier in ty = y × speed × 400 (var ty line). Reduce to 200 to minimize vertical shift (useful when the container is short). |
FAQ
<div class="kt-parallax-layer" data-speed="0.16"> as the first child of the container (higher speed = even more distant layer visually) and add a :nth-child(4) CSS rule with reduced opacity (0.10) and a slightly larger font-size. The JS reads all layers via querySelectorAll('.kt-parallax-layer') and processes them automatically — no JS changes needed.mousemove does not fire on touch. To enable parallax on mobile, add a touchmove listener that feeds the same x/y variables, or a deviceorientation listener based on gyroscope tilt. Without these, layers stay at their initial position — text is readable but static..kt-parallax-layer is an independent HTML div. Place different words, sizes, or even images in each layer. The depth effect comes purely from the movement speed (data-speed), not from repeating the same text — you can have a main word in the foreground and a secondary word or decorative text in the background.