Page load (cold)
A first-time visitor lands on the page. Nothing is cached. The server (or the route bundle, or the data fetch) takes 1.5 seconds to respond. During those 1.5 seconds the user is staring at something — and that something is the entire perception layer for this scenario.
The naive answer is to render nothing until everything is ready. The tuned answer is to render the layout immediately, fill it with placeholders the user can read as structure, and swap in the real content the moment it arrives. The total time-to-content is identical. The total time-to-useful-something-on-screen is fundamentally different.
This scenario sits in the 1–10 S band. Miller 1968's Miller 1968 simple-inquiry tier puts most cold loads in the 2–5 s comfortable range; Block & Zakay 1997 Block & Zakay 1997 and James 1890 James 1890 are the source-of-record for why filling that wait with structure makes it register as shorter.
List fetch
A small list of items loads from a synthetic API. The naive side waits silently; the tuned side shows skeletons that match the final layout.
Off
Press Run to start
On
Press Run to start
What is happening in the demo
Both sides simulate the same fetch — a 1,500 ms p50 wait drawn from a gamma distribution, returning the same 5-item list. The naive side renders an empty 8-rem-tall box for the duration of the fetch, then drops the list in. The tuned side renders five skeleton rows immediately — same dimensions as the final list items, with animate-pulse on two dimensional bars per row — and swaps in the real items when the fetch resolves.
The skeleton is layout-matching, not generic. Each placeholder row has a 32-character-wide bar (the "name" line) and a 48-character-wide bar (the "role" line). When the real data arrives, the visual change is a swap, not a jump. The user's eye is already in the right place.
The shimmer animation respects prefers-reduced-motion — for users who have asked for less motion, the placeholders hold a static low-contrast state instead of pulsing. They still serve the filled-duration purpose; they just do not animate.
What to tune
- First paint — shell ships immediately; layout structure is in place before the data arrives.
- First 1 s — layout-matching skeleton fills the empty regions. Same row count, same column widths, same vertical rhythm as the resolved content.
- 1 – 10 s — skeleton holds. LQIP / blur-up for image content. Streaming SSR with Suspense lets sections fill in independently.
- Completion — data swaps in over ~150 ms. Layout stable (no CLS); focus lands on the first heading for keyboard users who clicked through.
- Past 10 s — escalate to engagement copy. Below 1 s, no loader at all.
When perceived performance hurts you here
The cold-load case is the cleanest place for skeleton screens to do their work — the user is in consumption mode (they came to read, not to act), and the layout is predictable enough that a layout-matching skeleton is honest.
The failure mode is shipping a skeleton on a surface where the user is in production mode. A search input under a skeleton is a search input the user cannot use; a button placeholder is a button they cannot press. See Concepts §6 for the consumption-vs-production line.
The other failure: a skeleton that does not match the final layout. A generic shimmer at the top of the page is still a prospective-empty wait — the user's eye has nothing to anchor on. Match the row count, the column widths, the vertical rhythm. Otherwise the skeleton is decoration, not perception engineering.
Accessibility
aria-busy="true"on the skeleton container; flips tofalseonce content arrives.aria-label="Loading [thing]"describing what is loading. "Loading list" is enough; "Loading" alone is not.motion-reduce:animate-noneon the shimmer. Static low-contrast blocks still convey loading state.- Manage focus across the swap. If the user triggered the load (clicked through to this page), move focus to the new content's first heading, or to a stable landmark, so keyboard users do not lose their place.
- Layout stability. The skeleton's dimensions must match the resolved content's dimensions — otherwise the swap creates a Cumulative Layout Shift (CLS) that hurts both perception and Web Vitals.
References
References · 3
- James 1890
James, W. (1890). The Perception of Time. The Principles of Psychology, Ch. 15. Holt. Filled vs. empty duration — skeleton screens convert the prospective-empty wait of a cold load into a prospective-filled one.
- Block & Zakay 1997
Block, R. A., & Zakay, D. (1997). Prospective and retrospective duration judgments: A meta-analytic review. Psychonomic Bulletin & Review, 4(2), 184–197. Meta-analysis confirming the prospective-empty / prospective-filled distinction.
- Miller 1968
Miller, R. B. (1968). Response time in man-computer conversational transactions. Proceedings of the AFIPS Fall Joint Computer Conference, 33(I), 267–277. The 1–10 s simple-inquiry tier the cold load sits inside.