# Performance and reduced motion · Craft

<!-- https://learn-ui.com/chapters/craft/performance-and-reduced-motion -->

The blinking switchboard on the Next.js site glows. How the glow is drawn, and how a page behaves when a reader asks for less motion, are the invisible half of craft.

### Animate opacity and transform

In [Crafting the Next.js Website](https://rauno.me/craft/nextjs) Rauno Freiberg explains that the glow is a CSS shadow but only opacity and transform animate. Animating `box-shadow` would trigger a **repaint** (The browser redrawing pixels for an element; animating box-shadow forces one on every frame of the animation.) every frame, which modern computers absorb but older phones may not. So he toggles the opacity of pseudo elements that already carry a shadow, keyed on a `data-state` of off, medium, or high. The hover that spells NEXT replaces cherry-picked indices in sequence.

> Figure. CSSRauno Freiberg, Crafting the Next.js Website

Emil Kowalski states the rule in [Great Animations](https://emilkowal.ski/ui/great-animations): “If our animations won’t run at 60 frames per second, everything else we’ve talked about becomes useless.” Transform and opacity only trigger composite; padding or margin trigger layout, paint, and composite. When the main thread is busy, use hardware-accelerated CSS or the Web Animations API; his example is a Vercel dashboard tab transition that dropped frames during page load until it moved to CSS.

### Layer so the essence paints first

The Vercel hero in [What will you ship?](https://rauno.me/craft/vercel) is stacked, descending, as heading, SVG triangle, CSS grid lines, SVG rays, CSS rainbow gradient, and a GLSL shader, and needs no client-side code to show its essence. The shader is **progressive enhancement** (Building the core of an experience so it works without a capability, then layering the capability on top for browsers and devices that can handle it.): it fades in after load, can be code split, and light hardware detection skips it on low-powered devices. The pixel icons follow: pixel data renders as canvas for a smaller DOM and animation, with a base64 placeholder of about 1kb per icon, or as SVG above the fold.

Paco Coursey’s [SVG Caching with <use>](https://paco.me/writing/svg-caching-with-use) (2020) is a related economy: reuse rendered icon DOM through `use` with a stable hashed id, about 40% less markup in his example, as long as the id matches between server and client.

> Figure. HTMLPaco Coursey, SVG Caching with <use>

Source

Rauno Freiberg, Crafting the Next.js Website (Blinking Switchboard) and What will you ship? (Hero Composition, Pixelated Iconography, Reduced Motion); Emil Kowalski, Great Animations.

### Pause loops, leave interactions alone

Reduced motion on the Vercel page draws a distinction worth copying. Looping complementary animations, the floating cursors and blinking carets, are paused under `prefers-reduced-motion`. Interactions are not, because they are explicit inputs with no extravagant movement. The loops are CSS keyframes, so rather than `animation: none` the page uses `animation-play-state: paused`. And a detail no one sane has reason to notice: the caret’s opacity is forced to 1, so the blink cannot pause while invisible.

> Figure. CSSRauno Freiberg, What will you ship?

Emil’s reason for the media query is blunt: animations can make some people feel sick or distracted, and his example animates opacity only under reduced motion.

### Slow it down and look

Emil’s skill, [emil-design-eng](https://github.com/emilkowalski/skill/blob/main/skills/emil-design-eng/SKILL.md), adds two constraints. Blur can mask an imperfect transition, but “Keep blur under 20px. Heavy blur is expensive, especially in Safari.”

To see what the eye only senses, increase durations to 2 to 5 times normal, step frame by frame in the Chrome DevTools Animations panel, and test on real devices; in [Good vs Great Animations](https://emilkowal.ski/ui/good-vs-great-animations), “playing the animation frame by frame, or in slow motion, helps you spot it.” Jim Nielsen slowed `::view-transition-old()` to see an outline bug, and Kathryn Gonzalez learned to test on real devices. Three people, same tool.

The Vercel essay names the trade-off: “if an animation or interaction didn’t perform well, felt pompous, or out of rhythm relative to the page, we didn’t build it.” Rauno would rather polish a spring than chase a slow initial load, then asks: “is having a slow website with immaculate attention to visual craft desirable?” Invisible work is the easiest to trade away.

That is where the chapter lands: a glow that does not repaint, a hero that paints before its shader, a caret that pauses visible, designs found only in code. A site that feels fast to everyone is better craft than one immaculate only on the newest hardware.
