Scroll parallax layers
Layered SVG mountain scene with scroll-speed parallax depth
⚠ 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
<!--
============================================================
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>