CSS-Native Parallax Effect

Hacker News Top Tools

Summary

A CSS-native parallax effect using scroll-driven animation timelines, providing a performant and simple utility class with no JavaScript.

No content available
Original Article
View Cached Full Text

Cached at: 06/02/26, 03:33 PM

# Utils | CSS-native parallax effect Source: [https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/](https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/) jun 02, 2026 Parallax effects have a long history, and while there are countless ways and libraries to achieve them, a new CSS\-native way was recently made possible with[CSS Scroll\-driven animation timelines](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timelines)\. The usual recipe was a scroll event listener in JavaScript, recalculating positions on every frame and nudging an element up and down\. **Scroll\-driven animations**handle all of that with CSS\. Handling parallax animations with CSS has a few advantages: performance should be better as it runs it off the main thread, but my favorite part is the simplicity with which the whole thing becomes a small block of declarative styles, that can be applied with a single utility class\. Here is the full code for the class: ``` .parallax { view-timeline-name: --parallax-tl; view-timeline-axis: block; overflow: hidden; & > * { scale: calc(1 + var(--parallax-offset, 20) * 2 / 100); animation: parallax auto linear both; animation-timeline: --parallax-tl; animation-range: cover; will-change: translate; } } @keyframes parallax { from { translate: 0 calc(var(--parallax-offset, 20) * -1%); } to { translate: 0 calc(var(--parallax-offset, 20) * 1%); } } ``` ## [\#](https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/#the-timeline)The timeline The trick is`view\-timeline\-name`\. It creates a**view progress timeline**, a timeline whose progress is measured by how far the`\.parallax`element has travelled through the scrollport\. It reads 0% the moment the element starts to enter the viewport and 100% once it has fully left\.`view\-timeline\-axis: block`tells it to track movement along the block axis, which is the vertical one in a normal writing mode\. On the child,`animation\-timeline: \-\-parallax\-tl`swaps the animation's clock from time to that timeline\. From there the rest of the`animation`line falls into place: - `auto`for duration, because the duration now comes from the timeline rather than a number of seconds - `linear`so scroll progress maps straight onto movement, - `both`to hold the start and end frames outside the active range > ⚠️ Note: The animation\-timeline longhand property is not part of the animation shorthand and must be declared separately\. Furthermore, animation\-timeline must be declared after the animation shorthand as the shorthand will reset non\-included longhands to their initial value\. The keyframes do the actual work\. With the default offset, the child slides from`translate: 0 \-20%`to`translate: 0 20%`as you scroll past it\. Because it moves at a different rate to the container around it, you get that sense of depth\. ## [\#](https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/#scaling-to-avoid-empty-spots)Scaling to avoid empty spots The child translates by up to the offset percentage of its own height in each direction, so if the child were exactly the same size as its container, shifting it up or down would expose a strip of empty space\. The child needs to be scaled up in order to have a margin to move into\. It needs the offset's worth of extra height above and below, so twice the offset overall: ``` scale: calc(1 + var(--parallax-offset, 20) * 2 / 100); ``` With the default offset of 20, the child is rendered at 140% of its size, the surplus is clipped by`overflow: hidden`on the container, and there is always enough content to cover the box no matter where in the ±20% travel it sits\. The neat part is that both the translate and the scale read the same`\-\-parallax\-offset`variable\. Turn the offset up for a stronger effect and the scale grows to match it, so the cover stays correct on its own\. One value to tune, and the gaps never come back: ``` <div class="parallax" style="--parallax-offset: 30;"> <img src="…" /> </div> ``` `will\-change: translate`is the last piece, a hint that this element's`translate`is about to change so the browser can promote it to its own layer ahead of time\. ## [\#](https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/#motion-preferences)Motion preferences Parallax is movement tied to scrolling, and some people would rather not have it\. It's good practice to respect that by disabling the animation for anyone with`prefers\-reduced\-motion: reduce`\. In this case, we can just turn off the animation and scale: ``` @media (prefers-reduced-motion: reduce) { .parallax > * { animation: none; scale: 1; } } ``` ### [\#](https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/#resources)Resources - [Animate elements on scroll with Scroll\-driven animations](https://developer.chrome.com/docs/css-ui/scroll-driven-animations) - [Scroll\-driven animation timelines](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timelines) - [scroll\-timeline CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/scroll-timeline)

Similar Articles

@VincentLogic: In the past, when doing frontend work, I used to either hunt around for GIFs or write CSS until my head ached just to create a loading animation. Recently I came across this open-source library math-curve-loaders, which generates animations purely using mathematical formulas. I took a look — rose curves, Lissajous curves, and other mathematical figures produce extremely elegant animations. Pure HT…

X AI KOLs Timeline

Introduces an open-source frontend library called math-curve-loaders that utilizes mathematical formulas (such as rose curves and Lissajous curves) to generate elegant loading animations. It is implemented purely with HTML+CSS, has zero dependencies, and comes with a visual debugging panel that allows real-time parameter adjustments and one-click code copying.

Show HN: A CSS 3D Engine (no WebGL)

Hacker News Top

PolyCSS is a CSS polygon mesh library that renders 3D models as real HTML elements using CSS matrix3d, supporting OBJ/MTL, GLB, and VOX formats with React, Vue, or vanilla JS.

Dithering with CSS

Hacker News Top

The article demonstrates how to apply dithering effects to images using CSS filters and SVG feTurbulence to maintain a consistent aesthetic.

Cross-Document View Transitions: The Gotchas Nobody Mentions

Lobsters Hottest

A technical article explaining the current implementation of cross-document view transitions in CSS, covering deprecated meta tags, common pitfalls like the 4-second timeout and aspect ratio warping, and proper opt-in methods.

HTML-in-Canvas Demos

Hacker News Top

A collection of CSS and Web UI demos from the Chrome DevRel team, including HTML-in-Canvas demos.