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%
1<!--2 ============================================================3 SVGarden — https://www.svgarden.dev4 Author : Simon-Pierre Boucher5 Contact: contact@spboucher.ai6 File : snippets/scroll/scroll-reveal-mask.html7 Desc : Items unclip themselves as they enter the scroll viewport8 ============================================================9-->10<!--svgarden11title: Scroll reveal mask12slug: scroll-reveal-mask13category: scroll14tags: [scroll, reveal, clip-path, view-timeline]15difficulty: advanced16techniques: ["animation-timeline: view()", animation-range, "clip-path: inset()", "@supports"]17how_it_works: >18 Where scroll() tracks how far a container has scrolled, view() tracks how far19 a specific element has traveled across the visible viewport of that20 container — every item below owns its own timeline. animation-range: entry21 0% cover 40% confines the clip-path animation to the moment the item enters22 until it is 40% across, so each row wipes open exactly as you meet it and23 plays in reverse when you scroll back. The inset() clip is animatable24 because only its numbers change. Without scroll-driven animation support the25 @supports block is skipped and the rows are simply visible.26support: "view() timelines need Chrome/Edge 115+; other browsers show all rows unmasked."27customizable:28 - { var: "--sg-color", label: "Accent", type: color, default: "#7F77DD" }29 - { var: "--sg-size", label: "Box height", type: range, min: 180, max: 400, default: 260, unit: px }30created: 2026-08-1031-->32<div class="sg-scroll-reveal-mask" style="--sg-color:#7F77DD; --sg-size:260px;">33 <p class="sg-scroll-reveal-mask-hint">scroll ↓ to reveal</p>34 <div class="sg-scroll-reveal-mask-item">35 <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9" /><path d="M8 12.5 L11 15 L16 9" /></svg>36 <span class="sg-scroll-reveal-mask-bar" style="width: 72%;"></span>37 </div>38 <div class="sg-scroll-reveal-mask-item">39 <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9" /><path d="M8 12.5 L11 15 L16 9" /></svg>40 <span class="sg-scroll-reveal-mask-bar" style="width: 55%;"></span>41 </div>42 <div class="sg-scroll-reveal-mask-item">43 <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9" /><path d="M8 12.5 L11 15 L16 9" /></svg>44 <span class="sg-scroll-reveal-mask-bar" style="width: 80%;"></span>45 </div>46 <div class="sg-scroll-reveal-mask-item">47 <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9" /><path d="M8 12.5 L11 15 L16 9" /></svg>48 <span class="sg-scroll-reveal-mask-bar" style="width: 63%;"></span>49 </div>50</div>51<style>52 .sg-scroll-reveal-mask {53 width: 100%;54 min-width: 220px;55 height: var(--sg-size);56 overflow-y: scroll;57 border: 1px solid rgba(128, 128, 128, 0.3);58 border-radius: 10px;59 padding: 0 14px;60 }61 .sg-scroll-reveal-mask-hint {62 margin: 12px 2px calc(var(--sg-size) * 0.55);63 font-size: 13px;64 opacity: 0.6;65 }66 .sg-scroll-reveal-mask-item {67 display: flex;68 align-items: center;69 gap: 12px;70 padding: 14px;71 margin-bottom: calc(var(--sg-size) * 0.5);72 border: 1px solid rgba(128, 128, 128, 0.3);73 border-radius: 10px;74 }75 .sg-scroll-reveal-mask-item:last-of-type {76 margin-bottom: calc(var(--sg-size) * 0.35);77 }78 .sg-scroll-reveal-mask-item svg {79 width: 26px;80 height: 26px;81 flex: none;82 fill: none;83 stroke: var(--sg-color);84 stroke-width: 2;85 stroke-linecap: round;86 stroke-linejoin: round;87 }88 .sg-scroll-reveal-mask-bar {89 height: 8px;90 border-radius: 4px;91 background: var(--sg-color);92 opacity: 0.55;93 }94 @supports (animation-timeline: view()) {95 .sg-scroll-reveal-mask-item {96 animation: sg-scroll-reveal-mask-wipe linear both;97 animation-duration: auto;98 animation-timeline: view();99 animation-range: entry 0% cover 40%;100 }101 }102 @keyframes sg-scroll-reveal-mask-wipe {103 from { clip-path: inset(0 100% 0 0 round 10px); opacity: 0.2; }104 to { clip-path: inset(0 0 0 0 round 10px); opacity: 1; }105 }106</style>107