Skip to content

Gallery / scroll / Scroll parallax layers

Scroll parallax layers

Layered SVG mountain scene with scroll-speed parallax depth

scroll advanced scrollparallaxlayersscene
Live preview

⚠ Browser support Scroll-driven animations need Chrome/Edge 115+; other browsers show the layered scene without parallax motion.

Techniques: animation-timeline: scroll() · position: sticky · translate-property · @supports · calc-depth

Customizeupdates preview, code & clipboard
#7F77DD
260px
40
Code snippets/scroll/scroll-parallax-layers.html
<!--
  ============================================================
  SVGarden — https://www.svgarden.dev
  Author : Simon-Pierre Boucher
  Contact: contact@spboucher.ai
  File   : snippets/scroll/scroll-parallax-layers.html
  Desc   : Layered SVG mountain scene with scroll-speed parallax depth
  ============================================================
-->
<div class="sg-scroll-parallax-layers" style="--sg-color:#7F77DD; --sg-size:260px; --sg-depth:40;">
  <div class="sg-scroll-parallax-layers-track">
    <div class="sg-scroll-parallax-layers-sticky">
      <svg viewBox="0 0 200 120" preserveAspectRatio="xMidYMax slice" aria-hidden="true" focusable="false">
        <circle class="sg-scroll-parallax-layers-sun" cx="150" cy="30" r="12" />
        <path class="sg-scroll-parallax-layers-l1"
          d="M0 74 L28 42 L52 70 L84 40 L118 72 L148 46 L176 70 L200 56 V140 H0 Z" />
        <path class="sg-scroll-parallax-layers-l2"
          d="M0 90 C 30 68, 62 98, 102 82 C 142 66, 172 96, 200 84 V140 H0 Z" />
        <path class="sg-scroll-parallax-layers-l3"
          d="M0 104 C 40 88, 82 114, 124 100 C 162 88, 184 108, 200 102 V140 H0 Z" />
      </svg>
      <span class="sg-scroll-parallax-layers-hint">scroll ↓</span>
    </div>
  </div>
</div>
<style>
  .sg-scroll-parallax-layers {
    width: 100%;
    min-width: 220px;
    height: var(--sg-size);
    overflow-y: scroll;
    border: 1px solid rgba(128, 128, 128, 0.3);
    border-radius: 10px;
  }
  .sg-scroll-parallax-layers-track {
    height: calc(var(--sg-size) * 3);
  }
  .sg-scroll-parallax-layers-sticky {
    position: sticky;
    top: 0;
    height: var(--sg-size);
    /* no overflow:hidden here — it would become the nearest scroll container
       and scroll(nearest) would bind to a box that never scrolls */
  }
  .sg-scroll-parallax-layers-sticky svg {
    display: block;
    width: 100%;
    height: 100%;
  }
  .sg-scroll-parallax-layers-hint {
    position: absolute;
    right: 12px;
    top: 8px;
    font-size: 12px;
    opacity: 0.6;
  }
  .sg-scroll-parallax-layers-sun { fill: var(--sg-color); opacity: 0.4; }
  .sg-scroll-parallax-layers-l1 { fill: var(--sg-color); opacity: 0.25; --sg-shift: calc(var(--sg-depth) * -0.2px); }
  .sg-scroll-parallax-layers-l2 { fill: var(--sg-color); opacity: 0.5;  --sg-shift: calc(var(--sg-depth) * -0.55px); }
  .sg-scroll-parallax-layers-l3 { fill: var(--sg-color); opacity: 0.9;  --sg-shift: calc(var(--sg-depth) * -1px); }
  @supports (animation-timeline: scroll()) {
    .sg-scroll-parallax-layers-l1,
    .sg-scroll-parallax-layers-l2,
    .sg-scroll-parallax-layers-l3 {
      animation: sg-scroll-parallax-layers-rise linear both;
      animation-duration: auto;
      animation-timeline: scroll(nearest);
    }
  }
  @keyframes sg-scroll-parallax-layers-rise {
    from { translate: 0 0; }
    to   { translate: 0 var(--sg-shift); }
  }
</style>

More scroll