Performance Is Design
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.
Press the button below. Both cards take the same 1.2 seconds to load.
- Design reviewToday
- Ship OG imagesYesterday
- Fix Safari overscrollMonday
- Design reviewToday
- Ship OG imagesYesterday
- Fix Safari overscrollMonday
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.
- Design reviewToday
- Ship OG imagesYesterday
- Fix Safari overscrollMonday
- Design reviewToday
- Ship OG imagesYesterday
- Fix Safari overscrollMonday
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.
Resources
Performance is not a technical problem - Shu Ding on why slow products are the sum of small decisions nobody owned.
Response times, the three important limits - The classic 100ms, 1s, and 10s thresholds and what each one means for feedback.
Progress indicators make a slow system less insufferable - When a spinner is enough, when you need a bar, and when to show nothing.
You don't need animations - Emil Kowalski on how motion can make a fast interface feel slow.
Details that make interfaces feel better - A collection of small decisions, several of them about waiting.