CSS
It's common to reach for a JavaScript library like Motion when you want to perform spring animations. But Motion is also capable of generating springs via CSS, both on the server and in the browser.
In this guide, we'll learn how to make spring animations with CSS, with a variety of libraries and frameworks:
React Server Components
Via the
style
attributeCSS-in-JS (Styled Components, Tamagui)
Astro
React
Vue
We'll also learn how to fall back to either no animation or a different animation for cross-browser support.
Import
To generate our spring CSS rules, we're going to be using Motion's spring()
function.
Overview
spring
has two features that makes it perfect for CSS generation.
A
toString()
method.A
spring(visualDuration, bounce)
shorthand.
toString()
returns the spring as a CSS duration and easing. The new shorthand makes it simpler than ever to make springs.
Put together, we can create CSS rules like this:
The generated duration can be longer than the one provided to spring
because it accepts the new visualDuration
option, which makes it easier to edit springs and coordinate them with other transitions:
Here, transform
will actually take longer, but it will appear to take a similar amount of time to animate as opacity
. This is because the visualDuration
defines the amount of time the animation takes to first reach its target, not perform the "bouncy bit" after.
Server generation
React Server Components
With React Server Components (RSC), it's possible to set springs via the style
prop.
This code will be run entirely server-side, with no runtime overhead.
It's also possible to use the style
tag:
Client generation
style
attribute
You can set transition
on an element at runtime, before changing its other values.
CSS-in-JS
CSS-in-JS follows the same basic approach of string concatination, with the exact pattern depending on your library of choice:
Styled Components
Tamagui
Astro
In Astro, you can define the spring as a CSS variable using JavaScript, and then in your CSS use that value with var()
:
Vue
Fallbacks
By default, the browser will ignore your animation if it doesn't support the linear()
easing function.
In CSS it's possible to set a second transition
with a lower specificity to act as a fallback, though this might not be supported by all CSS generators (like setting via style
):
This is another benefit of the spring()
shorthand accepting visualDuration
instead of duration
- you can use the same duration for both of these animations and they'll feel like they take an equivalent time to complete.