Wave path
Animate an element along a wave-shaped path using CSS offset-path with an SVG path definition — no JavaScript required.
Quick implementation
.wave-dot {
offset-path: path('M 20,64 C 60,20 100,108 140,64 C 180,20 220,108 260,64 C 300,20 340,108 380,64');
offset-distance: 0%;
offset-rotate: auto;
animation: wave-travel 2.5s linear infinite;
}
@keyframes wave-travel {
to { offset-distance: 100%; }
}
@media (prefers-reduced-motion: reduce) {
.wave-dot { animation: none; }
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building CSS motion path animations.
Goal: Animate an element along a wave-shaped curved path using CSS
offset-path with an SVG path string — no JavaScript required.
Technical constraints:
- Use offset-path: path('M...C...') with cubic bezier SVG commands to
define the wave shape.
- Animate offset-distance from 0% to 100% with @keyframes.
- Add offset-rotate: auto so the element faces its direction of travel.
- Use oklch() for all color values — no hex or rgba.
- Wrap the animation in @media (prefers-reduced-motion: reduce) and stop it.
Framework variant (pick one):
A) Vanilla CSS — a .wave-dot class applied to any element.
B) React component — accepts pathD (string, the SVG path data), duration
(number, seconds), and color (string) props.
Edge cases to handle:
- The path coordinates are in the element's local coordinate space, not
the viewport — position the container as position: relative and the
animated element as position: absolute with top: 0; left: 0.
- If offset-rotate: auto causes unwanted flipping, use offset-rotate: 0deg
to lock the element's orientation.
- Screen readers do not perceive CSS motion — no ARIA is needed for the
animation itself, but the container should have a descriptive label if
the motion conveys meaning.
Return CSS only (or a React component if variant B).
Why this matters in 2026
CSS offset-path motion paths landed in all major browsers in 2022 and replace JavaScript-driven animation libraries for curved-path effects. Previously, animating along a non-linear path required a JS library like GSAP to interpolate coordinates at every frame — adding kilobytes of script for what CSS can now do natively. In 2026, with full cross-browser support established, offset-path is the correct tool for any animation that follows a curve.
How offset-path and offset-distance work together
offset-path accepts a path() string using SVG path syntax. offset-distance (animatable from 0% to 100%) moves the element along that path. offset-rotate: auto rotates the element to face the direction of travel — removing it makes the element stay upright while sliding along the curve.
The cubic bezier commands (C) in the path definition produce the smooth wave shape: each C x1,y1 x2,y2 x,y command defines two control points and the endpoint for a curve segment. Three such segments join end-to-end to form a full sinusoidal wave across the container.
Because the animated element is positioned absolute with top: 0; left: 0, the path coordinates are interpreted relative to the element's own containing block — so the SVG path data you render as a visible guide and the offset-path string can be identical, keeping the visual and the animation perfectly in sync.
Accessibility and performance
Wrap the animation in @media (prefers-reduced-motion: reduce) and stop it completely — offset-path motion is vestibular-triggering for users with motion sensitivities. Setting offset-distance: 50% in the reduced-motion block keeps the element visible and centred on the path rather than disappearing.
offset-distance is composited by the browser (GPU layer), so it animates at 60 fps without touching layout. Avoid animating offset-path itself (the path definition) — only animate offset-distance. Changing the path string at runtime forces a style recalculation and defeats the compositing benefit.
Mark the decorative SVG guide path as aria-hidden="true" so screen readers skip it. If the animation conveys meaningful information (for example, showing a data flow direction), add an aria-label to the container describing what is happening.