01

Performance Is Design

How fast it feels is a design choice.

Speed is something people feel before they measure it. Two apps can fetch the same data in the same time and one will feel quick while the other feels like it is thinking about it. The difference is what you show while the wait happens.

That makes waiting a design problem. Perceived performance is the part of speed you control with pixels, and it is usually the cheaper part to improve.

Both cards take the same 1.2 seconds to load. The wait plays on a loop, then they land on the same list. Replay is the only control.

The spinner says "please wait". The skeleton says "here is the shape of what is coming". Same wait, and the second one feels shorter because your eye already has somewhere to go.

Short waits want silence

Loading states have a cost of their own. Every placeholder is a thing that appears and then disappears, and quick flashes of UI read as churn.

For a wait that ends in a blink, the calmest thing you can do is hold the layout and show nothing. Then fade the real content in.

A rough guide that has held up well:

  • Under about 300ms, show nothing. Reserve the space so nothing jumps.
  • Between 300ms and a second, hold layout and fade content in. A skeleton is fine if the wait is reliably in the upper half of that range.
  • Over a second, you owe people an explanation. This is where skeletons, progress, and honest copy belong.

Never stretch a loading state to make it "smooth". If the data is ready, show it.

Do not wait for permission

Most actions succeed. When you already know what the result will look like, show it immediately and let the request catch up. If it fails, you can roll back and say so.

This is what makes Linear and Things feel instant. Nothing about their network is special. They just stopped making you watch the round trip.

Even the spinner has a speed

When you really do need a spinner, how fast it turns changes how long the wait feels. Same load, two spinners.

The faster one is not lying. It is just not adding its own slowness on top of the real one.

The real fix

Shu Ding's point is that slow products rarely have one cause. They are hundreds of small decisions, each defensible, that nobody looked at together. Design is the act of looking at them together.

So the best loading state is often the one you deleted. Cache the data. Render it on the server. Prefetch on hover. Then the interface gets to do the most confident thing it can do, which is to just show the thing.