Responsive Design in 2026: The Modern Approach
Media queries are just the beginning. Here's the full toolkit.
The Mobile-First Approach
/* Start with mobile styles (no media query needed) */
.container {
width: 100%;
padding: 1rem;
font-size: 16px;
}
.nav {
flex-direction: column;
}
.grid {
grid-template-columns: 1fr; /* Single column on mobile */
}
/* Then add complexity for larger screens */
@media (min-width: 640px) { /* Tablet */
.container {
max-width: 640px;
margin: 0 auto;
}
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) { /* Desktop */
.container {
max-width: 1200px;
}
.nav {
flex-direction: row; /* Horizontal nav on desktop */
}
.grid {
grid-template-columns: repeat(4, 1fr);
}
}
Modern Breakpoints (2026)
/* Don't use device-specific breakpoints! Use content-based ones */
:root {
--breakpoint-sm: 640px; /* Small tablets, large phones */
--breakpoint-md: 768px; /* Tablets */
--breakpoint-lg: 1024px; /* Laptops, small desktops */
--breakpoint-xl: 1280px; /* Desktops */
--breakpoint-2xl: 1536px; /* Large screens */
}
/* Or use container queries for component-level responsiveness */
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 120px 1fr;
}
}
Fluid Typography (No More Jumping Font Sizes!)
/* Old way: Fixed sizes at each breakpoint */
h1 { font-size: 24px; } /* Mobile */
@media (min-width: 768px) { h1 { font-size: 32px; } } /* Tablet */
@media (min-width: 1024px) { h1 { font-size: 48px; } } /* Desktop */
/* New way: Fluid scaling using clamp() */
h1 {
font-size: clamp(1.75rem, 4vw + 0.5rem, 3.5rem);
/* Minimum: 28px | Preferred: 4% of viewport + 8px | Maximum: 56px */
line-height: clamp(1.2, 4vw + 0.5rem, 1.3);
}
body {
font-size: clamp(0.875rem, 0.5vw + 0.8rem, 1.125rem);
/* 14px minimum → scales with viewport → 18px maximum */
}
/* Complete fluid type scale */
h1 { font-size: clamp(2rem, 5vw + 0.5rem, 4rem); } /* 32-64px */
h2 { font-size: clamp(1.5rem, 4vw + 0.5rem, 3rem); } /* 24-48px */
h3 { font-size: clamp(1.25rem, 3vw + 0.5rem, 2rem); } /* 20-32px */
p { font-size: clamp(1rem, 1.5vw + 0.5rem, 1.25rem); } /* 16-20px */
small { font-size: clamp(0.75rem, 1vw + 0.5rem, 0.875rem); } /* 12-14px */
Responsive Images
<!-- Art direction: Different images for different layouts -->
<picture>
<source
media="(min-width: 1024px)"
srcset="hero-large.webp 1920w, hero-medium.webp 1280w"
type="image/webp"
>
<source
srcset="hero-small.webp 640w"
type="image/webp"
>
<img
src="hero-fallback.jpg"
alt="Hero image showing our product dashboard"
loading="lazy"
decoding="async"
width="1920"
height="1080"
>
</picture>
<!-- Density switching for retina displays -->
<img
src="photo-1x.jpg"
srcset="photo-2x.jpg 2x, photo-3x.jpg 3x"
alt="Product photo"
>
CSS Grid + Auto-Fit (The Magic Combination)
/* Auto-adjusting number of columns based on available space */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
}
/* No media queries needed!
* On a 320px phone: 1 column (280px min doesn't fit twice)
* On a 768px tablet: 2 columns (280+280+gap ≈ 570 < 768)
* On a 1400px desktop: 4 columns (280*4+gaps ≈ 1140 < 1400)
* Automatically adjusts when you resize the window!
*/
Responsive Spacing
/* Using viewport units for spacing that scales */
.section {
padding: clamp(2rem, 5vh + 1rem, 6rem) 0;
/* Min: 32px | Scales with viewport height | Max: 96px */
}
.hero {
margin-block: clamp(1rem, 8vh, 4rem);
gap: clamp(1rem, 3vw, 3rem);
}
/* Container queries for component spacing */
.content-wrapper {
container-type: inline-size;
}
@container (max-width: 600px) {
.content-wrapper {
padding: 1rem;
}
}
@container (min-width: 601px) {
.content-wrapper {
padding: 2rem 4rem;
}
}
Navigation Patterns
/* Mobile: Hamburger menu */
.nav-toggle { display: block; }
.nav-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
padding: 1rem;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.nav-menu.is-open { display: block; }
@media (min-width: 768px) {
.nav-toggle { display: none; }
.nav-menu {
display: flex;
position: static;
box-shadow: none;
gap: 2rem;
}
}
/* Or use details/summary for no-JS dropdown */
details.nav-dropdown summary {
list-style: none;
cursor: pointer;
}
details[open] .dropdown-menu {
display: block;
}
@media (min-width: 768px) {
.nav-dropdown summary::after {
content: ''; /* Hide arrow on desktop */
}
.dropdown-menu {
display: flex; /* Always show on desktop */
position: static;
box-shadow: none;
}
}
Testing Responsive Design
/* Quick debug: Show current breakpoint */
body::after {
content: 'mobile';
display: block;
position: fixed;
bottom: 0;
right: 0;
background: #333;
color: white;
padding: 0.25rem 0.5rem;
font-size: 12px;
z-index: 9999;
}
@media (min-width: 640px) { body::after { content: 'sm'; } }
@media (min-width: 768px) { body::after { content: 'md'; } }
@media (min-width: 1024px) { body::after { content: 'lg'; } }
@media (min-width: 1280px) { body::after { content: 'xl'; } }
Quick Reference
| Technique | When to Use |
|---|---|
clamp() |
Typography, spacing, anything that should scale smoothly |
auto-fit / auto-fill
|
Grid layouts that adapt to container width |
Container queries (@container) |
Component-level responsiveness |
Media queries (@media) |
Page layout changes, major breakpoints |
min() / max()
|
Values that need constraints |
<picture> element |
Art direction (different images per breakpoint) |
srcset |
Resolution switching (retina displays) |
vw units |
Full-width elements, typography |
| Flexbox wrap | Navigation items, tag lists |
What's your go-to responsive design pattern?
Follow @armorbreak for more frontend content.
Top comments (0)