nuzairb@gmail.com— press E to copy
DESIGN ENGINEERING

Designing for Speed: What Performance-Obsessed UI Looks Like

PUBLISHED ON:February 11, 2025

Performance is usually treated as an engineering problem. The design is done, the interface is built, and then someone runs Lighthouse and the optimisation work begins.

That is the wrong order. Most slow interfaces were designed to be slow. The decisions that make them slow — loading everything at once, requiring network round-trips before showing content, animating properties that trigger layout — are made in Figma, not in the browser.

Where slow comes from

Layout animations on the wrong properties. Animating width, height, top, left triggers layout recalculation on every frame. Animating transform and opacity does not — these are compositor-only properties, handled by the GPU without touching the main thread.

A designer who specifies a drawer opening by changing its width has made a performance choice. A designer who understands this specifies a scaleX transform instead.

Blocking visible content on off-screen data. A page that waits for a complete API response before rendering anything creates a blank screen during the fetch. The fix — render the structure immediately, populate data as it arrives — is a design decision. You have to decide what the skeleton looks like. You have to decide the loading state. That's design work, done before engineering starts.

Images loaded at full resolution regardless of viewport. A 3000px wide hero image served to a 390px mobile screen is a design artifact. Responsive image design — different crops at different sizes, lazy loading below the fold — starts with decisions made in the design phase.

Perceived performance vs. measured performance

Measured performance is what Lighthouse scores. Perceived performance is what users feel.

They are not the same, and perceived performance is often more important.

An interface that loads completely in 800ms but shows nothing until it does feels slower than one that shows a skeleton in 100ms and fills in over the next 700ms. The second is no faster. It feels faster because the user has something to look at.

The techniques for improving perceived performance are almost all design decisions:

  • Skeleton screens that match the shape of the incoming content
  • Optimistic UI that assumes success and corrects on failure
  • Staggered content reveals that show progress rather than a single jump
  • Loading states that are designed, not afterthoughts

Each of these requires knowing what the UI looks like during the load, not just after. That's a design problem.

The will-change conversation

There's a property in CSS — will-change — that hints to the browser that an element will animate. The browser creates a new compositor layer for it, which makes the animation fast but costs memory.

Most engineers add it reactively: the animation is janky, they add will-change: transform, it gets smoother. This works but it's treating the symptom.

The real question is: which elements should be promoted to compositor layers? That's an architectural decision about the UI — it depends on what animates, how often, and what else is on the page. It should be part of the component design, not an afterthought.

What this changes about how I work

I think about performance while I design. When I'm deciding how something animates, I'm also asking: what properties are changing? What does the loading state look like? What renders first?

These aren't engineering constraints that get bolted on at the end. They're design constraints that inform every earlier decision — the same way mobile viewport size, or accessibility requirements, or brand guidelines do.

The best interfaces I've seen are ones where performance was a design goal from the beginning. The skeleton matched the content. The animations used the right properties. The data loaded progressively.

Fast is a design outcome. You have to design for it.

Articles in the Same Series