css

CSS-only parallax with animation-timeline: scroll()

No JS needed for parallax anymore. The animation-timeline: scroll() property lets you drive a CSS animation by scroll position instead of time. Define a regular @keyframes animation with translate3d, set animation-timeline: scroll(root), and each layer moves at its own speed based on a CSS custom property. Stack multiple layers with different --parallax-y values and you've got depth.

@keyframes parallax {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(0, var(--parallax-y), 0);
  }
}

.scene {
  position: relative;
}

.parallax-layer {
  --parallax-y: -20vh;
  position: absolute;
  inset: 0;
  animation: parallax linear both;
  animation-timeline: scroll(root);
}

/* Different speeds per layer via custom property */
.bg-layer  { --parallax-y: -5vh; }
.fg-layer  { --parallax-y: -10vh; }

/* Usage:
<div class="scene">
  <div class="parallax-layer bg-layer"></div>
  <div class="parallax-layer fg-layer"></div>
  <div class="content">Your content here</div>
</div>
*/
css
lubosmato