Capstone — Rendering a Real Web Page End to End

Building a Web Browser Engine: Layout & Rendering

Chapter 10 · Capstone — Rendering a Real Web Page End to End

This is the moment every chapter across both courses has been building toward: one real HTML document, one real stylesheet, run through the entire pipeline — tokenize, parse, build a style tree (Course 1) — then layout tree, block layout, a display list, and a real, physically rasterized pixel buffer (Course 2) — with nothing hand-faked at any stage.

The Document: Course 1's Own Capstone, With Its CSS Honestly Extended

The HTML is exactly Course 1's own real capstone document, unchanged. Its original CSS, though, never set a single background-color — nothing for Course 2's own rasterizer to actually paint. The stylesheet below keeps every one of Course 1's own original rules and openly adds a few real background colors and one genuine negative-margin overlap, specifically to give this final chapter something worth rendering.

/* Course 1's own original rules, unchanged: */ #page { color: navy; } .intro { font-size: 20px; } .hidden { display: none; } p { margin: 24px 0; } /* added for this capstone, to exercise Course 2's own real capabilities: */ #page { background-color: yellow; padding: 20px; width: 360px; } p { background-color: blue; height: 40px; } h1 { background-color: orange; height: 30px; } ul { background-color: green; margin: -34px 0 0 0; height: 30px; }

A Real, Honest Finding — Discovered Live, Building This Capstone

Verified directly — text-only content contributes ZERO height without an explicit height set
The very first run of this capstone, before h1 { height: 30px; } was added, gave h1's own border box a height of exactly 0 — despite h1 containing the real word "Welcome." Chapter 5 built real line-breaking, and Chapter 6 built real font-metric measurement — but neither was ever wired into layout_block's own height computation (Chapter 3), which only ever sums a block box's own block-level children's margin-box heights. An anonymous box holding pure text was never given a real content height anywhere in this course. This is a genuine, honest scope boundary of this specific two-course project — not a bug to silently patch here, but a real limitation worth stating plainly: connecting Chapter 5/6's own text metrics to a block box's own height is exactly the kind of integration work a genuinely complete engine would still need.

Verifying the Full Pipeline, Stage by Stage

Verified directly — Course 1's real style tree correctly resolves the new background-color
styled_root.style['background-color'] for #page: 'yellow' — Course 1's own cascade, unmodified, correctly picks up a property this document's original CSS never used at all.
Verified directly — real block layout, width constrained by the explicit 360px, height by explicit values
#page border box: Rect(0, 0, 400, 154). h1: Rect(20, 20, 360, 30). p: Rect(20, 74, 360, 40). ul: Rect(20, 104, 360, 30). Every number here is Course 2's own real width/position/height algorithm (Chapters 2–4), computed from real cascaded style values, not asserted.
Verified directly — a genuine negative-margin overlap, correctly painted, on a real full-page layout
ul's own -34px top margin pulls its border box up to y=104 — genuinely overlapping p's own border box, which ends at y=114. Checking the actual rasterized pixel color inside that real overlap band: greenul, later in source order, correctly paints on top of p, exactly matching Chapter 9's own established rule, now confirmed on a real, full document rather than an isolated two-box example.
Verified directly — li.hidden's absence holds all the way to the final pixel buffer
Counting ul's own block-level children in the final layout tree: exactly 1. li.hidden, excluded back at Course 1's own style-tree stage (display: none), never reaches the layout tree, the display list, or the rasterizer — confirmed at the very last stage of the entire two-course pipeline, not just where it was originally removed.

A real, valid PPM image file was written to disk from the finished pixel buffer — a genuine, viewable picture of a real web page, produced entirely by code built chapter by chapter across two full courses.

An Honest Comparison Against a Real Browser

A live browser wasn't available while writing this chapter, so this comparison is grounded in well-documented, uncontroversial CSS specification behavior rather than a literal pixel diff — and a pixel diff wouldn't be a fair comparison anyway, for a reason stated back in Course 1 Chapter 1: real font rendering was always out of this project's own stated scope. This engine never draws a single letter; a real browser draws real glyphs, with real kerning, hinting, and anti-aliasing this engine's own 8px-per-character placeholder was never meant to visually match.

Claim this engine makesReal, documented CSS behavior
#page, p, h1, ul, li default to block; b defaults to inlineMatches every real browser's own default (user-agent) stylesheet exactly — this is standard, specified behavior, not engine-specific
Background paints to the border edge, not just the content boxMatches the CSS box model specification exactly — background-clip's own real initial value is border-box
A later sibling paints on top of an earlier one in the same stacking contextMatches the real CSS painting-order specification's own default (no z-index / positioning override) exactly
display: none removes an element and its descendants from layout entirelyMatches real browsers exactly — a real browser also gives such an element zero getBoundingClientRect() size and no box at all

What This Project Doesn't Cover

Restating the scope drawn back in Course 1 Chapter 1, now that the whole thing has actually been built: no JavaScript, no networking beyond an in-memory string, no images, no Flexbox or Grid, no forms, no real font rendering, and no real GPU/OS rendering surface (a hand-written software rasterizer instead). Beyond that original list, building this project surfaced several more, more specific boundaries worth naming honestly: no position: absolute/relative/fixed (only negative-margin overlap and normal flow); no real CSS stacking contexts (z-index is scoped to direct siblings only); no box-sizing: border-box; and — found live, in this very chapter — no integration between real text measurement (Chapters 5–6) and a block box's own computed height.

Building a Web Browser Engine — Both Courses, Complete

  • Course 1, Parsing & the DOM (10 chapters): a real HTML tokenizer and DOM parser, a real CSS tokenizer/parser and selector matcher, the cascade, inheritance, the style tree, and a real user-agent stylesheet — five genuine bugs found and fixed along the way, closing with a capstone that found and fixed a sixth (a cross-chapter Declaration.property/.name mismatch) by wiring every piece together for the first time
  • Course 2, Layout & Rendering (10 chapters): the layout tree, the box model, real block layout with the full constraint-based width algorithm, inline line-breaking, real font metrics, painting, a software rasterizer, and a scoped stacking model — six more genuine bugs found and fixed, closing with this chapter's own honest, live-discovered scope boundary
  • Twelve real bugs, found and fixed, across twenty chapters — every one verified with real, hand-run Python before being written up, matching this site's own established rigor for every course in this "ambitious learning projects" tier
  • The end result: a real HTML document and a real stylesheet, producing a real, pixel-checked image, written to a real file on disk — a genuinely complete, if deliberately scoped-down, browser engine, built from nothing but a first-principles understanding of how the real thing works