Chapter 12: The Mobile Web and the Move from Responsive to Adaptive
On January 9, 2007, Steve Jobs walked onto a stage in San Francisco and introduced the iPhone.
The presentation is now a museum piece, watched by every generation of product designers, but the most important thing about it for this book happens in a moment most people don’t remember. About forty-five minutes in, Jobs demonstrated the web browser. He typed a URL. The page loaded. He pinched and zoomed. He scrolled. He tapped a link. The page that came up wasn’t a stripped-down mobile version. It was the regular New York Times website, rendered at full desktop fidelity on a 3.5-inch screen.
This was new. Smartphones had existed before the iPhone — BlackBerry, Treo, Windows Mobile devices — but their browsers were uniformly bad. Most websites served those devices a separate, stripped-down version through a different URL (typically wap.example.com or m.example.com) because the device’s browser couldn’t render the full page reliably.
The iPhone shipped with WebKit. The browser was, with a few mobile-specific limitations, the same engine running on Apple’s desktop Safari. Pages built for desktop rendered. The bar for “mobile web” had moved overnight, and the rest of the web industry was about to spend a decade catching up.
This chapter is about that catching-up. The first response was a design pattern called responsive design, which dominated the 2010s. The second response, still unfolding, is something different — a shift from designing against the viewport to designing against the container. Each shift moved more of the layout responsibility into the platform itself, and the second shift turned components into first-class units of design context.
The m-dot Era
Section titled “The m-dot Era”Before responsive design, the dominant strategy for mobile was the m-dot — a separate mobile site served from a different subdomain.
A user visiting nytimes.com on a phone got redirected to m.nytimes.com. The mobile site had its own URL structure, its own HTML, often its own CMS templates, and a deliberately stripped-down feature set. The desktop site and the mobile site were two products, maintained in parallel, kept in roughly synchronized states by editorial discipline and a lot of manual coordination.
This worked, in the way most things that double the team’s workload work. It also produced a long list of recognizable problems. Shared URLs broke when one user pasted a desktop link to another user who was on mobile. Search engines indexed two versions of the same content and had to be told (through rel="canonical") which one was authoritative. New features had to be built twice. Designers had to maintain two visual languages. Mobile sites were almost always behind the desktop ones in capability, because the mobile team had half the resources and was treated as a secondary product. The user got a worse experience on the smaller screen.
The iPhone’s full-desktop browser made the m-dot model start to look strange. If the device could render the desktop site, why was it being shown a stripped-down version? The answer was that the device could render it, but the layout had been designed for a 1280-pixel viewport and the user was looking at it on 320 pixels. The page rendered. It just rendered badly.
The industry needed a way to ship one site that worked on every screen size.
Responsive Web Design
Section titled “Responsive Web Design”On May 25, 2010, Ethan Marcotte published an essay on A List Apart called Responsive Web Design.
Marcotte’s argument was specific and practical. He proposed that a single web page could adapt to different screen sizes through three techniques used together. The first was a fluid grid — layouts defined in proportional units (percentages) rather than fixed pixel widths, so columns expanded and contracted with the viewport. The second was flexible images — img { max-width: 100% } and similar techniques that let media scale with their containing column. The third was media queries — the CSS3 feature, recently shipped in browsers, that let stylesheets target specific viewport sizes:
@media (max-width: 768px) { .sidebar { display: none } .content { width: 100% }}None of these three techniques was new in 2010. Fluid layouts had been part of CSS since the beginning; flexible images were a one-line CSS rule; media queries had been in the CSS3 working draft for years and shipped in major browsers around 2009. What Marcotte did was name the pattern, give it a coherent design philosophy, and demonstrate it with a working example.
The essay turned into a book — Responsive Web Design, A Book Apart, June 2011 — and the book turned into a design movement. Within three years, responsive had become the default for new commercial websites. By the mid-2010s, the m-dot model was in retreat across the industry. Most of the major web publishers consolidated their mobile and desktop sites onto a single responsive codebase. Google announced in 2015 that mobile-friendly sites would rank higher in mobile search results, which removed any remaining commercial reason to keep an m-dot site running.
Marcotte’s contribution is one of the cleanest examples in this book of the naming matters dynamic. The techniques existed. The conversation didn’t. Once the conversation had a name, the field could coordinate around it.
The Viewport Meta Tag
Section titled “The Viewport Meta Tag”One small technical detail made responsive design actually work on phones, and it deserves its own paragraph because it’s the kind of thing the reader will encounter and not quite understand the history of.
Mobile browsers, including iPhone’s original Safari, defaulted to rendering pages at a wide assumed viewport (typically 980 pixels) and then scaling the whole page down to fit the device’s screen. This was a workaround for the era of desktop-only websites — the browser pretended to be desktop-sized so layouts wouldn’t break. The side effect was that a responsively designed site that defined a mobile breakpoint at max-width: 768px would never hit that breakpoint, because the browser was telling the page it had 980 pixels to work with.
The fix was a small meta tag in the document head:
<meta name="viewport" content="width=device-width, initial-scale=1">This told the browser to stop pretending and treat the device’s actual pixel width as the viewport. Apple introduced the tag in iPhone Safari in 2007; Android adopted it; the W3C eventually standardized it. The single line of HTML is what made every responsive design technique that followed actually function as intended on mobile devices.
Mobile First
Section titled “Mobile First”In 2011, Luke Wroblewski published a small book called Mobile First. The argument was a design discipline that ran adjacent to Marcotte’s technical pattern.
Wroblewski’s claim was that designing for mobile first, and treating desktop as a progressive enhancement, produced better designs in both directions. The constraints of the small screen — limited horizontal space, single-finger interaction, slow networks, intermittent attention — forced the designer to identify the essential content and the essential actions. Once those were right, the desktop layout was a relatively easy expansion of the same priorities. Designing the other direction tended to produce desktop layouts crammed with secondary elements that then had to be cut for mobile, often badly.
Mobile first became the dominant design discipline for most of the 2010s. The pairing with responsive design was natural. Marcotte’s pattern gave the field the technical mechanism; Wroblewski’s discipline gave it the design philosophy. The CSS media query syntax even tilted in mobile-first’s favor — starting from base styles (which applied on small screens) and then adding @media (min-width: 768px) rules for larger viewports produced cleaner stylesheets than the reverse.
Around this time, Jeremy Keith — a British developer, writer, and one of the most consistent voices in the progressive-enhancement community throughout the 2010s — was making a parallel argument that took the philosophy further. Progressive enhancement said you should design for the lowest-capability device (no JavaScript, slow network, small screen, limited input) and then layer additional capability on top as it became available. The mobile-first / responsive movement was, in many ways, progressive enhancement applied to layout. Keith’s blog adactio.com and his books (especially Resilient Web Design, 2016) are still some of the most useful reading in the field on what the platform’s progressive-enhancement story actually buys you.
The community around all this work was largely held together by Smashing Magazine, Vitaly Friedman and Sven Lennartz’s German design publication, which became the field’s most reliable source of long-form articles on responsive design, mobile-first patterns, and the practical CSS techniques that made both work. The conferences that grew out of that community (Smashing Conf, alongside An Event Apart and Brad Frost’s Atomic Design talks) shaped a generation of frontend designers.
The Limits of the Viewport
Section titled “The Limits of the Viewport”By the late 2010s, responsive design had become the default and the field started running into the limits of the technique itself.
The problem was structural. Media queries target the viewport — the size of the browser window. They have no awareness of the size of any individual element on the page. A sidebar component that needed to lay out one way at 200 pixels wide and another way at 600 pixels wide had no clean way to express that in CSS. The same component on the same page might be in a narrow column on one route and a wide column on another, and the media query had no way to tell the difference.
The workaround was to wire JavaScript into layout. Components would observe their own size with ResizeObserver (added to browsers around 2018), measure their containing element, and apply class names that triggered different stylesheets. This worked but it was hacky. CSS was supposed to handle layout; JavaScript was supposed to handle behavior; pushing layout decisions back into JavaScript inverted the original layering.
The deeper issue was that responsive design’s mental model was wrong for the kind of work the field was actually doing. Responsive design assumed the page was the unit of layout, and that the page’s relationship to the viewport was what determined layout decisions. By the late 2010s, frontend codebases were organized around components, not pages. The same component might appear in five different layouts in five different contexts on the same site, and the component’s correct layout depended on its container, not the viewport.
The field needed a way to ask CSS the question “how wide is the element I’m laying out inside?” rather than “how wide is the viewport?”.
Container Queries
Section titled “Container Queries”Container queries were proposed in 2015. They took seven years to ship.
The reason was technical. Container queries are hard to implement in a CSS engine. Most CSS layout calculations are top-down — the parent’s size determines the child’s size. A container query inverts the relationship: the child’s layout depends on the parent’s size, but the parent’s size might depend on the child’s content, creating a circular dependency the engine has to detect and resolve. The CSS Working Group spent years on the design, the browser teams spent more years on the implementation, and the feature finally shipped across Chrome, Safari, and Firefox in 2022 and early 2023.
What container queries look like in practice:
.card { container-type: inline-size; container-name: card;}
@container card (min-width: 400px) { .card-content { display: grid; grid-template-columns: 1fr 2fr; }}The container-type and container-name properties mark an element as a containment context — a region whose size can be queried by its descendants. The @container rule then applies styles based on the size of the nearest matching containment context, not the viewport.
The shift is small in syntax and large in architecture. A component that uses container queries owns its own layout responses. It doesn’t need to know what page it’s on, what column it’s in, or how the layout above it has decided to size things. It declares the layout invariants it cares about — when I’m at least 400 pixels wide, lay my content out in two columns — and the platform handles the resolution.
This is the same kind of move the rest of this book is going to keep arguing for. The component becomes responsible for its own behavior. The framework or page above it stops needing to coordinate. The platform provides the mechanism that lets the component answer questions about its own context.
Components as Units of Layout Context
Section titled “Components as Units of Layout Context”The architectural significance of container queries is the move from page-as-unit to component-as-unit.
In the responsive era, the unit of layout was the page. A page had a viewport, the viewport had breakpoints, the breakpoints triggered different styles, and the whole page coordinated its layout around them. The mental model worked because most of the web in 2010 was still organized around pages — a CMS produced templates, each template defined its layout, and each layout was responsive to the viewport in a more or less independent way.
The component model that took over in the 2010s broke this. A <UserCard> component might render in a sidebar at 240 pixels, in a feed at 600 pixels, in a modal at 480 pixels, and in a grid at 320 pixels — all on the same page, all responding to layouts above them, none of them under the page’s overall control. Responsive design’s viewport-based model couldn’t express this cleanly. Container queries can.
Anyone who has worked with bounded contexts in domain-driven design will recognize the shape of this shift. The component is now a bounded context for its own layout. It has invariants it owns and protects. It exposes a layout contract — give me a width, I’ll arrange myself — and the surrounding system is responsible only for honoring that contract, not for understanding the internals of how the component lays itself out.
This connects forward to several arguments the rest of the book will make. Part II’s chapters on the DOM as a context tree, on attributes as protocol, on events as a publish-subscribe bus — they’re all parts of the same picture. The platform now has the primitives to let components own their own behavior and context, and the architectural patterns we’ll build in Parts III and IV are about taking that seriously.
The mobile web forced the first move. Responsive design was the first answer. Container queries are the platform finishing the work.
What Comes Next
Section titled “What Comes Next”This chapter has been a brief detour from the framework chronology. We left MVC at Chapter 11. The next chapter picks the framework story back up with React’s deliberately controversial 2013 debut and what JSX, the virtual DOM, and the move from MVC’s two-way binding to UI-as-a-function-of-state changed about what frontend code looked like.
The mobile and responsive story will return in Part II, when we discuss the platform’s modern layout capabilities, and again in Part VIII, when we consider what cross-device delivery looks like for AI-generated UIs that have to ride anywhere — phone, watch, TV, whatever comes next.
Exercise: Audit One Component
Section titled “Exercise: Audit One Component”Pick a component in a codebase you’re familiar with — a card, a sidebar, a navigation bar, a form field, a media player. Anything that gets used in more than one place.
For your chosen component:
- List every place in the codebase or product where it appears.
- For each appearance, write down the approximate width of the container it sits inside.
- Does the component’s current layout work cleanly at each of those widths, or does it rely on the surrounding page knowing how to size things?
- If the component were rewritten to use container queries, what layout breakpoints would it declare for itself?
- After that rewrite, would any of the surrounding pages still need to coordinate layout around it?
The point is to feel the shift the chapter described. A component that owns its own layout becomes portable in a way that a page-coordinated component can’t be — and the moment the component is portable, the architecture above it gets simpler.