On UI Animations
Thanks Paco for bringing up this great topic, and creating the outline of this article while we brainstorming the animation part of our design system. Here're some personal notes that I think worth writing down.
Common Transition Values as Design Tokens
Using CSS variables for animations will be very helpful for most of our use cases. I personally prefer ease
with a small duration (~200ms) as the CSS transition setup, but we can define our own easing function too as design tokens.
Transitions in Contexts
There are two types of transitions:
A. Styles (opacity, color, background, shadow, border, transform, etc.)
When changing a style, the animation should be subtle and should serve the purpose of noticing the user that, something appears, disappears, changes, or simply showing that it is interactable.
That covers most of our elements such as popover, tooltip, menu, button, link, modal. And in which case we should simply use pre-defined CSS variables (tokens) as their initial/target values.
B. Layouts (top, left, bottom, right, height, width, etc.)
When changing the layout, we usually want to show the logic of the UI to the user, to give them a sence of the connection between some elements. If the content is hidden inside a foldable, we use expand/collapse animations to build the UI structure. If the content is hidden inside a menu layer, we use slide in/out animations to imply the UI hierarchy.
Things with fixed layouts (hence the animations will have fixed durations and ranges) should be crafted case by case. e.g.: feedback input and toast.
For things with unpredictable layouts (mostly with dynamic contents), e.g.: file tree, collapse, show more, drawer..., there're 2 challenges with CSS:
- It's not allowed to use CSS to animate a property from fixed values like
0
toauto
. The target size has to be measured (getBoundingClientRect
) before the actual animation happens. - We need to monitor possible layout changes, such as resizing events, even during the animation. That makes it harder to implement correctly.
The best choice is to use spring-based animations (e.g.: react-spring, react-motion) with ResizeObserver to measure and animate the layout changes responsively.
When Is No Animation Desirable?
- Keep all the animation variables in one place, so we can have the ability to toggle them via one single class
.reduce-motion
in the future. - For toolbar menus or submenus, when hover and moving between items we don't want the popover to fade in/out too frequently. Users should have their focus on the content, rather than the animations. Also those menu should be visually continuous when moving around the cursor. stripe.com is a great example. Or we just disable the fading animation when moving the cursor between items like what macOS is doing.
- Functionality first. For very common components like tooltips and menus, we should try to reduce the animation as much as possible: they don't provide much info but instead can be really annoying. That's why the macOS' menu has a fading out duration when closing but instantly showing it when opening, to present the content to the user as soon as possible. As a bad example, Material Design has too many useless animations.
- If the (DOM) animation slows down the website, remove it. We can look for alternatives like video, canvas, or SVG.