4 Pure CSS3 with JSPublished 2026-10-05Free · no sign-up
Seven parallax effects: hills that move at different speeds, shapes that follow the pointer, the no-script perspective technique, a fixed-background window, a headline that drifts slower than the page, a product card with depth on hover and image drift with a view() timeline.
Three hill layers move at different speeds as the panel scrolls, the far hills slowest. A scroll listener writes the scroll position into one custom property and each layer multiplies it by its own speed in a translateY, all on the compositor.
View code
<div class="px1" tabindex="0" role="region" aria-label="Scroll this panel"><div class="scene" aria-hidden="true"><i class="l1"></i><i class="l2"></i><i class="l3"></i></div><div class="content"><h3>Into the hills</h3><p>Scroll to see the layers move at different speeds.</p></div></div>
var p = document.querySelector('.px1');
if (!matchMedia('(prefers-reduced-motion: reduce)').matches) p.addEventListener('scroll', function () { p.style.setProperty('--s', p.scrollTop); }, { passive: true });
02. Layers That Follow the Pointer
ParallaxPointer
Moving the pointer over the hero shifts its decorative shapes by different amounts, so the near ones move most. The pointer offset from the centre is stored once in two custom properties and each shape scales it by its own depth.
var h = document.querySelector('.px2');
if (!matchMedia('(prefers-reduced-motion: reduce)').matches) {
h.addEventListener('pointermove', function (e) { var r = h.getBoundingClientRect(); h.style.setProperty('--x', ((e.clientX - r.left) / r.width - .5).toFixed(3)); h.style.setProperty('--y', ((e.clientY - r.top) / r.height - .5).toFixed(3)); });
h.addEventListener('pointerleave', function () { h.style.setProperty('--x', 0); h.style.setProperty('--y', 0); });
}
03. Pure CSS Perspective Parallax
ParallaxNo JS
The no-script technique: the scroll container has perspective, and layers pushed back with translateZ move more slowly as it scrolls. A matching scale() keeps the far layer at its original size. It is smooth because the browser does all the work.
View code
<div class="px3" tabindex="0" role="region" aria-label="Scroll this panel"><div class="grp"><div class="back" aria-hidden="true">PARALLAX</div><div class="front"><p>Scroll. The big word behind moves slower than this text.</p></div></div><div class="more"><p>Content continues normally below.</p></div></div>
The oldest parallax: background-attachment: fixed makes a section's background stay still while the content scrolls over it, like looking through a window. iPhone Safari ignores it and scrolls normally, which is a safe fallback.
View code
<div class="px4" tabindex="0" role="region" aria-label="Scroll this panel"><p>Scroll down to pass the window.</p><div class="win"><b>Behind the glass</b></div><p>The striped background stayed still while this text moved.</p></div>
A big headline drifts up at half the scroll speed and fades as the content rises over it. One scroll handler sets a custom property, and calc() turns it into both the offset and the opacity, so there is a single source of truth.
View code
<div class="px5" tabindex="0" role="region" aria-label="Scroll this panel"><h3>Make it<br>yours.</h3><div class="body"><p>Custom engraving on every order, at no extra cost.</p></div></div>
var p = document.querySelector('.px5');
if (!matchMedia('(prefers-reduced-motion: reduce)').matches) p.addEventListener('scroll', function () { p.style.setProperty('--s', Math.min(p.scrollTop, 200)); }, { passive: true });
06. Hover Depth Card
ParallaxHover
A product image with its shadow and its badge on different planes: on hover the image moves up a little, the shadow stays down and spreads, and the badge moves up more. Three different translate distances on one hover create a sense of depth.
Images inside rounded frames drift upward slower than their frames as you scroll, the classic editorial parallax, built entirely in CSS with animation-timeline: view(). The image is taller than its frame so the drift never shows an edge.
Parallax is simply nearer things moving more than farther ones. Store one input, scroll position or pointer offset, in a custom property and multiply it by a different factor for each layer.
The pure CSS method
Give the scroll container perspective: 1px and push a layer back with translateZ(-1px) scale(2). It scrolls at half speed with no JavaScript, though the container must be the element that scrolls.
Use transform only
Move layers with transform, never top or margin, and mark scroll listeners passive. Scroll-driven animations with animation-timeline avoid script entirely.
Turn it off for comfort
Parallax is one of the motion effects most likely to cause dizziness. Every demo checks prefers-reduced-motion and stays still when it is set.
Frequently asked questions
Why does background-attachment: fixed not work on my iPhone?
iOS Safari treats it as scroll, so the background moves with the page. The section still looks fine.
Does parallax hurt performance?
Moving large images can on slow phones. Keep layers few and use transform, and test on a real device.
Is parallax bad for accessibility?
It can be for people with vestibular disorders, which is why the reduced-motion fallbacks matter.