SPB Git

spb/svgarden Public

SVGarden — searchable bank of 74 self-contained SVG+CSS animation snippets (svgarden.dev)

HTML 79.2% Astro 10.3% JavaScript 6% CSS 3.7% Shell 0.8%
4.1 KB · 98 lines html
Raw Blame History
1<!--2  ============================================================3  SVGarden — https://www.svgarden.dev4  Author : Simon-Pierre Boucher5  Contact: contact@spboucher.ai6  File   : snippets/scroll/scroll-parallax-layers.html7  Desc   : Layered SVG mountain scene with scroll-speed parallax depth8  ============================================================9-->10<!--svgarden11title: Scroll parallax layers12slug: scroll-parallax-layers13category: scroll14tags: [scroll, parallax, layers, scene]15difficulty: advanced16techniques: ["animation-timeline: scroll()", "position: sticky", translate-property, "@supports", calc-depth]17how_it_works: >18  The scene is pinned with position: sticky while its parent track is three19  times taller, so scrolling the box scrubs a timeline without the scene ever20  leaving view. All three mountain layers share one translate keyframe, but21  each sets its own --sg-shift (a calc() fraction of the depth variable), so22  the near layer rises five times farther than the far one — unequal travel23  for equal scroll is the entire parallax illusion. Browsers without24  scroll-driven animations skip the @supports block and show the scene as a25  static composition.26support: "Scroll-driven animations need Chrome/Edge 115+; other browsers show the layered scene without parallax motion."27customizable:28  - { var: "--sg-color", label: "Scene color", type: color, default: "#7F77DD" }29  - { var: "--sg-size",  label: "Box height",  type: range, min: 180, max: 400, default: 260, unit: px }30  - { var: "--sg-depth", label: "Depth",       type: range, min: 10, max: 80, default: 40 }31created: 2026-08-1032-->33<div class="sg-scroll-parallax-layers" style="--sg-color:#7F77DD; --sg-size:260px; --sg-depth:40;">34  <div class="sg-scroll-parallax-layers-track">35    <div class="sg-scroll-parallax-layers-sticky">36      <svg viewBox="0 0 200 120" preserveAspectRatio="xMidYMax slice" aria-hidden="true" focusable="false">37        <circle class="sg-scroll-parallax-layers-sun" cx="150" cy="30" r="12" />38        <path class="sg-scroll-parallax-layers-l1"39          d="M0 74 L28 42 L52 70 L84 40 L118 72 L148 46 L176 70 L200 56 V140 H0 Z" />40        <path class="sg-scroll-parallax-layers-l2"41          d="M0 90 C 30 68, 62 98, 102 82 C 142 66, 172 96, 200 84 V140 H0 Z" />42        <path class="sg-scroll-parallax-layers-l3"43          d="M0 104 C 40 88, 82 114, 124 100 C 162 88, 184 108, 200 102 V140 H0 Z" />44      </svg>45      <span class="sg-scroll-parallax-layers-hint">scroll ↓</span>46    </div>47  </div>48</div>49<style>50  .sg-scroll-parallax-layers {51    width: 100%;52    min-width: 220px;53    height: var(--sg-size);54    overflow-y: scroll;55    border: 1px solid rgba(128, 128, 128, 0.3);56    border-radius: 10px;57  }58  .sg-scroll-parallax-layers-track {59    height: calc(var(--sg-size) * 3);60  }61  .sg-scroll-parallax-layers-sticky {62    position: sticky;63    top: 0;64    height: var(--sg-size);65    /* no overflow:hidden here — it would become the nearest scroll container66       and scroll(nearest) would bind to a box that never scrolls */67  }68  .sg-scroll-parallax-layers-sticky svg {69    display: block;70    width: 100%;71    height: 100%;72  }73  .sg-scroll-parallax-layers-hint {74    position: absolute;75    right: 12px;76    top: 8px;77    font-size: 12px;78    opacity: 0.6;79  }80  .sg-scroll-parallax-layers-sun { fill: var(--sg-color); opacity: 0.4; }81  .sg-scroll-parallax-layers-l1 { fill: var(--sg-color); opacity: 0.25; --sg-shift: calc(var(--sg-depth) * -0.2px); }82  .sg-scroll-parallax-layers-l2 { fill: var(--sg-color); opacity: 0.5;  --sg-shift: calc(var(--sg-depth) * -0.55px); }83  .sg-scroll-parallax-layers-l3 { fill: var(--sg-color); opacity: 0.9;  --sg-shift: calc(var(--sg-depth) * -1px); }84  @supports (animation-timeline: scroll()) {85    .sg-scroll-parallax-layers-l1,86    .sg-scroll-parallax-layers-l2,87    .sg-scroll-parallax-layers-l3 {88      animation: sg-scroll-parallax-layers-rise linear both;89      animation-duration: auto;90      animation-timeline: scroll(nearest);91    }92  }93  @keyframes sg-scroll-parallax-layers-rise {94    from { translate: 0 0; }95    to   { translate: 0 var(--sg-shift); }96  }97</style>98