Scroll✨ Premium

Parallax

A gradient background sliding from +60 to −60 px over the 520 px travel of a 280 px box (animation-timeline: scroll()), and three backdrop-filter cards that rise 30 px and go from 0 to 1 opacity during their first 33 px inside the box (view(), entry → entry 50%). Two CSS timelines, zero JavaScript, 3.1 KB.

CSSParallaxScroll

Updated

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Scroll has 70 effects, including 12 free. Explore the category →

3 usage examples

Airport parking rates — public page on a runway background — Parallax example 1

① Airport parking rates — public page on a runway background

When“Parking” page: on a gradient background that drifts slowly, three cards (short stay, long stay, drop-off) with price and maximum stay, revealed one by one.
WhyThe cards must stay readable on the moving background: the code's backdrop-filter seats them on the gradient sliding behind, and each appears through view() — fx-0592 has no content block, its layers are purely decorative.
Settings316 px box under a 44 px bar, 760 px stage (444 travel). A night runway set on .sb-parallax-bg — 175° gradient #07172e → #0b4a63, centre line and edge lights as repeating-linear-gradient — hence in parallax with it; the word PARALLAX becomes the runway's “27” (96 px, white at 16%). A 262 px hero before the cards (99 px, rgba(2,10,24,.42) and a border), entry entry 50% range kept: measured, cards revealed between −10 and 40, 107 and 157, 224 and 274 px of scrolling. The auto-scroll (135 px/s, until the first gesture) is a demo device.
Strata of a cliff, top to bottom — a geopark's field app — Parallax example 2

② Strata of a cliff, top to bottom — a geopark's field app

When“The cliff” screen: the layered wall (cap, chalk, marl, limestone) slides behind, and three cards — one per bed of rock, with its age and fossils — reveal as the visitor scrolls down, from the top to the foot.
WhyScrolling down the screen is climbing down the wall: the beds of rock slide faster than the labels (120 px more over the 418 px travel), the cliff reads behind them, and each stratum arrives through view() as you reach its level — fx-0573 pins its night scene and slides five planes across it, but nothing there descends with the reader or reveals itself.
Settings236 px phone, 282 px box under status bar and header, 700 px stage (418 travel). The wall is set on .sb-parallax-bg — 180° gradient from the dark cap #2b2f26 to the chalk #a29a86, the marl #3a4147 and the limestone #8a6738, 24 px beds as a repeating-linear-gradient — hence in parallax with it; “JURASSIC” watermark (26 px, white at 14%) in place of the word. Intro and tide banner before the cards (83 and 44 px), 119 px cards in rgba(12,10,9,.5) with a tag and an age; measured: card 2 revealed between 50 and 110 px, card 3 between 183 and 243. Auto-scroll at 120 px/s until the first gesture.
Sorting instructions — digital panel at the entrance of a recycling centre — Parallax example 3

③ Sorting instructions — digital panel at the entrance of a recycling centre

WhenTouch screen: a sliding green-blue gradient background, and three cards (glass, cardboard, bulky items) with the skip to head for, revealed as the visitor scrolls.
WhyOn the screen, the instructions must read as posted in front of the site, not printed into it: the hatching and the ♻︎ slide faster than the cards (120 px more over the 348 px travel), the backdrop-filter blurs whatever passes behind, and each skip arrives through view() as the visitor scrolls it in — fx-0535 reveals its blocks the same way, but on a still background: nothing there separates the instruction from the backdrop.
Settings48 px bar, 312 px box, 660 px stage (348 travel). 165° gradient #064e3b → #0f766e → #0e7490 hatched at 4%, a 150 px ♻︎ glyph at 12% as a watermark. 150 px intro with the touch instruction, 81 to 99 px cards with the skip number in a 46 px square, 13 to 19 px text; measured: card 2 revealed between 11 and 51 px, card 3 between 116 and 166. Auto-scroll at 100 px/s until the first gesture; on the kiosk, the finger does it.

How it works

The sold HTML: the .demo-preview frame (centered flex, min-height: 300px, #0a0a0f background, white text, sans-serif), a .sdc-scroll-container box of 100% × 280px with overflow-y: auto and scroll-behavior: smooth, an 800 px stage .sb-parallax-content in position: relative; overflow: clip, and two layers inside it: .sb-parallax-bg, absolute with inset: -60px 0 (920 px), the 135° gradient #6366f1 → #d946ef and the word PARALLAX centered (32 px, weight 800); .sb-parallax-items (z-index: 2, padding: 200px 20px 20px, flex column, gap: 100px) with three .sb-parallax-item — padding: 16px, 12 px radius, rgba(0,0,0,.3), backdrop-filter: blur(8px), a 13.6 px h4, an 11.5 px p in white at 70%. Measured: 66 px cards at 200, 366 and 532 px from the top of the stage, travel 800 − 280 = 520 px. The hint .sdc-scroll-hint “Scrollez ↓” (absolute, 8 px from the bottom of the frame, 10.4 px, white at 30%) pulses between .3 and .7 every 2 s. Empty JS field, no site variable, no external resource, no console error.

Two animations, two clocks. The background carries animation-name: sbParallaxBg (translateY(60px) → translateY(-60px), linear) with animation-timeline: scroll(): its progress is the scroll position of the nearest scroll container, here the 280 px box, and animation-range: normal spreads the 120 px over the whole travel. Measured in 130 px steps in Chromium 151: 60, 30, 0, −30, −60 px; the layer's 60 px overhang keeps the box covered from end to end. Each card carries animation-name: sbFadeUp (to opacity: 1; transform: translateY(0)) with animation-timeline: view() and animation-range: entry entry 50%: the clock is the card's passage through the box's window, from “its top edge touches the bottom of the box” to “half of it is in”, i.e. 33 px of scrolling. animation-fill-mode: both holds it at opacity: 0; translateY(30px) before the range and at 1 / 0 after. Measured: card 1 is already in at rest (its range falls between −80 and −47 px), card 2 reveals between 86 and 119 px (opacity 0 at 0, 1 at 130), card 3 between 252 and 285 px (0.24 and translateY(22.7px) at 260, 1 at 390).

The line that holds it all together is overflow: clip on the stage. With overflow: hidden, the stage itself becomes a scroll container — with no travel, its 800 px being full — and that is the one scroll() and view() pick: measured, inactive timelines, transform: none on the background from 0 to 520 px and cards frozen at opacity 1 from rest. clip crops the same way without creating a container: both clocks climb up to the box. The direction comes from the keyframes: the background travels 120 px further up than the cards over the course, so it runs 1.23 times faster than they do — the opposite of classic parallax, where the background lags. The word PARALLAX crosses the box between 115 and 405 px of scrolling and passes behind card 2 around 260 px, blurred by the backdrop-filter. No id, no script: several copies coexist on one page, each tied to its box.

Accessibility

  • prefers-reduced-motion not in the code: measured under emulation in Chromium, nothing changes (background 60 → −60 px, cards fading in, hint running, scroll-behavior: smooth). A background moving at a different speed from the text is the motion WCAG 2.3.3 targets. Add @media (prefers-reduced-motion: reduce) { .sb-parallax-bg, .sb-parallax-item { animation: none } .sb-parallax-item { opacity: 1; transform: none } .sdc-scroll-hint { animation: none } .sdc-scroll-container { scroll-behavior: auto } }. Nothing is hidden for all that: a card is at opacity 0 only below the bottom edge of the box and during its first 33 px of entry.
  • Keyboard: measured in Chromium 151, Tab focuses the box without a tabindex, Arrow Down moves 40 px (background at 50.8 px), Page Down 285 px (all three cards revealed), End goes to 520; Firefox 153 also focuses the box on Tab. For Safari, add tabindex="0", a visible :focus-visible and an aria-label. With a finger, the gesture must start inside the box; overscroll-behavior: contain keeps the page from being dragged along at the end of the travel.
  • Contrast (computed at both ends of the gradient, card = 30% black on top): white 13.6 px headings at 7.7:1 on the blue and 6.3:1 on the pink; paragraph in white at 70% (11.5 px) at 4.7:1 on the blue but 3.9:1 on the pink, below 4.5:1 — raise it to 85% (5.0:1) or darken the card to rgba(0,0,0,.45) (5.1:1). The word PARALLAX (32 px, weight 800, 3:1 threshold) measures 4.5:1 on the blue, 3.5:1 on the pink. The hint at 30% swings between 1.2:1 and 1.8:1: decorative, set aria-hidden="true".
  • Screen readers and structure: three divs with one h4 each — a level 4 with no h2/h3 above breaks the page outline, use the level that follows your current heading. Opacity 0 removes nothing from the accessibility tree: all three cards are read whatever the scroll position. The word PARALLAX is read as is (decorative: aria-hidden="true") and “Scrollez ↓” is hard-coded in French. Catalog leftover: an inline style="font-family: Inter, …" on each h4. No JavaScript, so nothing changes without it; without animation-timeline, everything shows flat (see compatibility).

Browser compatibility

CSS only: animation-timeline: scroll() and view(), animation-range (Scroll-driven Animations Level 1), overflow: clip, backdrop-filter, inset, a gradient, @keyframes. Zero JavaScript, zero dependencies. Scroll timelines exist in Chrome and Edge 115+, Safari and iOS 26 (measured in WebKit 26.5: 60 → 0 → −60 px, card 3 at 0.24 at 260 px, same as Chromium); Firefox: no version. Measured in Firefox 153: CSS.supports('animation-timeline: scroll()') returns false, the declaration is dropped and both animations fall back to 0 s — the background stays at transform: none (fill-mode: none), the cards take their last keyframe (opacity: 1, translateY(0), fill-mode: both): everything is visible, flat, the box scrolls normally, the hint pulses. No @supports fallback in the code: nothing to catch, the final state of the keyframes is the readable state.

Chrome 115+✓ Full
Edge 115+✓ Full
Safari 26+✓ Full (measured in WebKit 26.5)
Firefox✓ No version: static background, three cards visible flat (measured in Firefox 153)
Mobile iOS 26+✓ Full (touch scrolling of the box)
Android Chrome 115+✓ Full

Without animation-timeline (Firefox, Safari and iOS before 26, Chrome before 115): still background, cards at opacity 1 from load, ordinary scrolling — only the motion is missing. Without overflow: clip (Safari before 16): the layer overhangs the stage by 60 px at the bottom, the box scrolls 580 px instead of 520, nothing else. Without backdrop-filter: 30% black panels with no blur, text readable.

The code

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

index.html — structure
<div class="demo-preview">
  <div class="sdc-scroll-container">
    <div class="sb-parallax-content">
      <div class="sb-parallax-bg">
        <div class="sb-parallax-text">…</div>
      </div>
      <div class="sb-parallax-items">
        <div class="sb-parallax-item">
          <h4>…</h4>
          <p>…</p>
        </div>
        <div class="sb-parallax-item">
          <h4>…</h4>
          <p>…</p>
        </div>
        <div class="sb-parallax-item">
          <h4>…</h4>
          <p>…</p>
        </div>
      </div>
    </div>
  </div>
  <span class="sdc-scroll-hint">…</span>
</div>
Unlock the full code — €9.90/mo excl. tax

The full HTML + CSS + JS of Parallax, ready to paste — plus all 811 effects. Or €299 once, lifetime access.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Background amplitude (CSS — @keyframes sbParallaxBg and .sb-parallax-bg { inset: -60px 0 }) 60 → −60 px (120 px over a 520 px travel) The layer's overhang follows the amplitude: ±100 px require inset: -100px 0, otherwise the frame's background shows as a 40 px band at the top at rest and at the bottom at the end of the travel. At 0 → 0, only the cards animate.
Parallax direction (CSS — @keyframes sbParallaxBg) the background runs 1.23 times faster than the cards Swap the two values (translateY(-60px) → translateY(60px)) so the background lags behind the content (0.77 times its speed), the classic reading of depth; the 60 px overhang then serves the other way.
Travel (CSS — .sb-parallax-content { height: 800px }, .sdc-scroll-container { height: 280px }) 520 px animation-range: normal spreads the background's 120 px over the whole travel: a 1,500 px stage (1,220 of travel) slows the background accordingly. The cards are set by their position (padding-top: 200px, gap: 100px): less than 280 px from the top, a card is visible at rest, like the first one.
Reveal range (CSS — .sb-parallax-item { animation-range: entry entry 50% }) entry → entry 50% (33 px for a 66 px card) entry 0% entry 100% spreads the fade over the card's full height; entry 20% entry 80% lets it cross the edge before starting; cover 0% cover 30% anchors the end at 30% of its passage. Since the range is a percentage of the card, a taller card lengthens it accordingly.
Cards' starting state (CSS — .sb-parallax-item { opacity: 0; transform: translateY(30px) }) 30 px lower, invisible The sbFadeUp keyframe only has a to: the start is the card's base style. translateY(60px) scale(.96) for a stronger entrance, opacity: .4 for a card readable before its entry, or remove the transform for a pure fade.
Card material (CSS — background: rgba(0,0,0,.3), backdrop-filter: blur(8px)) black at 30%, 8 px blur The blur reads whatever passes behind (the gradient, the word PARALLAX): on a photo, blur(14px); for a light theme, rgba(255,255,255,.18) with dark text. Darkening to .45 brings the 70% paragraph above 4.5:1 across the whole gradient.
Gradient and word (CSS — .sb-parallax-bg { background }, .sb-parallax-text) 135° #6366f1 → #d946ef, PARALLAX 32 px Everything set on .sb-parallax-bg slides with it, multiple backgrounds included (lines as repeating-linear-gradient, a radial glow): the most visible way to make the parallax read. The word becomes a watermark by lowering its color (rgba(255,255,255,.15)); give it aria-hidden="true".
Hint and easing (CSS — .sdc-scroll-hint, .sdc-scroll-container { scroll-behavior: smooth }) “Scrollez ↓” pulsing 2 s, smooth scrolling The hint is a catalog leftover: hard-coded French, absolute relative to .demo-preview (without that frame it drops to the bottom of the page) — delete the span, the sdcHintPulse keyframe goes with it. smooth only eases programmatic scrolls (anchors, scrollTo), not the wheel.

FAQ

Three causes, in order. The browser: Firefox has animation-timeline in no version, Chrome since 115, Safari since 26 — elsewhere the effect shows flat, still background and visible cards. The stage: if .sb-parallax-content goes back to overflow: hidden, or if an element with overflow: hidden or auto slips in between the layers and the box, that full block becomes the container scroll() and view() pick, with no travel: measured, transform: none and cards frozen at opacity 1. Keep overflow: clip. The box, finally, must stay shorter than its content, otherwise nothing scrolls. A wrapper in overflow: hidden around the frame does no harm: the box is nearer.
Yes. Remove the box (or its height and overflow-y) and the .demo-preview frame: the nearest container becomes the page, scroll() follows its full height and view() the browser window — the cards reveal as they enter from the bottom of the screen. Two precautions: an ancestor in overflow: hidden (a horizontal-overflow-proof .wrapper) would capture both timelines — switch it to overflow: clip, or write animation-timeline: scroll(root) for the background; and the background layer, absolute inside an 800 px stage, must take the height of the section it dresses, or go position: fixed.
fx-0592 stacks five absolute layers in a 900 px stage, all driven by scroll() with their own keyframes — a glow in scale(1) → scale(1.3), shapes and rings rising 60 to 100 px while rotating a few degrees, dots, a title going from .7 to 1 opacity. Five speeds, no view(), nothing to read: its layers are decorative, the title is its only text. fx-0538 has a single background layer but carries a content column: three backdrop-filter cards, each revealed by view() as it enters the box, independently of the background. fx-0592 for a section backdrop; fx-0538 as soon as cards — rates, plans, instructions — must stay readable over a moving background.