Table of Contents
- What Are Media Queries?
- Media Query Syntax: The Basics
- Structuring Approaches: Mobile-First vs. Desktop-First
- Choosing Breakpoints: Content-First, Not Device-First
- Organizing Media Queries in Your CSS
- Best Practices for Maintainable Media Queries
- Advanced Media Query Techniques
- Troubleshooting Common Media Query Issues
- Conclusion
- References
What Are Media Queries?
Media queries are a CSS3 feature that allow you to apply styles based on the characteristics of the device rendering the content. Think of them as “if-then” statements for CSS: “If the screen is at least 768px wide, apply these styles; otherwise, use the default.”
They enable you to:
- Adjust layout (e.g., stack elements vertically on mobile, horizontally on desktop).
- Modify typography (e.g., larger font sizes on larger screens).
- Hide/show elements (e.g., hide a sidebar on mobile).
- Adapt to device features (e.g., dark mode, touchscreens, or print).
Without media queries, responsive design is impossible. They bridge the gap between static styles and dynamic user experiences.
Media Query Syntax: The Basics
A media query consists of a media type (optional) and one or more media features (conditions), followed by a set of CSS rules. Here’s the basic structure:
@media [media-type] and ([media-feature]) {
/* CSS rules to apply when conditions are met */
}
1. Media Types
Media types define the category of device the query targets. The most common are:
screen: For devices with a screen (e.g., phones, laptops).print: For printed documents or print previews.all: Applies to all media types (default if omitted).
Example: Target print styles
@media print {
body {
font-size: 12pt;
color: black; /* Black text for printing */
}
}
2. Media Features
Media features are the conditions that must be met for the styles to apply. They describe device characteristics like width, height, orientation, or resolution.
Common media features include:
width/min-width/max-width: Viewport width (most used for responsive design).height/min-height/max-height: Viewport height.orientation:portrait(height > width) orlandscape(width > height).aspect-ratio: Ratio of viewport width to height (e.g.,16/9for widescreens).prefers-color-scheme: Detects user’s system theme (lightordark).
Example: Target screens at least 768px wide
@media screen and (min-width: 768px) {
.container {
padding: 2rem;
}
}
3. Logical Operators
Combine media features or types using operators like and, or (, ), and not:
-
and: Requires all conditions to be true.@media (min-width: 768px) and (orientation: landscape) { /* Applies to screens ≥768px AND in landscape */ } -
,(OR): Applies if any condition is true.@media (max-width: 599px), (print) { /* Applies to screens <600px OR print */ } -
not: Negates the entire query (rarely used).@media not print { /* Applies to all media types EXCEPT print */ }
4. The only Keyword
The only keyword prevents older browsers (that don’t support media queries) from misinterpreting the query. It’s optional but safe to include:
@media only screen and (min-width: 768px) {
/* Styles here */
}
Structuring Approaches: Mobile-First vs. Desktop-First
When building responsive layouts, you’ll choose between two core strategies: mobile-first or desktop-first. Your choice impacts how you write media queries and scale styles.
Mobile-First Design
Mobile-first starts with styles for the smallest screens (e.g., smartphones) and adds media queries to enhance styles for larger screens. It uses min-width to target larger breakpoints.
Why mobile-first?
- Prioritizes mobile users (60% of global web traffic is mobile).
- Forces you to focus on core content (no bloat).
- Results in fewer overrides (base styles are for mobile; larger screens add complexity).
Example: Mobile-first base styles + media query for tablets
/* Base styles: Mobile (default) */
.container {
padding: 1rem;
max-width: 100%;
}
/* Tablet and up (≥768px) */
@media (min-width: 768px) {
.container {
padding: 2rem;
max-width: 700px;
margin: 0 auto; /* Center container */
}
}
/* Desktop and up (≥1024px) */
@media (min-width: 1024px) {
.container {
max-width: 900px;
}
}
Desktop-First Design
Desktop-first starts with styles for large screens and uses max-width to restrict styles for smaller screens. It’s the older approach but still used in legacy projects.
Caveats:
- Risk of mobile styles being an afterthought (e.g., broken layouts on small screens).
- Requires more overrides (base styles for desktop; mobile must undo them).
Example: Desktop-first base styles + media query for mobile
/* Base styles: Desktop (default) */
.container {
padding: 2rem;
max-width: 900px;
margin: 0 auto;
}
/* Tablet and down (<1024px) */
@media (max-width: 1023px) {
.container {
max-width: 700px;
}
}
/* Mobile (<768px) */
@media (max-width: 767px) {
.container {
padding: 1rem;
max-width: 100%;
}
}
Recommendation: Use mobile-first. It aligns with user behavior, reduces CSS bloat, and is easier to maintain.
Choosing Breakpoints: Content-First, Not Device-First
Breakpoints are the screen widths where your layout changes (e.g., 768px). The biggest mistake developers make is hardcoding breakpoints for specific devices (e.g., “iPhone 13: 390px”). Devices evolve (new screen sizes every year!), but content remains constant.
Rule: Let content dictate breakpoints. Resize your browser and note where content breaks (e.g., text overflows, buttons stack awkwardly). That’s your breakpoint.
Common (Content-Driven) Breakpoints
While breakpoints should be content-specific, these are widely used as starting points:
360px–480px: Small mobile (e.g., older phones).481px–767px: Large mobile (e.g., modern smartphones).768px–1023px: Tablet (portrait and landscape).1024px–1439px: Small desktop/laptop.1440px+: Large desktop.
Defining Breakpoints with CSS Variables
For consistency, store breakpoints in CSS custom properties (variables). This makes updates easier:
:root {
--breakpoint-sm: 360px;
--breakpoint-md: 768px;
--breakpoint-lg: 1024px;
--breakpoint-xl: 1440px;
}
/* Use variables in media queries */
@media (min-width: var(--breakpoint-md)) {
/* Styles for tablets and up */
}
Organizing Media Queries in Your CSS
Where you place media queries in your CSS file impacts readability and maintainability. Choose one of these approaches:
1. Inline with Component Styles
Group media queries directly after the base styles of a component. This keeps related styles together (e.g., all .header styles in one place).
Example: Inline media queries for a header
.header {
padding: 1rem;
background: #333;
}
/* Tablet: Adjust header padding */
@media (min-width: 768px) {
.header {
padding: 1.5rem 2rem;
}
}
/* Desktop: Add shadow */
@media (min-width: 1024px) {
.header {
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
}
Pros: Easy to find/modify component-specific styles.
Cons: Media queries for the same breakpoint are scattered across the file.
2. Grouped at the End of the CSS File
Collect all media queries at the bottom of your stylesheet, organized by breakpoint (e.g., all min-width: 768px styles together).
Example: Grouped media queries
/* Base styles */
.header { padding: 1rem; }
.card { margin: 1rem 0; }
/* Tablet and up (768px) */
@media (min-width: 768px) {
.header { padding: 1.5rem 2rem; }
.card { margin: 1rem; }
}
/* Desktop and up (1024px) */
@media (min-width: 1024px) {
.header { box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.card { display: grid; grid-template-columns: repeat(3, 1fr); }
}
Pros: All responsive styles in one place; easy to see how breakpoints affect the whole site.
Cons: Harder to trace which base styles a media query modifies.
3. Separate Files (For Large Projects)
In large apps, split media queries into separate files (e.g., responsive/tablet.css, responsive/desktop.css) and import them. Use a preprocessor like Sass or a bundler (Webpack) to manage imports.
Example: Sass partial for tablet styles
// _tablet.scss
@media (min-width: 768px) {
.header { padding: 1.5rem 2rem; }
// ... other tablet styles
}
// main.scss
@import 'base';
@import 'tablet';
@import 'desktop';
Pros: Scalable; teams can work on separate breakpoints.
Cons: Adds complexity (requires tooling).
Recommendation: For small projects, use inline media queries. For large projects, group by breakpoint or use separate files with a preprocessor.
Best Practices for Maintainable Media Queries
To keep your media queries clean and scalable, follow these best practices:
1. Use Relative Units
Avoid fixed units like px for breakpoints and typography. Instead, use rem or em to respect user font-size preferences:
/* Better: Use rem (1rem = 16px by default) */
@media (min-width: 48rem) { /* 768px (48 * 16) */
body { font-size: 1.1rem; }
}
2. Avoid Over-Nesting (Preprocessors)
Sass/Less let you nest media queries inside selectors, but over-nesting leads to bloated CSS. Keep nesting shallow:
// Good: Shallow nesting
.header {
padding: 1rem;
@media (min-width: 48rem) {
padding: 2rem;
}
}
// Bad: Deep nesting (hard to read)
.header {
.nav {
.link {
color: blue;
@media (min-width: 48rem) {
color: red;
}
}
}
}
3. Test Across Devices
Always test media queries using browser dev tools (Chrome DevTools, Firefox Responsive Design Mode) or real devices. Emulators aren’t perfect—test for:
- Orientation changes (portrait ↔ landscape).
- Text readability (font size, line height).
- Touch targets (buttons should be ≥48x48px on mobile).
4. Don’t Overuse Breakpoints
Too many breakpoints (e.g., one for every 100px) create maintenance hell. Stick to 3–5 breakpoints (mobile, tablet, desktop, large desktop) unless content demands more.
5. Add the Viewport Meta Tag
Without this tag, mobile browsers zoom out to fit the “desktop” layout, breaking media queries. Always include it in your HTML <head>:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Advanced Media Query Techniques
Take your responsive design to the next level with these advanced features:
1. Range Queries (Modern CSS)
Instead of min-width and max-width, use the newer range syntax for clarity:
/* Old way */
@media (min-width: 768px) and (max-width: 1023px) { ... }
/* New way (Chrome 104+, Firefox 105+) */
@media (768px <= width <= 1023px) { ... }
2. Detect User Preferences
Use prefers-color-scheme to adapt to dark/light mode, or prefers-reduced-motion to disable animations for users with vestibular disorders:
/* Dark mode */
@media (prefers-color-scheme: dark) {
body { background: #1a1a1a; color: white; }
}
/* Reduce motion */
@media (prefers-reduced-motion: reduce) {
.animation { animation: none; }
}
3. Target High-DPI Screens
Use min-resolution or min-device-pixel-ratio to serve high-res images:
@media (min-resolution: 2dppx) { /* 2x+ screens (Retina) */
.logo { background-image: url('[email protected]'); }
}
Troubleshooting Common Media Query Issues
Even with best practices, media queries can misbehave. Here’s how to fix common problems:
1. Styles Not Applying
-
Check specificity: Media query styles must match the specificity of base styles. If your base style is
.header .nav, your media query needs the same selector:/* Base */ .header .nav { color: blue; } /* Media query (same specificity) */ @media (min-width: 48rem) { .header .nav { color: red; } } -
Missing viewport meta tag: Always include
<meta name="viewport" ...>.
2. Overlapping Breakpoints
Avoid gaps or overlaps between breakpoints. For mobile-first, use min-width sequentially:
/* Good: No overlaps */
@media (min-width: 360px) { ... } /* 360px+ */
@media (min-width: 768px) { ... } /* 768px+ (no overlap with 360px) */
3. Mobile Styles Overriding Desktop
In desktop-first designs, ensure max-width breakpoints are ordered from largest to smallest:
/* Good: Largest first */
@media (max-width: 1023px) { ... } /* <1024px */
@media (max-width: 767px) { ... } /* <768px (nested inside <1024px) */
/* Bad: Smallest first (767px styles override 1023px) */
@media (max-width: 767px) { ... }
@media (max-width: 1023px) { ... }
Conclusion
Media queries are the backbone of responsive design, but their power lies in how you structure them. By choosing a mobile-first approach, defining content-driven breakpoints, and organizing queries logically, you’ll build layouts that scale across devices and remain maintainable.
Remember: Responsive design isn’t about pixel-perfect matching for every device—it’s about ensuring your content is accessible and usable, no matter how it’s viewed. With the techniques in this guide, you’ll be well on your way to mastering media queries.