CSS offset-path: Animate Elements Along Any Path You Can Imagine
If you have ever wanted to move an element along a curved line, a circle, or even a wild hand-drawn path — all without a JavaScript animation library — the CSS offset-path property is exactly what you need.
This guide covers everything you need to know: what offset-path does, how to use it, its accepted values, related properties, and alternative approaches.
What Is offset-path?
The offset-path CSS property defines a movement path that an element follows during an animation. Instead of moving in a straight line from point A to point B, you can guide an element along any shape you define — a circle, a bezier curve, a polygon, or a completely custom SVG path.
It is important to note: offset-path itself is not animatable. It defines the route. You then use companion properties — primarily offset-distance — to actually move the element along that route.
A Note on the Old motion-path Name
This property originally shipped in browsers as motion-path. The CSS Motion Path specification later renamed it (along with all related motion-* properties) to use the offset-* prefix. If you need to support older Blink-based browsers from around 2015–2016, it is safest to include both syntaxes:
.thing-that-moves {
/* "Old" syntax — available in Blink browsers around October 2015 */
motion-path: path("M 5 5 m -4, 0 a 4,4 0 1,0 8,0 a 4,4 0 1,0 -8,0");
/* Current spec syntax — stable Chrome from around December 2016 */
offset-path: path("M 5 5 m -4, 0 a 4,4 0 1,0 8,0 a 4,4 0 1,0 -8,0");
}
For any modern project, use offset-path exclusively.
Basic Usage: Animating Along a Path
Here is a simple, complete example. First, define the path on the element. Then use a @keyframes animation that drives offset-distance from 0% to 100%:
.thing-that-moves {
offset-path: path('M 5 5 m -4, 0 a 4,4 0 1,0 8,0 a 4,4 0 1,0 -8,0');
animation: move 3s linear infinite;
}
@keyframes move {
100% {
offset-distance: 100%;
}
}
In this example, the element travels from the start of the SVG path all the way to the end over three seconds, then loops infinitely. The path in this case is a circle — defined using SVG arc commands.
You do not need to visually draw the SVG path on the page at all. The path data in offset-path is invisible by default. It purely dictates the route for your animation.
Using Custom SVG Paths
One of the most powerful aspects of offset-path is that you can design any path you want in a vector editing tool like Figma, Illustrator, or Inkscape, then transfer the path data directly into your CSS.
When you draw a path in an SVG editor, the resulting markup looks something like this:
<path d="M10,80 C40,10 65,10 95,80 S150,150 180,80" />
The value of the d attribute is what you want. Copy it and drop it straight into your CSS:
.animated-element {
offset-path: path("M10,80 C40,10 65,10 95,80 S150,150 180,80");
animation: travel 4s ease-in-out infinite;
}
@keyframes travel {
100% {
offset-distance: 100%;
}
}
That is all there is to it. The element will glide smoothly along your custom-drawn curve.
A Note About Coordinate Units
The values inside path() are unitless numbers. How they are interpreted depends on context:
- If the CSS is applied to an element inside an SVG, the coordinates map to the SVG’s internal coordinate system as set up by its
viewBox. - If the CSS is applied to a regular HTML element, the coordinate values are treated as pixels.
Controlling Element Rotation with offset-rotate
By default, when an element moves along a path, CSS automatically rotates it to face the direction of travel — like a car navigating a winding road. This behavior is controlled by the offset-rotate property.
You have several options:
.mover {
offset-rotate: auto; /* Default: faces forward along the path */
offset-rotate: reverse; /* Faces backward along the path */
offset-rotate: 30deg; /* Fixed angle, no automatic rotation */
offset-rotate: auto 30deg; /* Auto-rotate plus an additional 30° offset */
}
The auto value is what makes animated characters, arrows, or icons naturally “point” in the direction they are moving. The auto 30deg combination is handy when your graphic is not perfectly aligned with the path direction out of the box.
Accepted Values for offset-path
The CSS Motion Path specification defines several values for offset-path. In practice, path() and none have the strongest, most reliable browser support today. The others are part of the specification and support is actively improving.
path()
Uses SVG path syntax to define the movement route. This is the most widely supported option and what you will use most often.
offset-path: path("M 0 0 L 300 200 L 600 0");
shape()
A newer CSS-native way to define a path using CSS-style commands rather than SVG syntax. It is designed to feel more natural for CSS developers.
offset-path: shape(from 0% 0%, line to 100% 50%, line to 0% 100%);
url()
References an SVG element by its ID to be used as the movement path. In theory this lets you reuse a visible SVG path in your markup. Browser support for this remains inconsistent.
offset-path: url(#my-svg-path);
none
Removes any offset path from the element. The element is positioned normally.
offset-path: none;
CSS Shape Functions
The specification also allows basic CSS shape functions from the CSS Shapes specification to be used as offset paths:
circle()— animate along a circular pathellipse()— animate along an elliptical pathinset()— animate along a rectangular inset pathpolygon()— animate along a multi-sided polygonxywh()— define a rectangle by position and size
Support for these shape functions as offset-path values is steadily improving across modern browsers, but always check current compatibility tables before using them in production.
The Full Family: Related offset-* Properties
The offset-path property does not work in isolation. It is part of a group of CSS properties that together give you complete control over motion path animations:
offset-path— Defines the path the element follows.offset-distance— Controls how far along the path the element has traveled, expressed as a percentage or length. This is what you animate.offset-anchor— Sets which point of the element is pinned to the path (similar totransform-origin).offset-rotate— Controls the rotation of the element as it travels along the path.
A typical full setup combining these properties might look like this:
.animated-icon {
offset-path: path("M0 100 Q 150 0 300 100 T 600 100");
offset-distance: 0%;
offset-anchor: center;
offset-rotate: auto;
animation: follow-path 5s linear infinite;
}
@keyframes follow-path {
to {
offset-distance: 100%;
}
}
Using offset-path with the Web Animations API
Everything you can do with offset-path in CSS is also accessible through the Web Animations API in JavaScript. This gives you programmatic control over the animation — the ability to pause, reverse, scrub, or dynamically change the path at runtime.
For example, if you have defined your offset-path in CSS, you can still control the animation from JavaScript:
const element = document.querySelector('.animated-icon');
const animation = element.animate(
[
{ offsetDistance: '0%' },
{ offsetDistance: '100%' }
],
{
duration: 3000,
iterations: Infinity,
easing: 'linear'
}
);
// Pause on hover
element.addEventListener('mouseenter', () => animation.pause());
element.addEventListener('mouseleave', () => animation.play());
This combination of declarative CSS path definition and JavaScript animation control is a very powerful pattern for interactive UIs.
Alternative Approaches to Path-Based Animation
CSS offset-path is the modern, standards-based solution, but it is worth knowing about other options that have existed for longer and may fit certain use cases better.
SMIL animateMotion
SVG has its own native animation system called SMIL (