Scroll-Linked SVG Path Draw — Native CSS view-timeline, No GSAP

SVG Path Draw (view-timeline, No GSAP) · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Classic stroke-dasharray / stroke-dashoffset draw, timed by native animation-timeline: view()
A second dot element rides the exact same named timeline via offset-path + offset-distance
No GSAP, no ScrollTrigger, no scrub configuration — zero animation library dependency
contain-based animation-range ties progress to the SVG genuinely being in view
Gradient stroke via a standard SVG <linearGradient>
Bidirectional — the line retracts correctly when scrolling back up
@supports fallback shows the fully-drawn line and dot rather than an invisible stroke
Runs entirely on the compositor — no per-frame JavaScript cost

About this UI Snippet

Scroll-Linked SVG Path Draw — animation-timeline: view() Instead of GSAP ScrollTrigger

Screenshot of the SVG Path Draw (view-timeline, No GSAP) snippet rendered live

The scroll-linked "line draws itself in" effect — an SVG stroke that appears to trace its own path as the reader scrolls past it — is one of the most recognizable scroll animations on the web, almost always built with GSAP's DrawSVGPlugin and ScrollTrigger (see Scroll SVG Path Draw for that approach). This snippet reproduces the identical stroke-drawing mechanic using nothing but native CSS: a view-timeline binding stroke-dashoffset directly to the SVG's own scroll position, with no animation library and no JavaScript computing scroll progress.

The classic stroke-dasharray trick, now scroll-timed by CSS

stroke-dasharray is set to a value at least as long as the path itself (1400, comfortably longer than this particular route), and stroke-dashoffset starts at that same value, which hides the entire stroke behind an equally long gap. Animating stroke-dashoffset down to 0 reveals the stroke progressively from start to end — this half of the trick is identical to the GSAP version. What's different is what drives the animation's progress: instead of ScrollTrigger's scrub option computing a 0–1 value from scroll position on every frame, animation-timeline: --route-in — a named view timeline declared on the <svg> element itself — supplies that progress value natively.

A second element riding the exact same timeline

A small dot uses CSS offset-path (set to the identical path data) combined with offset-distance animated from 0% to 100%, bound to the same --route-in timeline via animation-range: contain 0% contain 100%. Because both the stroke draw and the dot's movement reference the same named timeline and the same range, they stay perfectly in sync with no manual coordination — both are simply reading the same scroll-derived progress value.

contain instead of cover, and why it matters for a tall SVG

animation-range: contain 0% contain 100% uses the contain keyword so the draw only progresses while the entire SVG is contained within the viewport — for an SVG taller than the viewport, this differs meaningfully from cover, which would start progress the instant the top edge appears even while most of the graphic is still off-screen below. contain here effectively requires the SVG to fit inside the viewport at all, which works well for a graphic sized to roughly viewport height, as this one is; a route taller than the viewport would need a cover-based range or a different sizing approach instead.

Comparing to the GSAP version

The GSAP Scroll SVG Path Draw snippet gives finer control — precise scrub smoothing, pinning, easing curves, and cross-browser consistency today, at the cost of a ~40KB dependency and a JS runtime cost per scroll frame. This CSS-only version has zero dependency weight and runs entirely on the compositor, at the cost of narrower browser support today and less granular control over easing along the path.

Browser support

Chromium-based browsers (Chrome, Edge, Opera, Brave) support animation-timeline: view() today. Firefox and Safari support is still landing, so an @supports not (animation-timeline: view()) block resets the stroke and dot to their fully-drawn end states rather than leaving the line invisible.

Customizing it

Swap the path's d attribute for your own route or logo outline (recompute stroke-dasharray to comfortably exceed the new path's length), adjust the gradient stops in <linearGradient id="spd-grad">, or change view-timeline-axis to inline for a horizontally-scrolling version of the same draw. Pair it with a Scroll Company Timeline or Vertical Timeline for a journey-style narrative.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out the stroke-dasharray or offset-path math by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why stroke-dasharray must be set to a value at least as long as the path's total length, how animation-timeline: --route-in ties the stroke-dashoffset progress to the SVG's own scroll position, and why the dot's offset-path animation stays in sync with the stroke draw purely by referencing the same named timeline and range. The same assistant is useful for extending the effect: ask it to add a pulsing glow to the dot as it travels, make the gradient's colors shift along the path length rather than staying fixed, or convert the effect to view-timeline-axis: inline for a horizontally scrolling route. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an SVG line-drawing effect where a stroked path draws itself in as the reader scrolls past it, using only native CSS scroll-driven animations with a view timeline bound to the SVG element — no GSAP, no ScrollTrigger, no JavaScript scroll math.

Requirements:
- An SVG containing a path drawn with a visible stroke and a gradient defined via a native <linearGradient>, plus a small circular dot element that will travel along the same path.
- The <svg> element itself must declare view-timeline-name and view-timeline-axis: block, creating a named view timeline representing the SVG's own transit through the viewport.
- The path must use the classic stroke-dasharray / stroke-dashoffset technique: stroke-dasharray set to a value at least as long as the path's total length, stroke-dashoffset starting at that same value, and a @keyframes animation driving stroke-dashoffset to 0, bound via animation-timeline to the SVG's named view timeline.
- The dot must use offset-path (set to the identical path data as the stroked path) combined with a @keyframes animation driving offset-distance from 0% to 100%, bound to the exact same named view timeline and the same animation-range as the stroke-draw animation, so the dot's position and the stroke's progress stay in sync automatically with no manual coordination logic.
- Use the contain keyword in animation-range (for example contain 0% contain 100%) so progress is tied to the whole SVG genuinely being within the viewport, appropriate for a graphic sized to roughly fit the viewport height.
- Add an @supports not (animation-timeline: view()) fallback that sets stroke-dashoffset to 0 and offset-distance to 100%, so unsupported browsers show the fully drawn line and the dot at the path's end rather than an invisible stroke or a dot stuck at the origin.
- Keep any JavaScript limited to a CSS.supports('animation-timeline: view()') feature check logged to the console — it must never drive the draw or the dot's movement itself.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste the HTML, CSS, and JSAn intro, the route SVG, and an outro render — no CDN or library needed.
  2. 2
    Scroll down slowlyWatch the gradient stroke draw itself in and the dot travel along the same path.
  3. 3
    Scroll back upThe stroke and dot retract in reverse, since both are bound to a live view timeline.
  4. 4
    Swap in your own routeReplace the path d attribute on .spd-track, .spd-line, and offset-path with your own SVG path data.
  5. 5
    Recompute stroke-dasharraySet stroke-dasharray to a value at least as long as your new path's total length so it fully hides at the start.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Journey, route, and process visualizations
A CSS-only alternative to the Scroll SVG Path Draw GSAP snippet for the same drawing effect.
Brand logo reveal animations
Trace a logo outline in as it scrolls into view without adding an animation library dependency.
Learn view-timeline on non-block elements
A demo of applying a named view timeline to an <svg> element and syncing a second element to the same timeline.
Company history and roadmap pages
Pair with Scroll Company Timeline for a connecting line between milestones.
Replace a GSAP DrawSVGPlugin dependency
Removes the need for GSAP purely for this specific scroll-linked stroke-drawing effect.
Related: Scroll SVG Path Draw
See the Scroll SVG Path Draw for the GSAP ScrollTrigger version with finer scrub control.
Related: Count-Up Stats on Scroll (IntersectionObserver)
See the Count-Up Stats on Scroll (IntersectionObserver) for a related scroll pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

stroke-dasharray is set to a value at least as long as the path, and stroke-dashoffset starts at that same value, hiding the stroke entirely. A @keyframes animation drives stroke-dashoffset down to 0, and binding that animation to animation-timeline: --route-in (a named view timeline declared on the SVG element) ties its progress directly to the SVG's own scroll-driven visibility instead of to a duration in seconds.

The dot uses offset-path set to the identical path data as the line, with offset-distance animated from 0% to 100%. Because that animation references the exact same --route-in named timeline and the same animation-range as the stroke-draw animation, both progress together automatically — there is no manual synchronization logic.

contain restricts progress to the window during which the entire SVG element is contained within the viewport at once, rather than starting as soon as any part becomes visible (which is what cover does). For an SVG sized to fit within the viewport, this keeps the draw progress tied to the graphic genuinely being on screen rather than starting prematurely while most of it is still off-screen.

The GSAP version (Scroll SVG Path Draw) offers finer scrub smoothing, pinning options, custom easing curves, and works consistently across all current browsers today, at the cost of a JavaScript dependency and per-frame script execution. This CSS-only version has zero dependency weight and runs on the compositor, at the cost of currently narrower browser support and less granular control over the draw's easing.

The @supports not (animation-timeline: view()) block sets stroke-dashoffset to 0 and offset-distance to 100%, so Firefox and Safari users see the fully drawn line and the dot already at the end of the path — a stable, complete state rather than an invisible stroke or a dot stuck at the origin.

Yes. Replace the d attribute on .spd-track, .spd-line, and the offset-path value on .spd-dot with your own path data (all three should describe the same path), and update stroke-dasharray to a number comfortably larger than your new path's total length so it fully hides the stroke at the start.