micro-interactions
Micro-Interactions
Big animations impress once. Micro-interactions are what make an app feel expensive on the hundredth use: the button that acknowledges a press, the toggle that moves like an object, the row that tells you it is clickable before you click it. This is also where scattered, per-element effects do the most damage -- ten different hover treatments read as ten different authors.
Draw every value from the motion system (--dur-fast, --ease-out); this skill is about which interactions get motion and what they do.
The interaction set
Hover -- available on the element, not a new element appearing. Background, border, or foreground shift; at most a 1-2px lift or scale(1.02). Never reveal essential information only on hover: it does not exist on touch. Guard hover styles with @media (hover: hover) so mobile does not get sticky hover states after a tap.
Press -- the most underrated one. scale(0.97) on :active, at --dur-fast. It costs one line and is the difference between a div and a button.
Focus -- designed, never default. A visible ring using the brand's accent, on :focus-visible so it appears for keyboard users and not on mouse click. Removing focus outlines without replacing them is an accessibility failure, not a style choice.
Loading -- state-appropriate. Under ~300ms show nothing (a flashed spinner is worse than a pause). Up to a few seconds, a spinner or an inline button state. Longer, and for content-shaped waits, use a skeleton that matches the real layout. A skeleton whose shape does not match what loads causes a layout jump, which is worse than a spinner.
Success / error -- the result must be felt, not just rendered. A brief color shift, a checkmark that draws, an error that shakes once (one cycle, 300ms, never a loop). Errors also need to be announced, not only shown -- aria-live on the message.
Toggles, accordions, tabs -- these move something that exists, so the motion is positional and continuous. --ease-in-out. For accordions use grid-template-rows: 0fr → 1fr (animatable, unlike height: auto) or the newer interpolate-size: allow-keywords.