The First Rule of Animation, Applied to the Web
Disney's 12 Basic Principles of Animation were written for cartoon movies, not CSS. But one of them, "squash and stretch," translates remarkably well to front-end development. The idea is simple: objects in motion shouldn't stay rigid. A bouncing ball flattens on impact and elongates as it rebounds, and that distortion makes the motion feel more convincing and pleasant.
While the classic demo is a bouncing ball, the technique is often more useful for subtle micro-interactions on SVG icons. Small touches—an arrow that appears to stretch and thin as it grows—can make an interface feel significantly more polished.
Stretchy Arrows: A Practical Example
To see this in action, consider a standard arrow-right icon from Lucide, a popular SVG icon set. The icon's markup contains two paths: a straight horizontal line for the shaft and a path for the arrow tip. The goal is to create a hover state where the shaft grows wider (say from a 14px line to a 17px line) while the arrowhead also changes shape.
This requires defining an alternative set of drawing instructions for the hover state. The core technical question becomes: how do we smoothly transition between these two sets of SVG path data?
The CSS Route and Its Limitations
One option is to use CSS transitions. You can override the d attribute directly within CSS using the path() function. When a user hovers, you apply new drawing instructions for both path nodes, and CSS transitions handle the interpolation.
You can wrap this in a prefers-reduced-motion media query to avoid triggering the animation for users with motion sensitivities, even for subtle effects like this.
There is, however, a significant gotcha: CSS transitions on path elements are not supported in Safari. This limits browser support to roughly 79% as of early 2026. For purely cosmetic enhancements, this may be acceptable. Another wrinkle is that CSS strings are not multi-line. You'll have to keep the new path data on a single line (e.g., path("M 5,12 h 17")) or escape newlines with backslashes if you want to format the code for readability.
The JavaScript Library Alternative
For broader support, a JavaScript animation library like Motion is a better fit. Motion has evolved from the React-exclusive Framer Motion into a vanilla-JS tool with versions for React and Vue. Its animate() function manually calculates intermediate values each frame. This often sounds inefficient, but Motion is well-optimized and uses the Web Animations API under the hood, which runs on a separate thread to keep animations smooth even during heavy application load.
Refining the Effect
The basic stretch effect can be improved in two notable ways, especially when using a library like Motion.
First, you can switch from a standard Bézier curve to spring physics. Unlike Bézier curves, spring models are based on real-world physics and produce motion that feels more natural and elastic. For a squash and stretch effect, this rubbery quality is particularly fitting.
Second, the interaction model can change. Rather than a state-based hover (the arrow stays stretched as long as the cursor is over it), you can trigger the animation on the hover event itself. In this variant, the arrow stretches briefly for a moment and then snaps back, even as the cursor remains. This event-based approach is more playful and unexpected, distinguishing it from nearly all other state-based hover interactions on the web.
Combining spring physics with an event-based trigger creates a much more distinctive and lively micro-interaction than a standard CSS hover transition.



