Performance

Why we reach for browser-native behavior before animation libraries

Why we prefer browser and CSS capabilities for ordinary motion and interaction, and reserve animation libraries for behavior that actually needs them.

Animation is one of the easiest places for a website to become technically expensive without becoming more useful. A small reveal effect can turn into a dependency. The dependency can turn into client components. The client components can turn into observers, scroll handlers, layout measurement, and more code executing on every page.

We still use motion. We just make it prove its value.

CSS handles a lot of motion well

Opacity, transforms, hover states, focus states, simple reveals, marquee movement, and responsive transitions can often be handled in CSS. That keeps the behavior close to the presentation layer and avoids shipping a JavaScript runtime for effects the browser already knows how to animate efficiently.

Real devices change the calculation

One of our builds had a reveal effect that looked fine on desktop but became visually unstable on touch-first devices when mobile Safari resized its browser chrome. The solution was not to add more JavaScript. The CSS explicitly disables the reveal on narrow or coarse-pointer devices. The content renders normally. The effect disappears.

That decision captures an important priority: content integrity beats animation consistency. If the choice is between "every device gets the same entrance effect" and "every device gets stable content," stable content wins.

Reduced motion is not optional polish

Several repos include prefers-reduced-motion handling. When the user has asked the operating system to reduce motion, the site should respect that preference. This is both an accessibility decision and an engineering simplification. A page should not depend on an animation completing in order for the content to become visible.

We often set the final visible state directly when reduced motion is active.

Scroll listeners need discipline

Sometimes a small amount of JavaScript is appropriate. One production navigation changes appearance after the page has scrolled a short distance. The listener is small and marked passive: true, which tells the browser the handler is not going to cancel scrolling. A gallery listens for keyboard events while its interactive behavior is active.

These are narrow event-driven features, not a global animation engine measuring every section on every frame.

Passive listeners are a small example of a larger philosophy

Performance work is full of details that sound minor. A passive scroll listener. Cleaning up an event listener on unmount. Avoiding body overflow leaks when a modal closes. Not attaching ten observers to the same page. Each detail protects the browser from unnecessary work.

The larger principle is that interaction code should have a lifecycle and a reason to exist.

Animation libraries are useful when the interaction is actually complex

There are experiences where a dedicated animation system is the right tool. Coordinated timeline animation, gesture-driven interfaces, complex shared layout transitions, or rich application states may justify a library. The mistake is using that level of machinery for a headline fading up by twenty pixels.

Motion should support comprehension

Good motion can communicate hierarchy, focus attention, show state changes, or make navigation feel coherent. Motion that exists only to prove the site is animated often becomes repetitive. We prefer subtle motion with short durations and clear purpose. If removing an effect makes the site easier to use and faster, that is a strong signal the effect was not carrying its weight.

The performance cost is not only bundle size

Animation can create layout work, paint work, compositing layers, and continuous main-thread activity. A small library can still be expensive if it causes constant measurement or state updates. This is why real-device testing matters. DevTools can tell us about script weight. A phone can tell us whether the page actually feels steady while its viewport is changing.

Browser-native behavior is easier to hand off

A future developer understands CSS hover states, media queries, keyframes, and simple event listeners. A site built around a specialized motion abstraction may require understanding a library before changing a basic interaction. We are not trying to avoid dependencies at all costs. We are trying to avoid making simple behavior depend on specialized infrastructure.

Our default question

Before adding an animation dependency, we ask: Can CSS do this cleanly? Can the browser's native behavior do this? Can a small isolated client component do this? Does the effect survive reduced-motion mode? Does it behave correctly on touch devices? Does it add enough value to justify its runtime cost?

If the answer keeps pointing toward a simpler implementation, we choose the simpler implementation. The visitor came for the business, not the animation stack.

From explanation to proof

Where this connects to the work

The performance library explains why our technical scores tend to be unusually strong without treating the score itself as the product.