offset-rotate and Auto-Orientation Along a Path
Part of Motion Path & Individual Transforms in Core CSS Animation Fundamentals.
The problem
A delivery-tracking illustration animates a small van along a winding route. With offset-rotate: auto the van turns with the road — but it drives sideways, because the artwork was drawn facing up. On a sharp corner it spins around instantly. On the return leg it drives in reverse. And the label attached to it, “Out for delivery”, is upside-down for half the journey.
Every one of these is a question about which angle the browser applies at each point on the path, and every one has a one-line answer once that rule is clear.
Root cause analysis: the tangent and the element’s x-axis
When an element moves along an offset path, offset-rotate decides its rotation at every point.
With auto, the element is rotated so that its positive x-axis — pointing right in its own coordinate system — lines up with the direction of the path at that point, the tangent. Artwork that faces right follows the road correctly. Artwork that faces up is off by 90 degrees.
auto <angle> adds a fixed angle to the tangent. auto -90deg corrects artwork drawn facing up; auto 180deg corrects artwork drawn facing left.
reverse is auto 180deg: the element faces opposite to the direction of travel.
A plain <angle>, such as 0deg, ignores the path’s direction entirely and keeps a constant rotation. That is the right value for anything with text.
The sudden spin comes from the path, not the property. At a sharp corner the tangent changes direction instantly, so auto rotation changes instantly too. At a cusp — where the path doubles back — the tangent reverses and the element flips 180 degrees in one frame. The fix belongs in the path data: rounded corners give the tangent a curve to turn through.
Step-by-step resolution
Production code pattern
.route {
position: relative;
aspect-ratio: 480 / 220;
--route: path("M 20 180 C 120 180 120 60 220 60 S 320 180 460 40");
}
.route__van,
.route__label {
position: absolute;
inset: 0 auto auto 0;
offset-path: var(--route);
offset-distance: var(--progress, 0%);
transition: offset-distance 2.4s cubic-bezier(0.45, 0, 0.25, 1);
}
.route__van {
offset-anchor: center;
offset-rotate: auto -90deg; /* artwork faces up; rotate it onto the tangent */
}
.route__label {
offset-anchor: 50% 180%; /* ride above the van */
offset-rotate: 0deg; /* never turn text */
}
.route[data-status="delivered"] { --progress: 100%; }
@media (prefers-reduced-motion: reduce) {
.route__van, .route__label { transition: none; }
.route__van { offset-rotate: 0deg; } /* no leftover diagonal angle at the destination */
}
Rendering Impact: composite.
offset-rotateis applied as part of the element’s transform at each sampled distance; it adds no layout or paint, and the tangent at each point comes from geometry the browser computed once for the path.
Declaring the path once in a custom property keeps the two elements on exactly the same route. If they each carried their own copy of the path data, a later edit to one would silently separate the label from the van.
Cusps and closed loops
A path that doubles back on itself has a point where the tangent reverses. With auto, the element flips 180 degrees there in a single frame. If the artwork is symmetrical — a dot, a circle — nobody notices. For a vehicle, either split the journey into two paths so the flip happens while the element is paused or hidden, or change the path to a tight loop so the turn has somewhere to happen.
Closed paths such as circle() or a path() ending in Z have a continuous tangent everywhere except possibly at the start point. With an infinite orbit animation, check the join: if the path’s start and end directions differ, the element snaps its rotation once per revolution.
Verification checklist
Constraints and trade-offs
offset-rotaterotates everything inside the element, including focus rings and shadows.- Rounded corners change the route’s length, which changes speed through them slightly.
- A fixed angle ignores direction completely, so arrows will point the wrong way on some legs.
autodepends on the tangent, which is undefined on zero-length path segments; remove degenerate segments.- The
offsetshorthand resetsoffset-rotatetoautoif you omit it.
Frequently asked questions
Why does my element travel sideways with offset-rotate: auto?
auto aligns the element’s right-pointing x-axis with the path. If the artwork faces up, add a correcting angle such as auto -90deg.
How do I stop an element spinning at a corner?
Round the corner in the path data. The tangent changes instantly at a sharp corner, so auto rotation does too; a curve spreads the turn over several frames.
Should text use offset-rotate: auto?
No. Use a fixed angle such as 0deg. Rotating text along a path makes it hard or impossible to read, especially for people using magnification.
Related
- Motion Path & Individual Transforms — the parent topic
- Animating Along an Offset Path — path() routes in detail
- offset-anchor and offset-position Explained — which point of the element rides the path