Layout on the web has cycled through five or six paradigms in thirty years. Each one looked permanent at the time. Here's the trail, with the code each era looked like — plus what actually arrived after the original 2023 cut of this post.
The initial web (mid-1990s)
CSS didn't exist yet. Styling was HTML attributes — bgcolor, font, align — applied directly on the elements you wanted to style.
1<body bgcolor="lightblue">
2 <h1 align="center">Hello, World!</h1>
3 <p><font size="3" color="red">This is an example paragraph.</font></p>
4</body>Browsers were Mosaic and early Netscape. Pages were documents with hyperlinks, not applications. Forms gave you any interactivity you got.
Frames
HTML 4 added <frameset> and <frame> for splitting the viewport into independently-scrollable sub-pages, each loading its own URL. They made it cheap to ship a fixed sidebar or header that didn't reload between navigations. They were also disastrous for accessibility, deep-linking, and SEO — bookmarking the URL gave you the frameset shell, not the content. HTML5 dropped them; <iframe> survived as the embedded-content story.
1<frameset cols="25%,75%">
2 <frame src="sidebar.html" />
3 <frame src="content.html" />
4</frameset>Tables for layout (late '90s–early '00s)
<table> was meant for tabular data, but it was also the only widely-supported way to align two boxes side by side in a row. The signature artefact of the era was the spacer GIF: a 1×1 transparent pixel stretched with width/height attributes to push neighbouring cells around.
1<table width="100%" cellspacing="0" cellpadding="0">
2 <tr>
3 <td colspan="2" height="50">Header</td>
4 </tr>
5 <tr valign="top">
6 <td width="20%">Sidebar</td>
7 <td width="80%">Content</td>
8 </tr>
9 <tr>
10 <td colspan="2" height="50">Footer</td>
11 </tr>
12</table>Tables nested into tables nested into tables. The markup-as-layout was hostile to screen readers and impossible to redesign without rewriting. Mobile killed it.
CSS floats
CSS finally gave us separation of structure and presentation. float: left was originally intended to wrap text around images, but you could co-opt it for multi-column layout — float a sidebar, float a main column, deal with the consequences. The signature cost was the clearfix hack: a floated child wouldn't extend its parent's height, so you needed an empty pseudo-element to clear the float.
1.clearfix::after {
2 content: "";
3 display: table;
4 clear: both;
5}display: flow-root (in all majors for years now) is the modern one-liner that retires clearfix entirely.
Bootstrap and jQuery (2011)
Bootstrap shipped a 12-column responsive grid as a CDN drop-in plus a kit of pre-styled components — navbars, modals, forms, alerts. jQuery papered over the IE quirks of XMLHttpRequest and DOM traversal. Together they ended the per-project bespoke layout-and-widgets phase.
1<link rel="stylesheet" href="https://cdn/bootstrap/3.3.7/css/bootstrap.min.css">
2<script src="https://cdn/jquery/3.2.1/jquery.min.js"></script>
3<div class="container-fluid">
4 <div class="row"><div class="col-xs-12">Header</div></div>
5 <div class="row">
6 <div class="col-xs-3">Sidebar</div>
7 <div class="col-xs-9">Main</div>
8 </div>
9</div>Bootstrap 5 (2021) dropped the jQuery dependency. By then jQuery itself was largely redundant — querySelector, fetch, and the framework era (React, Vue, Angular) had absorbed its job.
Flexbox and Grid (2014, 2017)
Flexbox stabilized around 2014–2015 and gave one-dimensional layout (a row or a column) with content-aware sizing, vertical centring that finally worked, and intuitive ordering. Grid hit W3C Recommendation in 2017 with simultaneous shipping in Chrome, Firefox, and Safari, and gave two-dimensional layout with named template areas and explicit tracks.
1.wrapper {
2 display: grid;
3 grid-template-columns: 1fr 3fr;
4 grid-template-areas:
5 "header header"
6 "sidebar main"
7 "footer footer";
8}Floats-for-layout became history. Bootstrap's 12-column grid became something you could build natively in two lines.
What actually arrived since 2022
The 2023 cut of this post speculated about the future. Here's what shipped:
- Container Queries (
@container, all majors 2022–23) — components can size themselves based on their parent's width, not the viewport. The biggest layout primitive since Grid. :has()(Safari 2022, Chrome and Firefox 2023) — the long-missing parent selector.- Subgrid (Firefox 2019, Safari 2022, Chrome 2023) — child grids inheriting the parent's tracks. Made nested grids actually usable.
- Cascade Layers (
@layer, all majors 2022) — explicit precedence between framework, override, and utility CSS. - View Transitions API (Chrome 2023, Safari 2024) — animated state transitions between DOM updates, including cross-document since Chromium 126.
- Scroll-driven animations (Chromium 2023, others behind flag) — bind animations to scroll position without JS.
- Anchor positioning (
anchor-name, Chromium 2024) — popovers and tooltips positioned relative to other elements without per-frame JS measurement.
What didn't pan out: WebAssembly and Houdini
The 2023 version of this post speculated about WebAssembly replacing HTML/CSS for layout and CSS Houdini opening the rendering engine to userland. Three years on:
WebAssembly is mainstream — Figma, Adobe Photoshop on the Web, language runtimes, games — but for application cores, not for layout. Replacing the DOM means re-implementing accessibility, focus management, copy-paste, find-in-page, and SEO. That gravity is enormous, and the apps that did break out of it accepted the cost because their value isn't the document model.
CSS Houdini largely stalled. The Properties and Values API (@property) shipped in all majors and is genuinely useful for typed custom properties. The Layout API and Paint API never reached cross-browser parity, and the "ecosystem of custom CSS implementations" the spec promised did not materialize.
The pattern in both cases: the platform absorbs what frameworks used to provide. Container Queries did what we used JS resize observers for. :has() did what we used class-toggling for. View Transitions did what we used FLIP libraries for. The future of layout has, so far, looked more like richer primitives in the platform than escape hatches around it.