Browser, HTML/CSS & React — from markup to hydration
Core details
1. Browser: from bytes to pixels
The browser is a pipeline. Rough order (same vocabulary as Rendering pipeline & compositing):
- Parse HTML → DOM (live tree of nodes: elements, text, comments).
- Parse CSS → CSSOM (tree of style rules + @-rules).
- Style — match selectors to nodes, resolve cascade, produce computed values per element.
- Layout (“reflow”) — compute geometry (box model, flow, positioning).
- Paint — rasterize pictures (text, colors, images, effects) for regions that changed.
- Composite — merge layers into the frame shown on screen (GPU-backed where applicable).
HTTP response (HTML bytes)
│
▼
┌─────────┐ stylesheets, inline <style>
│ DOM │◄────────────────────────────┐
└────┬────┘ │
│ ┌─────▼─────┐
│ │ CSSOM │
└──────────┬──────────────┴─────┬─────┘
│ │
▼ ▼
computed styles ◄─── cascade (specificity,
order, inherit)
│
▼
layout → paint → composite → frameHTML’s job: encode structure and semantics (<main>, headings, landmarks). Accessibility and SEO lean on honest structure—not only div soup.
CSS’s job: encode presentation (which properties apply to which elements). The cascade decides which declaration wins when several rules target the same property: origin (user agent, author, user) → important → specificity → source order.
2. HTML loading & script execution (interview soundbite)
| Script mode | Typical effect |
|---|---|
Classic <script src> | Blocks HTML parsing until fetched & run (unless async/defer). |
defer | Fetch in parallel; run after HTML parse, in order. |
async | Fetch in parallel; run when ready—order not guaranteed vs other async scripts. |
Why it matters for React: your bundle must load and execute before hydration can attach event listeners and state to existing HTML.
3. Where React fits (mental model)
Without React (imperative): your code calls document.createElement, appendChild, className = … as data changes—easy to let DOM and in-memory state drift.
With React (declarative): you write functions that return a description of UI (React elements—plain objects: type, props, children). On each render, React compares the new tree to the previous one (reconciliation on the Fiber tree) and commits the minimal DOM mutations needed.
props + state
│
▼
render() ──► React element tree (descriptors)
│
▼
reconciliation (Fiber) ──► commit ──► DOM updates + effectsReact is not “the DOM”—it’s a scheduler + reconciler that owns updates to a DOM subtree (via react-dom). Concurrent React can interrupt low-priority rendering so input stays responsive (details).
4. Hydration — what actually happens
Problem: SSR (or SSG) sends HTML so the user sees content before JS is ready. That HTML is a snapshot: no React event handlers yet.
Hydration: when the client bundle runs, hydrateRoot/HydrationRoot (React 18+) walks the existing DOM, expects it to match what React would render for the same props/state snapshot, attaches internal Fiber state, registers event listeners, and from then on updates are incremental like a normal client app.
| Step | What happens |
|---|---|
| 1 | Server emitted HTML string (+ sometimes serialized data). |
| 2 | Browser paints visible content (good LCP / perceived perf). |
| 3 | JS loads → React hydrates root—reuse nodes where possible. |
| 4 | After hydration, state updates go through client React as usual. |
If server HTML ≠ first client render → hydration mismatch (warnings, broken nodes, duplicate UI). Common causes: Date.now(), Math.random(), window during render, suppressHydrationWarning misused, locale/timezone drift, or invalid HTML nesting that the parser “fixes” differently than React expects.
Next.js App Router note: React Server Components change the split: much UI never ships as client component JS—only client boundaries hydrate. See Next.js App Router for RSC vs “classic” SSR + client tree.
5. React core concepts (SDE3 checklist)
| Concept | One sentence |
|---|---|
| Component | Function (or class) that returns elements; capitalize in JSX. |
| Props | Inputs—treat as read-only; prefer key to reset state when identity changes. |
| State | Mutable over time via useState / useReducer; triggers re-render when updated. |
| Derived data | Compute in render (or useMemo when expensive)—don’t copy props to state without reason. |
Effects (useEffect) | Sync with systems outside React (fetch, subscriptions, timers)—not a replacement for event handlers. |
| Refs | Stable boxes for DOM nodes or values that must not trigger re-render on change. |
| Context | Dependency injection for trees—avoid one mega-context for app-wide churn. |
| Keys | Stable identity for list children—wrong keys → state leaks across rows. |
| Error boundaries | Catch render errors in children; event errors need try/catch inside handlers. |
| Strict Mode (dev) | Double-invokes some paths to surface non-idempotent effects. |
Deeper Fiber, transitions, Suspense: React — rendering & architecture.
Understanding
The browser does not know React—it only knows DOM + CSS + JS. React’s value is discipline: a single equation UI = f(state, props) with a reconciliation engine that batches and prioritizes work. Hydration is the bridge between fast static HTML and interactive client trees; get the contract wrong and you pay in bugs, not just perf.
Senior understanding
| Probe | Strong angle |
|---|---|
| “Why SSR at all?” | TTFB/FCP, SEO, edge caching—not magic if hydration cost dominates |
| “CSR-only?” | Simpler mental model; worse first meaningful paint on slow devices unless shell is tiny |
| “CSS-in-JS vs modules?” | Invalidation cost on hot paths; SSR style extraction; team consistency |
Operational: log hydration warnings in staging; treat serialized state like an API with versioning.
Diagram — layers you own in production
┌──────────────────────────────────────────────┐
│ Your product (Next.js / Remix / SPA) │
│ ├── Routing, data loading, meta-framework │
│ └── Client boundaries / server components │
├──────────────────────────────────────────────┤
│ React (scheduler, reconciler, hooks model) │
├──────────────────────────────────────────────┤
│ react-dom (commit to DOM, hydration) │
├──────────────────────────────────────────────┤
│ Browser: DOM + CSSOM + layout + paint … │
└──────────────────────────────────────────────┘See also
Last updated on
Spotted something unclear or wrong on this page?