Reducing Layout Shift During React Hydration
A server-rendered React page can look perfect on first paint and then jump a moment later, when hydration mounts components that were not in the server markup β a personalized header, an ad slot, a client-only carousel. Each unreserved mount pushes content down and adds to Cumulative Layout Shift, a Core Web Vital that influences ranking. This guide eliminates hydration-driven CLS and complements the hydration strategies comparison.
Step-by-step fix
-
Reserve space for client-only widgets. Give the container fixed dimensions in the server markup so the mount fills a held slot instead of pushing content.
// β Widget mounts into a zero-height container, shoving content down <div id="promo">{mounted && <Promo />}</div> // β Reserve the final size up front; no shift when it mounts <div id="promo" style={{ minHeight: 90 }}>{mounted && <Promo />}</div> -
Render auth-dependent UI consistently between server and client. Rendering a logged-out header on the server and a logged-in one after hydration shifts the layout; render a stable shell and fill details in place.
// β Same height server and client; only the label swaps <nav style={{ height: 56 }}>{user ? <AccountMenu /> : <SignInLink />}</nav> -
Size skeletons to match final content. A 200px skeleton replaced by 400px of content shifts everything below it β match the dimensions.
-
Pin web fonts with
font-display: optionalor preload to avoid a font swap reflow during hydration.
Each of these fixes removes one contributor to a score that otherwise stacks up quickly β three unreserved mounts alone can push a page past the limit.
Validation
- Lighthouse β Cumulative Layout Shift under 0.1 on lab runs.
- Performance panel β Experience lane shows no shift markers after load.
- Web Vitals field data (CrUX / RUM) confirms CLS at the 75th percentile under 0.1.
- DevTools βLayout Shift Regionsβ overlay highlights nothing during hydration.
The number those tools report is graded against fixed bands, and validation passes only when the field score lands in the good one.
Configuration reference
/* Reserve space for hydration-mounted regions so CLS stays flat */
[data-hydrate] { min-height: var(--reserved-height, 0); }
.skeleton { height: var(--final-height); } /* match real content */
@font-face { font-family: Inter; font-display: optional; } /* no swap reflow */
Frequently Asked Questions
Why does my page shift right after it loads? Hydration mounts components that were not in the server HTML β ads, auth-dependent menus, client-only widgets β and they push existing content down. Each unreserved mount contributes to Cumulative Layout Shift. Reserving space before hydration eliminates the shift.
Does Cumulative Layout Shift affect rankings? Yes. CLS is a Core Web Vital and part of Googleβs page experience signals. A CLS above 0.1 is flagged as needing improvement and can weigh against a page in competitive rankings.
Related
- Incremental and streaming SSR for SEO β where hydration fits in the streaming pipeline.
- Hydration strategies compared β hydrate less to shift less.
- How to fix React hydration mismatch SEO warnings β the related correctness bug.
β Back to Incremental & Streaming SSR for SEO