CSS Responsive Design Intro
Responsive design is the practice of writing CSS so that a single page layout adapts gracefully to any screen size, from a small phone to a wide desktop monitor, without the developer needing to build separate versions of the site. It matters because visitors arrive on an enormous range of devices and window sizes, and a layout that only looks right at one width will break, overflow, or become unreadable at another. CSS gives you the tools to do this natively: media queries that apply different rules at different viewport widths, and flexible units and layout models that let content resize on their own. This lesson introduces the core ideas that every later responsive-design lesson builds on.
Overview / How it works
A browser renders a page inside a viewport: the visible area of the browser window (or the physical screen on mobile). By default, mobile browsers pretend to have a much wider viewport (often 980px) and then zoom out, which is why a page can look tiny on a phone unless the document includes <meta name="viewport" content="width=device-width, initial-scale=1"> in its HTML <head>. That meta tag is HTML, not CSS, but it is a prerequisite for responsive CSS to work as intended: without it, a media query written for a 400px-wide phone will never actually match, because the browser reports a fake, wider viewport.
Once the real viewport width is exposed, responsive CSS relies on two complementary strategies. The first is fluid layout: instead of fixing box sizes in pixels, you size them in relative units (percentages, fr tracks in Grid, flex factors, em/rem, or vw/vh) so the browser’s layout algorithm recalculates box sizes automatically whenever the containing block’s size changes. The second is conditional CSS via the @media at-rule: a block of rules that the browser only applies when a stated condition about the viewport (most commonly its width) is true. The rendering engine re-evaluates every media query on every layout pass, including when the window is resized or a device is rotated, so the applied rule set updates live.
These two strategies work at different levels of the box model. Fluid units change how individual boxes are sized within the layout algorithm (how much of the available inline space a Grid track or Flexbox item claims). Media queries change which declarations exist at all, letting you restructure the whole page: switching a multi-column grid to a single column, hiding a sidebar, or changing font sizes, all as a shift from one breakpoint to the next.
Syntax
A media query has three parts: the @media keyword, one or more media features in parentheses (usually joined with and), and a block of ordinary CSS rules that only apply when the condition is true.
@media (feature: value) {
selector {
property: value;
}
}
| Part | Meaning |
|---|---|
@media |
Starts a conditional block of CSS rules. |
(min-width: 768px) |
True when the viewport is at least 768px wide. Used for mobile-first breakpoints. |
(max-width: 600px) |
True when the viewport is at most 600px wide. Used for desktop-first breakpoints. |
and, , |
Combine conditions: and requires both to be true; a comma means “or”. |
| rule block | Any normal CSS rules; they are inserted into the cascade only while the condition holds. |
Besides media queries, responsive CSS leans on relative sizing keywords and functions: %, rem, vw/vh, and the modern clamp(min, preferred, max) function, which lets a single value fluidly scale between two limits without any media query at all.
Examples
Example 1: A grid that collapses to one column on small screens
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
@media (max-width: 600px) {
.container {
grid-template-columns: 1fr;
}
}
Result: On any viewport wider than 600px, .container‘s children are laid out in three equal-width columns with a 1rem gap between them. Once the viewport shrinks to 600px or narrower, the @media block’s rule takes over and the same children stack into a single full-width column, one below another.
This is the classic desktop-first pattern: write the wide-screen layout as the default, then override it inside a max-width query for narrow screens. The grid’s column count itself is what changes; the browser recomputes track sizes from scratch every time the rule set changes.
Example 2: Fluid images that never overflow their container
img {
max-width: 100%;
height: auto;
display: block;
}
Result: Every image on the page shrinks to fit its parent container whenever that container is narrower than the image’s natural size, while never being stretched larger than its true pixel dimensions. Because height is auto, the image’s aspect ratio is preserved as it shrinks, so it never looks squashed or stretched.
This single rule is one of the oldest and most important responsive techniques: without it, a 1200px-wide photo will force a horizontal scrollbar on a 375px phone screen, breaking the whole layout.
Example 3: Mobile-first breakpoints with fluid typography
.card {
padding: 1rem;
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
}
@media (min-width: 768px) {
.card {
padding: 2rem;
}
}
Result: On a narrow phone viewport, .card has 1rem of padding and text sized near 1rem. As the viewport widens, the clamp() value smoothly increases the font size (bounded between 1rem and 1.25rem) with no breakpoint jump at all. Separately, once the viewport reaches 768px or wider, the min-width media query adds extra padding, giving the card noticeably more breathing room on tablets and desktops.
This example mixes both responsive strategies: clamp() handles continuous, small-scale fluid resizing, while the media query handles a larger structural jump (spacing) at a specific breakpoint. Writing the base rules for the smallest screen first and adding min-width overrides for larger ones is called mobile-first design, and it is the pattern most modern CSS style guides recommend.
How it works step by step
When the browser lays out a page, responsive CSS is resolved in this order:
- 1. Viewport measurement. The browser determines the current viewport width (respecting the HTML viewport meta tag on mobile).
- 2. Media query evaluation. For every
@mediablock in the stylesheet, the browser checks whether the stated feature conditions are currently true. - 3. Cascade assembly. Declarations from matching media blocks are added to the normal cascade, competing by specificity and source order exactly like any other rule — a matching media query does not raise a selector’s specificity, it only determines whether the rule is considered at all.
- 4. Box generation and sizing. The layout algorithm (Grid, Flexbox, or normal flow) computes box sizes using whatever relative or fixed units apply, based on the size of each box’s containing block.
- 5. Re-evaluation on resize. Whenever the viewport size changes (window resize, device rotation, DevTools responsive mode), the browser repeats steps 1–4, so the visible layout updates live.
Common Mistakes
Mistake 1: Fixed pixel widths that overflow small screens
.sidebar {
width: 400px;
float: left;
}
This is valid CSS, but it is not responsive: on a 320px-wide phone, a 400px-wide sidebar is wider than the entire viewport, forcing a horizontal scrollbar and pushing other content out of view. The fix is to size the box relative to its container and cap it with max-width:
.sidebar {
width: 100%;
max-width: 400px;
}
Now the sidebar shrinks to fit narrow viewports but still tops out at 400px on wide screens.
Mistake 2: Overlapping min-width breakpoints written out of order
@media (min-width: 1024px) {
.nav {
display: flex;
}
}
@media (min-width: 768px) {
.nav {
display: block;
}
}
Both blocks are individually valid, but at a 1200px viewport both conditions are true (1200px is over both 1024px and 768px), so both rules match. Because the 768px block appears later in the source, it wins the cascade tie and silently overrides the intended flex layout on large screens — the opposite of what a mobile-first design intends. The fix is to always order min-width queries from smallest to largest so later, more specific overrides for wider screens come last:
@media (min-width: 768px) {
.nav {
display: block;
}
}
@media (min-width: 1024px) {
.nav {
display: flex;
}
}
Best Practices
- Always pair responsive CSS with
<meta name="viewport" content="width=device-width, initial-scale=1">in the document’s HTML head. - Design mobile-first: write base styles for small screens, then layer
min-widthmedia queries for progressively larger ones. - Order multiple
min-widthqueries from smallest to largest (ormax-widthqueries from largest to smallest) so the cascade resolves overlaps the way you intend. - Prefer relative units (
%,rem,fr,clamp()) over fixed pixel widths for anything that should adapt to its container. - Always set
max-width: 100%andheight: autoon images so they never overflow their container. - Choose breakpoints based on where your own content starts to look cramped or awkward, not on specific device dimensions — devices vary too much to target reliably.
- Keep the number of breakpoints small; two or three well-chosen ones are easier to maintain than a dozen device-specific ones.
Practice Exercises
- Write a
.gridrule with three equal columns using CSS Grid, then add amax-width: 700pxmedia query that switches it to a single column. - Take a
.hero-textselector and give it a fluid font size usingclamp()so it scales smoothly between 1.25rem and 2.5rem as the viewport widens, with no media query involved. - Write two mobile-first
min-widthmedia queries (for 600px and 900px) that progressively increase thepaddingof a.panelclass, and double-check the breakpoints are ordered so the 900px rule can still win at very wide viewports.
Summary
- Responsive design lets one CSS file adapt a layout to any viewport width, instead of building separate sites per device.
- The HTML viewport meta tag is required for mobile browsers to report their real width; without it, media queries won’t match as expected.
@mediaat-rules apply CSS conditionally based on features likemin-widthormax-width, and the browser re-evaluates them on every resize.- Relative units and functions like
clamp()provide continuous fluid resizing without needing a breakpoint at all. - Mobile-first design (base styles plus ascending
min-widthoverrides) is the recommended default pattern because it avoids overlap and override bugs. - Always cap image and fixed-content widths with
max-width: 100%to prevent horizontal overflow on small screens.
