SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/parallax-effects

7 CSS Parallax Effects

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.

01. Layered Landscape on Scroll

ParallaxScroll

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>
.px1 { --s: 0; position: relative; width: 280px; max-width: 100%; height: 280px; overflow-y: auto; border-radius: 16px; background: linear-gradient(#1e1b4b, #7c3aed 70%, #f472b6); font-family: Inter, system-ui, sans-serif; }
.px1:focus-visible { outline: 2px solid #f9a8d4; outline-offset: 2px; }
.px1 .scene { position: sticky; top: 0; height: 280px; margin-bottom: -280px; overflow: hidden; }
.px1 i { position: absolute; left: -10%; right: -10%; bottom: 0; border-radius: 50% 50% 0 0; }
.px1 .l1 { height: 120px; background: #4c1d95; transform: translateY(calc(var(--s) * .15px)); }
.px1 .l2 { height: 90px; left: 20%; background: #3b0764; transform: translateY(calc(var(--s) * .35px)); }
.px1 .l3 { height: 60px; right: 30%; background: #1e0536; transform: translateY(calc(var(--s) * .6px)); }
.px1 .content { position: relative; padding: 300px 20px 40px; color: #fff; }
.px1 h3 { margin: 0 0 6px; } .px1 p { margin: 0; font-size: 14px; color: #e9d5ff; }
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.

View code
<div class="px2"><span class="s a" style="--d:30" aria-hidden="true"></span><span class="s b" style="--d:16" aria-hidden="true"></span><span class="s c" style="--d:8" aria-hidden="true"></span><h3>Spring collection</h3></div>
.px2 { --x: 0; --y: 0; position: relative; display: grid; place-items: center; width: 300px; max-width: 100%; height: 220px; overflow: hidden; border-radius: 18px; background: #fff7ed; font-family: Inter, system-ui, sans-serif; }
.px2 .s { position: absolute; border-radius: 50%; transform: translate(calc(var(--x) * var(--d) * 1px), calc(var(--y) * var(--d) * 1px)); transition: transform .2s ease-out; }
.px2 .a { width: 70px; height: 70px; top: 20px; left: 30px; background: #fb923c; }
.px2 .b { width: 40px; height: 40px; bottom: 30px; right: 50px; background: #f472b6; }
.px2 .c { width: 120px; height: 120px; top: -30px; right: -20px; background: #fde68a; }
.px2 h3 { position: relative; margin: 0; color: #7c2d12; font-size: 24px; }
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>
.px3 { width: 280px; max-width: 100%; height: 260px; overflow-y: auto; overflow-x: hidden; perspective: 1px; border-radius: 16px; background: #0f172a; font-family: Inter, system-ui, sans-serif; }
.px3:focus-visible { outline: 2px solid #38bdf8; outline-offset: 2px; }
.px3 .grp { position: relative; height: 260px; transform-style: preserve-3d; }
.px3 .back { position: absolute; inset: 0; display: grid; place-items: center; color: #1e3a5f; font-size: 48px; font-weight: 900; transform: translateZ(-1px) scale(2); }
.px3 .front { position: absolute; inset: 0; display: grid; place-items: center; padding: 30px; }
.px3 .front p { margin: 0; padding: 14px; border-radius: 12px; background: rgba(15,23,42,.8); color: #e0f2fe; font-weight: 600; text-align: center; }
.px3 .more { position: relative; height: 260px; padding: 20px; box-sizing: border-box; background: #38bdf8; color: #082f49; font-weight: 700; }
.px3 .more p { margin: 0; }
@media (prefers-reduced-motion: reduce) { .px3 { perspective: none; } .px3 .back { transform: none; } }

04. Fixed Background Window

ParallaxBackground

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>
.px4 { box-sizing: border-box; width: 280px; max-width: 100%; height: 260px; overflow-y: auto; border: 1px solid #e4e7ec; border-radius: 16px; background: #fff; font-family: Inter, system-ui, sans-serif; color: #344054; }
.px4:focus-visible { outline: 3px solid #84adff; outline-offset: 2px; }
.px4 p { margin: 0; padding: 70px 20px; font-size: 14px; }
.px4 .win { display: grid; place-items: center; height: 180px; background: repeating-linear-gradient(45deg, #0ea5e9 0 18px, #0284c7 18px 36px) fixed; }
.px4 b { padding: 8px 14px; border-radius: 8px; background: #fff; color: #0c4a6e; }

05. Headline Slower Than the Page

ParallaxTypography

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>
.px5 { --s: 0; width: 280px; max-width: 100%; height: 260px; overflow-y: auto; border-radius: 16px; background: #18181b; font-family: Inter, system-ui, sans-serif; }
.px5:focus-visible { outline: 2px solid #fde047; outline-offset: 2px; }
.px5 h3 { position: sticky; top: 0; margin: 0; padding: 40px 20px; color: #fde047; font-size: 46px; line-height: 1; transform: translateY(calc(var(--s) * -.5px)); opacity: calc(1 - var(--s) / 200); }
.px5 .body { position: relative; min-height: 330px; margin-top: 60px; padding: 20px; border-radius: 16px 16px 0 0; background: #fafafa; color: #27272a; }
.px5 p { margin: 0; font-weight: 600; }
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.

View code
<a class="px6" href="#sneaker"><span class="sh" aria-hidden="true"></span><span class="pr" aria-hidden="true"></span><span class="bd">New</span><span class="t">Court low sneaker</span></a>
.px6 { position: relative; display: grid; justify-items: center; width: 220px; max-width: 100%; padding: 20px 16px 16px; box-sizing: border-box; border-radius: 18px; background: #eef2ff; text-decoration: none; font-family: Inter, system-ui, sans-serif; }
.px6 .pr { width: 140px; height: 80px; border-radius: 40px 60px 18px 18px; background: linear-gradient(135deg, #4f46e5, #0ea5e9); transition: transform .35s ease; }
.px6 .sh { position: absolute; top: 106px; width: 120px; height: 14px; border-radius: 50%; background: rgba(30,27,75,.25); filter: blur(3px); transition: transform .35s ease, opacity .35s; }
.px6 .bd { position: absolute; top: 14px; right: 14px; padding: 3px 8px; border-radius: 999px; background: #101828; color: #fff; font-size: 12px; font-weight: 700; transition: transform .35s ease; }
.px6 .t { margin-top: 26px; color: #1e1b4b; font-weight: 700; }
.px6:hover .pr, .px6:focus-visible .pr { transform: translateY(-10px) rotate(-6deg); }
.px6:hover .sh, .px6:focus-visible .sh { transform: scaleX(.8); opacity: .6; }
.px6:hover .bd, .px6:focus-visible .bd { transform: translateY(-4px); }
.px6:focus-visible { outline: 3px solid #6366f1; outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .px6 * { transition: none !important; } }

07. Image Drift with view() Timeline

Parallaxanimation-timeline

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.

View code
<div class="px7" tabindex="0" role="region" aria-label="Gallery, scroll"><p>Scroll ↓</p><figure><div style="--g:linear-gradient(#f59e0b,#be123c)"></div></figure><figure><div style="--g:linear-gradient(#22d3ee,#4338ca)"></div></figure><figure><div style="--g:linear-gradient(#a3e635,#047857)"></div></figure></div>
.px7 { width: 260px; max-width: 100%; height: 280px; overflow-y: auto; padding: 14px; box-sizing: border-box; border-radius: 16px; background: #121828; font-family: Inter, system-ui, sans-serif; }
.px7:focus-visible { outline: 2px solid #a5b4fc; outline-offset: 2px; }
.px7 p { height: 160px; margin: 0; color: #94a3b8; font-size: 14px; }
.px7 figure { height: 160px; margin: 0 0 16px; border-radius: 14px; overflow: hidden; }
.px7 figure div { height: 140%; background: var(--g); }
@supports (animation-timeline: view()) {
  .px7 figure div { animation: px7 linear both; animation-timeline: view(); }
  @keyframes px7 { from { transform: translateY(-25%); } to { transform: translateY(0); } }
}
@media (prefers-reduced-motion: reduce) { .px7 figure div { animation: none; } }

About these CSS Parallax Effects

Depth from different speeds

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.