Building layouts that adapt to any screen — mobile-first thinking, relative units, fluid containers, responsive images, media queries, breakpoints, and responsive navigation
When the web was young, almost everyone browsing it sat in front of a desktop computer with a large monitor. Designers could safely assume a wide, predictable screen. That world is gone. Today the same HTML page might open on a 375-pixel phone, a 768-pixel tablet, a 1440-pixel laptop, or a 2560-pixel desktop monitor — sometimes within the same hour, on the same person's devices. A layout that only works at one of these sizes fails everywhere else.
This chapter teaches you how to build pages that adapt. You will learn why fixed, pixel-locked layouts break on small screens, how to think mobile-first instead of designing for desktop and patching mobile afterward, how to use CSS units that scale instead of units that are locked in place, how to make images resize without overflowing their containers, how to write media queries that apply different styles at different screen widths, how to choose breakpoints based on your content rather than guesswork, how to adapt navigation for narrow screens, and how to test all of it using your browser's built-in tools. By the end of the chapter, the pages you build will work as well on a phone in someone's pocket as they do on a desktop monitor across a room.
Imagine the same HTML file opened on three different screens: a phone 375 pixels wide, a tablet 768 pixels wide, and a desktop monitor 1440 pixels wide. With no responsive CSS at all, what happens to a three-column layout designed for the desktop width when it loads on the phone? Why does simply shrinking everything proportionally, the way a photocopier shrinks a page, not actually solve the problem? By the end of this chapter you will be able to answer both questions with specific CSS tools, not just general impressions.
By the end of this chapter, you should be able to:
em, rem, %, vw, vh, and ch — appropriately for different sizing tasks.width and max-width together.max-width: 100%, height: auto, and the srcset attribute.min-width and explain other media features such as prefers-color-scheme.max-width and Fluid ContainersThe width-plus-max-width pattern; why max-width enables fluid behavior that width alone cannotWhen the web was young, almost everyone who used it sat in front of a desktop computer with a large monitor. Web pages were designed for fixed, wide screens. Designers and developers could assume that a user's browser window was probably at least 800 pixels wide, and later 1024 pixels wide. Pages were built with hard-coded pixel measurements because the screen was predictable.
That world no longer exists. Today, people browse the web on smartphones, tablets, laptops, desktop monitors, smart TVs, e-readers, and devices that did not exist a decade ago. A smartphone screen might be 320 to 430 pixels wide. A tablet might be 768 to 1024 pixels. A laptop might be 1200 to 1440 pixels. A desktop with a wide monitor might be 1600 to 2560 pixels or more. No single fixed layout can serve all of these well.
Responsive design is the practice of building websites that detect and adapt to the user's screen size and environment, so that the layout, text, images, and navigation all remain readable and usable no matter where someone opens the page. The term was defined and popularized by web designer Ethan Marcotte, who described three core ingredients: fluid grids, flexible images, and media queries. These three ideas remain central today.
A website that is not responsive forces users on small screens to scroll horizontally, zoom in and out to read text, squint at tiny navigation menus, and pinch to hit buttons. These are serious usability failures. In many parts of the world, mobile devices are the primary or only way people access the web. Building a site that only works well on a large screen means excluding or frustrating a large part of the audience.
Responsive design is also an accessibility issue. A site that requires zooming, horizontal scrolling, or tapping tiny targets is harder to use for people with motor disabilities, vision differences, or older devices. The accessibility principles from earlier chapters and the layout principles in this one work toward the same goal: a page that anyone can use, on whatever device they have.
Before writing any responsive CSS, it helps to understand the range of devices that visit websites.
| Device Category | Typical Viewport Width | Notes |
|---|---|---|
| Mobile phones | 320px – 430px (portrait) | 375px and 390–430px are common for current phones; 320px covers older or budget devices |
| Tablets | 600px – 1024px | About 768–820px in portrait, 1024px or wider in landscape; varies by manufacturer |
| Laptops | 1200px – 1440px | Measured at 100% browser zoom; some users zoom in or out, changing the effective viewport |
| Desktop monitors | 1440px – 2560px+ | Wide monitors can exceed 3000px; max-width containers matter most here |
These numbers describe the viewport, which is the visible area of the browser window, not necessarily the full screen resolution. A user can resize their browser window, which changes the viewport. This range from 320 to 2560-plus pixels is enormous. A layout that fills a 1400-pixel screen comfortably will be completely unusable at 375 pixels if no responsive adjustments are made.
There is also the concept of pixel density. Modern devices have high-resolution retina or HiDPI screens where one CSS pixel does not correspond to one physical hardware pixel. On these screens, the browser scales content automatically, but images that are not sized appropriately may appear blurry. Section 17.6 returns to this when discussing the srcset attribute.
There are two approaches to building responsive layouts. Desktop-first means you design and code the full wide-screen layout first, then add CSS to override it for smaller screens. Mobile-first means you design and code the narrow mobile layout first, then add CSS to enhance it for wider screens.
Mobile-first is the stronger approach, and it is what professional developers use by default. Writing CSS in a mobile-first way means your base styles are the simplest version of the layout: a single column, readable text, accessible buttons, no complex positioning. This is correct behavior for small screens. Then, as the screen gets wider, you layer in enhancements using media queries.
This is technically cleaner because you are progressively adding complexity rather than trying to undo complexity. It is also easier to maintain because the fallback behavior — what happens on the smallest screen, or in the least capable browser — is always the base stylesheet, which is simple and reliable. Desktop-first thinking often produces code where the base styles contain a complex multi-column layout, and the developer has to override many properties at smaller breakpoints to collapse everything back to a single column. This leads to more overrides, more specificity conflicts, and harder debugging.
flex-direction: column. A min-width: 768px media query switches to flex-direction: row. The simplest case is the default; complexity is added only when there is room for it.flex-direction: row. A max-width: 767px media query overrides back to flex-direction: column. The complex case is the default, and the simple case is an override./* Base styles: cards stack vertically on mobile */
.card-row {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
/* At wider screens, switch to horizontal row */
@media (min-width: 768px) {
.card-row {
flex-direction: row;
}
}
/* Base styles: three columns on desktop */
.card-row {
display: flex;
flex-direction: row;
gap: 1.5rem;
}
/* At narrow screens, override to stack */
@media (max-width: 767px) {
.card-row {
flex-direction: column;
}
}
All examples in this chapter follow the mobile-first approach: base styles target the narrowest screens, and min-width media queries layer in enhancements as the viewport widens.
A key tool of responsive design is using units that scale with the user's environment instead of units fixed at a specific number of pixels.
The px unit in CSS is an absolute unit tied to a specific physical size, calibrated to the device. On most screens, 16px is the default browser body font size. However, pixels do not scale when users change their browser zoom level or default font size. If a user has set their browser font size to 20px for readability, font-size: 16px ignores that preference and forces the smaller size. This is an accessibility concern. Pixels are also inflexible for layout: a column that is 600px wide will overflow a 375px phone screen.
em UnitThe em unit is relative to the font size of the current element. If an element has font-size: 20px, then 1em equals 20px within that element, 2em equals 40px, and 0.5em equals 10px. em units are useful for spacing that should scale proportionally with text, such as padding inside buttons. However, em values can compound when elements are nested, which makes them harder to reason about across deep nesting.
rem UnitThe rem unit stands for root em. It is relative to the font size of the root element — the html element. Since the default browser body font size is typically 16px, 1rem equals 16px on most browsers. Unlike em, rem does not compound through nesting: 1rem always means the same thing no matter how deep inside the HTML the element lives. rem also respects browser font size preferences, which is important for accessibility.
body {
font-size: 1rem; /* 16px at default browser settings */
line-height: 1.6;
}
h1 {
font-size: 2rem; /* 32px at default */
margin-bottom: 1rem;
}
p {
font-size: 1rem;
margin-bottom: 1rem;
}
.button {
padding: 0.75rem 1.5rem;
font-size: 1rem;
}
Percentage units are relative to the parent element's size. width: 50% means the element takes up half its parent's width. This is useful for fluid layouts where elements should fill available space proportionally.
.container {
width: 90%; /* 90% of the viewport width */
max-width: 1200px; /* but never wider than 1200px */
margin: 0 auto; /* centered */
}
Viewport units are relative to the viewport size — the visible browser area. vw is one percent of the viewport width; 100vw is the full width. vh is one percent of the viewport height; 100vh is the full height. Viewport units are useful for full-screen sections, hero images, and large typographic elements.
/* A hero section that fills the full viewport height */
.hero {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
/* Large display text that scales with the screen */
.display-text {
font-size: 5vw;
}
Be careful with vw on text. 5vw on a 1400px screen produces 70px text, which may suit a hero heading. On a 375px phone, 5vw produces only 18.75px, which may also be fine — but check the result on both ends of the range. Very small or very large vw values on text can produce unreadably tiny or disproportionately large text.
ch UnitThe ch unit is equal to the width of the 0 character in the current font. This is surprisingly useful for setting readable line widths. A comfortable reading line is generally between 45 and 75 characters wide. max-width: 65ch on a paragraph container creates a readable measure that also scales with the font size.
.article-body p {
max-width: 65ch;
}
| Unit | Best Used For |
|---|---|
rem | Font sizes, spacing, and most general sizing. Scales with browser preferences. |
% | Widths of containers and layout elements that should fill available space. |
px | Fine details like borders, shadows, or very small decorative sizes needing pixel precision. |
vw / vh | Full-screen sections, hero areas, and viewport-sized containers. |
em | Spacing directly tied to local text size, such as padding inside a component. |
ch | Readable maximum line lengths for body text. |
max-width and Fluid ContainersA fundamental tool of responsive layout is the pattern of setting a fluid width with a maximum cap. Without any responsive thinking, you might write width: 1200px. This works on wide screens, but on a 375px phone the container overflows the viewport by 825 pixels. The page becomes unusable.
.container {
width: 90%;
max-width: 1200px;
margin: 0 auto;
}
This container takes up 90% of the available width — which on a phone is 90% of 375px, giving roughly 338px — but grows no wider than 1200px on large screens. The margin: 0 auto centers it horizontally. This pattern is the foundation of almost every responsive layout: the container is always fluid and proportional, but never so wide that it becomes hard to read on large monitors.
max-width Instead of widthSetting width: 1200px locks the element at exactly 1200px. Setting max-width: 1200px allows the element to be narrower than 1200px when the screen is smaller, while still preventing it from growing beyond 1200px on wide screens. This is the difference between a fixed layout and a fluid one.
/* This blocks responsive behavior */
.container {
width: 1200px; /* never changes */
}
/* This enables responsive behavior */
.container {
width: 100%; /* takes all available space */
max-width: 1200px; /* but no wider than this */
padding: 0 1.5rem; /* horizontal breathing room */
margin: 0 auto; /* centered */
}
The padding: 0 1.5rem adds horizontal padding so that on a small screen the text does not press directly against the edges of the screen. This is an important usability detail that is easy to forget.
Images are one of the most common places where layouts break on small screens. An image that is 800 pixels wide will overflow a 375-pixel phone if no CSS handles it.
The simplest and most important rule for responsive images is:
img {
max-width: 100%;
height: auto;
display: block; /* prevents small gap below image in some browsers */
}
max-width: 100% prevents an image from growing wider than its container. On a phone where the container is 338px, a 1200px image will scale down to 338px. height: auto keeps the aspect ratio correct as the width changes, so the image does not appear squashed or stretched. Many developers include this rule in their global base styles so it applies to every image on every page automatically.
width and height Attributes in HTMLIt is good practice to include width and height attributes on img elements in your HTML, even when CSS is controlling the display size. These attributes let the browser reserve the correct amount of space in the layout before the image loads, preventing a visual jump known as layout shift.
<img
src="images/hero.jpg"
alt="Students working together at a library table"
width="1200"
height="600"
>
The HTML attributes define the aspect ratio. The CSS can still override the display size, but the browser uses the ratio from the attributes to hold space correctly.
srcset AttributeOn high-resolution (retina or HiDPI) screens, a single image displayed at a given CSS pixel size may look blurry if the image file itself does not have enough pixels. A screen with a 2x pixel ratio needs twice as many image pixels per CSS pixel to look sharp. The srcset attribute on img allows the browser to choose from a list of image sources based on the screen's pixel density or the available layout width.
At an introductory level, the two-image version is the most practical:
<img
src="images/photo-800.jpg"
srcset="images/photo-800.jpg 1x, images/photo-1600.jpg 2x"
alt="A courtyard with trees and benches"
width="800"
height="450"
>
The browser uses photo-800.jpg on standard displays and photo-1600.jpg on high-resolution displays. This improves visual quality without forcing every user to download a larger file. A deeper treatment of srcset with width descriptors and sizes attributes is a topic for more advanced study, but the 1x/2x pattern is a practical starting point.
Background images set with CSS, such as background-image: url(...), also need responsive attention. They can be sized with background-size: cover to fill their container regardless of size, which is the most common technique for hero background images.
.hero {
background-image: url("images/hero-background.jpg");
background-size: cover;
background-position: center;
height: 60vh;
}
background-size: cover ensures the image always covers the entire container, cropping if necessary, but never leaving empty space. This works well for decorative backgrounds, though important content should not be embedded inside images used as backgrounds — screen readers cannot read text baked into an image.
A media query is a CSS rule that applies certain styles only when specific conditions about the user's device or browser environment are true. The most common use of media queries is to detect viewport width and apply different layout styles at different sizes. This is the core mechanism of responsive CSS.
@media (condition) {
/* Styles that apply only when the condition is true */
}
The most important condition for layout is min-width for mobile-first design, or max-width for desktop-first. Mobile-first uses min-width, which means "apply these styles when the viewport is at least this wide":
/* Base styles apply to all screens (mobile first) */
.nav-links {
display: none; /* hidden on mobile */
}
/* At 768px and wider, show the navigation */
@media (min-width: 768px) {
.nav-links {
display: flex;
}
}
Everything inside the @media block is normal CSS. Selectors, properties, values — they all work exactly as in the rest of your stylesheet. The media query is just a condition wrapper.
/* Mobile base: single column layout */
.content-grid {
display: flex;
flex-direction: column;
gap: 2rem;
}
.sidebar {
background-color: var(--color-surface);
padding: 1.5rem;
border-radius: 8px;
}
/* Tablet and above: two-column layout */
@media (min-width: 768px) {
.content-grid {
flex-direction: row;
}
.sidebar {
width: 280px;
flex-shrink: 0;
}
}
/* Wide desktop: adjust spacing */
@media (min-width: 1200px) {
.content-grid {
gap: 3rem;
}
}
There are two common ways to organize media queries. One approach places all media queries together at the bottom of the stylesheet, grouped by breakpoint. Another approach places media queries directly after the base styles for each component they modify. Both are valid. For beginners, grouping media queries near the styles they modify makes it easier to understand what changes at each breakpoint.
/* Navigation */
.nav {
display: flex;
align-items: center;
padding: 1rem var(--space-page-padding);
background-color: var(--color-nav-bg);
}
.nav-menu {
display: none; /* hidden hamburger area on mobile */
gap: 2rem;
}
.nav-hamburger {
display: block; /* visible on mobile */
cursor: pointer;
}
@media (min-width: 768px) {
.nav-menu {
display: flex; /* show full menu on tablet and above */
}
.nav-hamburger {
display: none; /* hide hamburger button on tablet and above */
}
}
min-width and max-width are the most commonly used conditions, but media queries can test other things. orientation: portrait matches when the height is greater than the width; orientation: landscape matches when the width is greater than the height.
@media (orientation: landscape) {
.hero {
height: 50vh; /* shorter in landscape to leave room for content */
}
}
prefers-color-scheme: dark matches when the user's operating system is set to dark mode.
@media (prefers-color-scheme: dark) {
:root {
--color-background: #1a1a2e;
--color-text: #e8e8f0;
--color-surface: #2a2a3e;
}
}
prefers-reduced-motion: reduce matches when the user has requested less motion or animation in their system settings.
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
These preference-based media queries are important for accessibility. Respecting a user's system settings — their color preference, their motion tolerance — is a form of inclusive design that costs only a few lines of CSS.
A breakpoint is a specific viewport width at which your layout changes in a meaningful way. A breakpoint is the value you put inside min-width or max-width in a media query.
There is no universal list of required breakpoints. Breakpoints should be chosen based on where your specific content needs to change, not based on matching specific device models. That said, the following ranges are commonly useful as starting points:
| Range | Label | Typical Use |
|---|---|---|
| Below 600px | Small mobile | Base mobile styles |
| 600px – 767px | Large mobile / small tablet | Sometimes a distinct step |
| 768px – 1023px | Tablet | Two-column layouts, expanded navigation |
| 1024px – 1279px | Small laptop | Wider containers, more columns |
| 1280px and above | Desktop | Full multi-column layouts |
| 1440px and above | Wide desktop | Max-width containers become visible |
These numbers are not locked. Your project might only need two or three breakpoints. A simpler site with clean semantic HTML and a fluid container might only need one or two media queries.
The most reliable way to find the right breakpoints for your layout is to resize your browser window and watch your content. When the layout starts to look uncomfortable — when text gets too narrow or too wide, when columns become cramped, when navigation items start crowding — add a breakpoint there. Do not add breakpoints just because a popular device has a certain width. Add them because your content needs them.
/* Base: single column, narrow screens */
.layout {
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 1rem;
}
/* Two columns when there is room */
@media (min-width: 720px) {
.layout {
flex-direction: row;
padding: 2rem;
}
}
/* Widen the container and add more spacing */
@media (min-width: 1100px) {
.layout {
gap: 3rem;
padding: 2rem 4rem;
}
}
Some developers add many breakpoints — targeting every device size they can think of — and end up with a stylesheet that is difficult to maintain. It is better to have three thoughtful breakpoints that cover most users well than to have fifteen breakpoints that each adjust tiny details. Start with one or two breakpoints and add more only when the content clearly needs them.
Building a responsive layout without testing it at different sizes is like building a bridge without measuring. Testing is not optional, and it does not have to be complicated.
Every major browser's developer tools include a responsive preview mode. In Chrome, Firefox, and Edge, you can open the developer tools and click the device toolbar icon (or press Ctrl+Shift+M on Windows/Linux, Cmd+Shift+M on macOS). In this mode, you can set a specific pixel width by typing a number, drag the edge of the preview to resize freely while watching the layout adjust, select from a list of preset device sizes, change orientation between portrait and landscape, and toggle the display pixel ratio to simulate retina screens.
This is the fastest and most reliable way to test a responsive layout during development. Resize the window slowly from narrow to wide, watching carefully for any point where the layout breaks, text overflows, or elements collide.
Developer tools responsive mode is very helpful, but it does not perfectly replicate how a real phone renders a page. When possible, test on at least one actual smartphone by opening your site on the local network. Browsers on real devices sometimes render fonts, scrolling, and touch targets differently from what the desktop simulation shows. A common method: start a local development server, find your computer's local IP address, and type that address in your phone's browser, making sure both devices share the same Wi-Fi network.
| Problem | Likely Cause |
|---|---|
| Horizontal scrolling on mobile | An element with a fixed pixel width wider than the viewport, or content with overflow: visible extending off-screen. Try overflow-x: hidden on body to confirm, then find and fix the source element. |
| Text too small to read | Font sizes set too small in the base stylesheet, or px-based font sizes that fail to scale with user preferences. |
| Images overflowing their container | max-width: 100%; height: auto not applied to img. |
| Navigation breaking at certain widths | The breakpoint value does not match where the navigation naturally starts to overflow. |
| Content cut off on mobile | A fixed-width parent element that does not resize with the viewport. |
The viewport meta tag is a critical piece of HTML that is required for responsive design to work correctly on mobile devices.
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Without this tag, mobile browsers shrink the entire page down to simulate a desktop viewport — typically around 980 pixels wide — and then display it at that tiny size, leaving the user to zoom in. This behavior comes from the early days of smartphones, when websites were not designed for small screens and mobile browsers tried to helpfully display them anyway by shrinking everything.
With this tag, you are telling the browser: this page is designed for mobile, set the viewport width to the actual device width, and display at 1:1 scale without zooming. width=device-width sets the viewport width to the physical width of the device. initial-scale=1.0 sets the initial zoom level to 100%.
Without this tag, your media queries will still fire at their min-width values — but based on the simulated desktop viewport, not the real device width. Your beautifully crafted mobile layout at 375px will never appear on a real iPhone because the browser thinks it is operating at 980px. The viewport meta tag is what makes CSS media queries respond to the real device width. Every responsive HTML document should have this tag in the <head>. It is included in the standard HTML skeleton taught in Chapter 5.
Some developers add user-scalable=no to the viewport meta tag to prevent zooming: content="width=device-width, initial-scale=1.0, user-scalable=no". This is incorrect and should never be done. Users who need to zoom in — including people with low vision — have the right to do so. Disabling zoom is an accessibility violation, not a design choice.
Let us work through building a page that combines responsive principles from this chapter: a simple page with a sticky header, a hero section, a three-card content section, and a footer. On mobile, the cards stack vertically. On tablets and above, they display in a row.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive Page Example</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<header class="site-header">
<div class="header-inner">
<a href="index.html" class="site-logo">Learning Site</a>
<nav class="main-nav" aria-label="Main navigation">
<ul class="nav-list">
<li><a href="index.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="lessons.html">Lessons</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</nav>
</div>
</header>
<main>
<section class="hero">
<div class="hero-inner">
<h1>Learn at Your Own Pace</h1>
<p>Resources, guides, and lessons for curious students.</p>
<a href="lessons.html" class="button-primary">Browse Lessons</a>
</div>
</section>
<section class="features">
<div class="container">
<h2>What You Will Find</h2>
<div class="card-row">
<article class="card">
<h3>Lessons</h3>
<p>Step-by-step guides on web development, programming, and computer science foundations.</p>
</article>
<article class="card">
<h3>Resources</h3>
<p>Curated links, references, and tools for every topic in the curriculum.</p>
</article>
<article class="card">
<h3>Projects</h3>
<p>Hands-on mini-projects that practice skills in real, practical contexts.</p>
</article>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="container">
<p>© 2025 Learning Site. All rights reserved.</p>
</div>
</footer>
</body>
</html>
The viewport meta tag is present in the <head>. This is essential for responsive design and was covered in Section 17.11.
/* =========================================
CSS Variables (Chapter 18 preview)
========================================= */
:root {
--color-background: #ffffff;
--color-text: #1a1a2e;
--color-text-muted: #555566;
--color-surface: #f4f4f8;
--color-border: #dddde8;
--color-header-bg: #ffffff;
--color-hero-bg: #1a1a2e;
--color-hero-text: #ffffff;
--color-primary: #4a6cf7;
--color-primary-hover: #3a5ce7;
--space-xs: 0.5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--page-padding: 1.25rem;
--container-max: 1200px;
}
/* =========================================
Base / Reset
========================================= */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Georgia, "Times New Roman", serif;
font-size: 1rem;
line-height: 1.7;
color: var(--color-text);
background-color: var(--color-background);
}
img {
max-width: 100%;
height: auto;
display: block;
}
a {
color: var(--color-primary);
}
/* =========================================
Utility
========================================= */
.container {
width: 100%;
max-width: var(--container-max);
margin: 0 auto;
padding: 0 var(--page-padding);
}
/* =========================================
Header
========================================= */
.site-header {
background-color: var(--color-header-bg);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 0;
z-index: 100;
}
.header-inner {
display: flex;
align-items: center;
justify-content: space-between;
height: 60px;
max-width: var(--container-max);
margin: 0 auto;
padding: 0 var(--page-padding);
}
.site-logo {
font-size: 1.125rem;
font-weight: 700;
text-decoration: none;
color: var(--color-text);
}
/* Navigation: simplified version without hamburger for this example */
.nav-list {
list-style: none;
display: flex;
gap: var(--space-lg);
}
.nav-list a {
text-decoration: none;
color: var(--color-text-muted);
font-size: 0.9375rem;
transition: color 0.2s ease;
}
.nav-list a:hover {
color: var(--color-primary);
}
/* On mobile, hide the nav list for simplicity in this base example */
.main-nav {
display: none;
}
@media (min-width: 640px) {
.main-nav {
display: block;
}
}
/* =========================================
Hero Section
========================================= */
.hero {
background-color: var(--color-hero-bg);
color: var(--color-hero-text);
padding: var(--space-xl) var(--page-padding);
text-align: center;
}
.hero-inner {
max-width: 680px;
margin: 0 auto;
}
.hero h1 {
font-size: 2rem;
line-height: 1.2;
margin-bottom: var(--space-sm);
}
.hero p {
font-size: 1.125rem;
margin-bottom: var(--space-lg);
color: rgba(255, 255, 255, 0.8);
}
.button-primary {
display: inline-block;
background-color: var(--color-primary);
color: #ffffff;
padding: 0.75rem 1.75rem;
border-radius: 6px;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
transition: background-color 0.2s ease;
}
.button-primary:hover {
background-color: var(--color-primary-hover);
color: #ffffff;
}
@media (min-width: 768px) {
.hero {
padding: 5rem var(--page-padding);
}
.hero h1 {
font-size: 3rem;
}
}
/* =========================================
Features Section
========================================= */
.features {
padding: var(--space-xl) 0;
background-color: var(--color-surface);
}
.features h2 {
font-size: 1.5rem;
margin-bottom: var(--space-lg);
text-align: center;
}
/* Cards: single column on mobile */
.card-row {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.card {
background-color: var(--color-background);
border: 1px solid var(--color-border);
border-radius: 8px;
padding: var(--space-md);
}
.card h3 {
font-size: 1.125rem;
margin-bottom: var(--space-xs);
color: var(--color-text);
}
.card p {
color: var(--color-text-muted);
font-size: 0.9375rem;
line-height: 1.6;
}
/* Cards: three-column row on tablet and above */
@media (min-width: 768px) {
.card-row {
flex-direction: row;
}
.card {
flex: 1; /* each card takes equal share of space */
}
.features h2 {
font-size: 1.75rem;
}
}
/* =========================================
Footer
========================================= */
.site-footer {
background-color: var(--color-text);
color: rgba(255, 255, 255, 0.7);
padding: var(--space-lg) 0;
text-align: center;
font-size: 0.875rem;
}
.main-nav is hidden (display: none). .hero h1 is 2rem. .card-row is a vertical flex column. .container fills 100% of the width with 1.25rem padding on each side.@media (min-width: 640px) query fires. .main-nav becomes visible and navigation links appear in the header.@media (min-width: 768px) query fires. .hero gets more padding (5rem). .hero h1 grows to 3rem. .card-row switches from column to row, and the three cards appear side by side..container's max-width: 1200px activates. Content stops growing wider, and the site is centered on the page.Answer these questions before beginning the full review questions. They check basic understanding, not deep analysis.
rem respect a user's browser font size preferences while px does not?user-scalable=no on the viewport meta tag does prevent users from zooming, but it does so by removing an accessibility feature that people with low vision rely on. A responsive layout should remain usable and attractive at the intended sizes without needing to strip away the user's ability to zoom.Read each code block and answer the questions that follow.
.hero-image {
width: 100%;
max-width: 960px;
height: auto;
}
width: 100% do to this image on a narrow phone screen?max-width: 960px do on a 1400px wide monitor?height: auto important for this image?.description {
font-size: 1.125rem;
max-width: 65ch;
line-height: 1.7;
}
@media (min-width: 900px) {
.description {
font-size: 1.25rem;
}
}
px?max-width: 65ch limit?.description have? At 950px?.grid {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
@media (min-width: 640px) {
.grid {
flex-direction: row;
flex-wrap: wrap;
}
.grid > * {
flex: 1 1 200px;
}
}
@media (min-width: 1024px) {
.grid {
gap: 2.5rem;
}
}
Trace through the following sequence of breakpoints and describe what the page looks like at each width.
.page-title {
font-size: 1.5rem;
text-align: center;
}
@media (min-width: 768px) {
.page-title {
font-size: 2.5rem;
text-align: left;
}
}
@media (min-width: 1200px) {
.page-title {
font-size: 3.5rem;
}
}
| Viewport Width | font-size | text-align |
|---|---|---|
| 375px | ? | ? |
| 768px | ? | ? |
| 900px | ? | ? |
| 1200px | ? | ? |
| 1440px | ? | ? |
Look at the following HTML and CSS. Predict what the layout looks like at 500px wide and at 900px wide before checking in a browser.
<div class="panel-group">
<div class="panel">Alpha</div>
<div class="panel">Beta</div>
</div>
.panel-group {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
background-color: #f0f0f0;
}
.panel {
background-color: #3a5ce7;
color: white;
padding: 2rem;
text-align: center;
border-radius: 6px;
}
@media (min-width: 768px) {
.panel-group {
flex-direction: row;
}
.panel {
flex: 1;
}
}
Each code sample below has a problem. Identify the problem and explain how to fix it.
<head>
<title>My Portfolio</title>
<link rel="stylesheet" href="css/style.css">
</head>
The page looks fine in a desktop browser but is zoomed out and tiny on a real phone, and the mobile media queries are not activating correctly. What is missing and what should be added?
.hero-photo {
width: 1200px;
height: auto;
}
On a phone, the hero image is forcing horizontal scrolling. How should this be fixed?
/* Mobile: cards should stack */
.cards {
display: flex;
flex-direction: row; /* should be column on mobile */
}
/* Desktop: row */
@media (min-width: 768px) {
.cards {
flex-direction: row;
}
}
What is wrong with this code from a mobile-first perspective, and what is the correct fix?
body {
font-size: 12px; /* feels like it prevents overflow */
}
h1 {
font-size: 36px;
}
p {
font-size: 14px;
}
A student has used px for all font sizes. Identify two problems this creates and rewrite using rem.
.sidebar from display: none to display: block, and changes .main-content from width: 100% to width: calc(100% - 320px).--page-padding variable set to 1rem by default, a --container-max variable set to 1140px, a .container class using both variables, and that increases --page-padding to 2rem at 1024px and above.Requirements: Use mobile-first media queries with min-width conditions. Use rem units for font sizes and spacing. Use a fluid container with max-width and margin: 0 auto. Include the viewport meta tag. Apply max-width: 100%; height: auto to any images. Use at least two breakpoints. Use CSS custom properties for colors and spacing values.
max-width container is centered at 1200px and above.Responsive design and accessibility are closely related. Review your responsive landing page against this checklist.
| Check | What to Verify |
|---|---|
| Text size | Are rem units used for font sizes so text scales with browser font preferences? |
| Touch targets | Are buttons and links at least 44px tall (using min-height or padding) so they are easy to tap on a phone? |
| Contrast | Does text color have sufficient contrast against the background at all breakpoints? (4.5:1 is the recommended minimum for normal-sized body text.) |
| Keyboard navigation | Can the navigation be reached and activated using only a keyboard (Tab and Enter)? |
| Image alt text | Do all images have meaningful alt attributes? |
| Zoom behavior | Does the viewport meta tag avoid user-scalable=no? Users must always be allowed to zoom. |
| Orientation | Does the page work in both portrait and landscape? Locking to one orientation can exclude users with a fixed-mounted device. |
These questions combine material from Chapters 11 through 17.
box-sizing: border-box interact with fluid widths? If an element has width: 100% and padding: 0 1.5rem, does the padding reduce the visible content width when box-sizing is border-box? Explain.flex-direction: column to flex-direction: row at 768px. What other Flexbox property in the desktop media query ensures each card takes an equal share of the row?rem preferred over px for font-size in a responsive stylesheet?1fr 1fr 1fr. On mobile you want a single column. Write the complete CSS for both states using a mobile-first approach.Chapter 17 taught you how to build layouts that adapt to any screen size using media queries, relative units, fluid containers, and responsive images. You now have the tools to make pages that work on phones, tablets, and desktops. Chapter 18 introduces CSS variables, themes, and reusable styles. You will learn how to define custom properties that store your color palette, spacing scale, and typography values. Instead of repeating the same hex code or pixel value throughout a stylesheet, you define it once and use it everywhere. When you want to update a color, you change one line. When you build a dark mode variant, you simply override a handful of variables. Chapter 18 turns a stylesheet into a design system — organized, maintainable, and built for growth.