On this page
Responsive design
What is responsive design?
Responsive design is the strategy of building websites that adapt to any screen size: from 320px phones to 4K monitors. Instead of creating separate versions, a single site adjusts fluidly.
The three pillars of responsive design are:
- Viewport meta tag (essential)
- Media queries (breakpoints)
- Fluid units and functions (clamp, vw, %)
The viewport meta tag
Without this tag, mobile browsers render the page as if it were a desktop and scale it down. It is mandatory:
<meta name="viewport" content="width=device-width, initial-scale=1">Mobile first
The mobile first strategy consists of writing base styles for small screens and using media queries to add complexity on larger screens.
/* Base: mobile (one column) */
.grid { display: grid; grid-template-columns: 1fr; }
/* Tablet: two columns */
@media (width >= 768px) {
.grid { grid-template-columns: repeat(2, 1fr); }
}
/* Desktop: three columns */
@media (width >= 1024px) {
.grid { grid-template-columns: repeat(3, 1fr); }
}It is easier to add complexity for larger screens than to remove complexity for smaller screens.
Modern media queries
The modern syntax uses comparison operators instead of min-width and max-width:
/* Classic syntax */
@media (min-width: 768px) { }
/* Modern syntax (recommended) */
@media (width >= 768px) { }
/* Range */
@media (768px <= width < 1024px) { }Recommended breakpoints
| Name | Width | Typical use |
|---|---|---|
| sm | 640px | Large phones |
| md | 768px | Tablets |
| lg | 1024px | Laptops |
| xl | 1280px | Desktops |
| 2xl | 1536px | Large screens |
You do not have to use all of them. Use only the ones your content needs.
Fluid units
Percentages and viewport units
| Unit | Relative to |
|---|---|
% |
Parent element |
vw |
1% of the viewport width |
vh |
1% of the viewport height |
dvh |
Dynamic height (respects mobile address bar) |
svh |
Smallest possible height |
lvh |
Largest possible height |
The clamp() function
clamp(minimum, ideal, maximum) is the most powerful tool for fluid values:
/* Typography that scales with the screen */
h1 { font-size: clamp(1.5rem, 4vw, 3.5rem); }
/* Readable content width */
.content { max-width: clamp(45ch, 80%, 75ch); }
/* Adaptive padding */
.section { padding: clamp(1rem, 5vw, 4rem); }With clamp(), you can eliminate many media queries.
Responsive images
Images must adapt to their container without overflowing:
img {
max-width: 100%;
height: auto;
display: block;
}For more control, use the HTML srcset attribute with different resolutions:
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
sizes="(width >= 1024px) 33vw, (width >= 768px) 50vw, 100vw"
alt="Photo description"
>Container queries
Media queries respond to the viewport size. Container queries respond to the parent container size. This makes components truly reusable.
.wrapper {
container-type: inline-size;
}
@container (width >= 400px) {
.card {
display: flex;
gap: 1rem;
}
}With container queries, a card component adapts based on where you place it: in a narrow sidebar it appears vertical, in a wide area it appears horizontal. Without changing anything in the component.
Responsive layouts without media queries
Combining Grid and Flexbox tools, you can create layouts that adapt automatically:
/* Auto-fill + minmax = automatic columns */
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
/* Flexbox wrap with minimum basis */
.cards {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card { flex: 1 1 300px; }Your site now adapts to any screen. Next, we will refine typography, a crucial element for readability and aesthetics.
Practice
- Implement a mobile-first layout: Create an article grid that shows 1 column on mobile, 2 on tablet (768px), and 3 on desktop (1024px) using media queries with the modern
(width >= ...)syntax. - Use clamp() for fluid typography: Apply
font-size: clamp(...)to a heading and a paragraph so they scale smoothly between small and large screens without media queries. - Create a component with container queries: Wrap a card in a container with
container-type: inline-sizeand use@containerto change its layout based on the container width.
/* Mobile first: base styles for mobile */
.articles-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
padding: 1rem;
}
/* Tablet: 2 columns */
@media (width >= 768px) {
.articles-grid {
grid-template-columns: repeat(2, 1fr);
padding: 2rem;
}
}
/* Desktop: 3 columns with sidebar */
@media (width >= 1024px) {
.layout {
display: grid;
grid-template-columns: 1fr 300px;
gap: 2rem;
}
.articles-grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* Fluid typography with clamp() */
.title {
font-size: clamp(1.5rem, 4vw, 3rem);
line-height: 1.2;
}
.content {
max-width: clamp(45ch, 60%, 75ch);
margin-inline: auto;
}
/* Container queries: respond to the container, not the viewport */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
.card {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
padding: 1rem;
}
/* When the CONTAINER is 400px+ */
@container card (width >= 400px) {
.card {
grid-template-columns: 150px 1fr;
align-items: center;
}
}
@container card (width >= 600px) {
.card {
grid-template-columns: 200px 1fr auto;
}
}
Sign in to track your progress