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.

Layout shift from an unreserved hydrated widget Before hydration the content sits high; after a widget mounts without reserved space, the content is pushed down, causing layout shift. Reserving space keeps it stable. No reserved space widget appears content pushed down CLS spikes ↑ Reserved space slot held open content stays put CLS β‰ˆ 0
Reserve the widget's dimensions before hydration so mounting it does not move surrounding content.

Step-by-step fix

  1. 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>
  2. 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>
  3. Size skeletons to match final content. A 200px skeleton replaced by 400px of content shifts everything below it β€” match the dimensions.

  4. Pin web fonts with font-display: optional or preload to avoid a font swap reflow during hydration.

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.

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.

← Back to Incremental & Streaming SSR for SEO