Breakpoints are the viewport widths where your layout changes significantly. Media queries are the CSS mechanism that makes it happen. Getting breakpoints right means your site looks intentional on every screen, not just the ones you tested.
Choosing Breakpoints
The most common mistake is choosing breakpoints based on specific devices: "320px for iPhone SE, 768px for iPad, 1440px for MacBook." This approach breaks every time a new device launches.
Instead, choose breakpoints based on your content. Open your site, slowly resize the browser, and add a breakpoint wherever the layout starts to look broken.
That said, most design systems converge on similar ranges:
| Breakpoint | Width | Target |
|---|---|---|
sm | 640px | Large phones in landscape |
md | 768px | Tablets |
lg | 1024px | Small laptops |
xl | 1280px | Desktops |
2xl | 1536px | Large monitors |
These are starting points. Your content may need breakpoints at 480px, 900px, or any other width where the layout needs adjustment.
min-width vs max-width
The direction of your media queries defines your entire strategy:
min-width (Mobile-First)
/* Base styles: mobile */
.sidebar {
display: none;
}
/* 768px and above: show sidebar */
@media (min-width: 768px) {
.sidebar {
display: block;
width: 250px;
}
}With min-width, you start with mobile styles and add complexity. Each query builds on the previous. This is the recommended approach because:
- Base styles are simpler and faster to load
- You only add what larger screens need
- It aligns with progressive enhancement
max-width (Desktop-First)
/* Base styles: desktop */
.sidebar {
display: block;
width: 250px;
}
/* Below 768px: hide sidebar */
@media (max-width: 767px) {
.sidebar {
display: none;
}
}With max-width, you start with desktop styles and remove features for smaller screens. This leads to more overrides and more CSS.
Mixing Both
Sometimes you need a range. Target a specific range by combining both:
/* Tablet only: between 768px and 1023px */
@media (min-width: 768px) and (max-width: 1023px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}Use range queries sparingly. They add complexity and make your styles harder to trace.
Modern Range Syntax
CSS now supports a cleaner range syntax that reads more naturally:
/* Old syntax */
@media (min-width: 768px) and (max-width: 1023px) { }
/* New range syntax */
@media (768px <= width < 1024px) { }
/* One-sided range */
@media (width >= 768px) { }Browser support for range syntax is strong in modern browsers (Chrome 104+, Firefox 63+, Safari 16.4+).
Common Responsive Patterns
The Column Drop
Columns stack vertically on small screens and sit side by side on larger screens:
.columns {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
}
@media (min-width: 768px) {
.columns {
grid-template-columns: 1fr 1fr;
}
}
@media (min-width: 1024px) {
.columns {
grid-template-columns: 1fr 1fr 1fr;
}
}The Layout Shifter
The layout fundamentally reorganizes at different sizes using grid areas:
.page {
display: grid;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
@media (min-width: 768px) {
.page {
grid-template-columns: 250px 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
}The Off-Canvas
Navigation slides in from the side on mobile, stays visible on desktop:
.nav {
position: fixed;
left: -280px;
width: 280px;
height: 100vh;
transition: left 0.3s ease;
}
.nav.open {
left: 0;
}
@media (min-width: 1024px) {
.nav {
position: static;
height: auto;
}
}Media Query Best Practices
- Use
emunits in media queries for better zoom behavior:@media (min-width: 48em)equals 768px at default font size - Order queries from smallest to largest when using
min-width - Group media queries with their components, not in a separate file. Keep related styles together
- Test between breakpoints, not just at them. The space between 768px and 1024px should also look good
- Limit the number of breakpoints. Most layouts need only 2-3. If you need more, your layout may be too rigid