Media queries enable responsive designs that adapt to different devices and conditions. Here's a comprehensive guide.
Basic Syntax#
1/* Screen width */
2@media (min-width: 768px) {
3 .container {
4 max-width: 720px;
5 }
6}
7
8/* Max width */
9@media (max-width: 767px) {
10 .sidebar {
11 display: none;
12 }
13}
14
15/* Range (modern syntax) */
16@media (width >= 768px) {
17 .container {
18 padding: 2rem;
19 }
20}
21
22/* Combined range */
23@media (768px <= width <= 1024px) {
24 .container {
25 max-width: 960px;
26 }
27}Common Breakpoints#
1/* Mobile first approach */
2/* Base styles for mobile */
3.container {
4 padding: 1rem;
5}
6
7/* Small devices (landscape phones) */
8@media (min-width: 576px) {
9 .container {
10 max-width: 540px;
11 }
12}
13
14/* Medium devices (tablets) */
15@media (min-width: 768px) {
16 .container {
17 max-width: 720px;
18 }
19}
20
21/* Large devices (desktops) */
22@media (min-width: 992px) {
23 .container {
24 max-width: 960px;
25 }
26}
27
28/* Extra large devices */
29@media (min-width: 1200px) {
30 .container {
31 max-width: 1140px;
32 }
33}
34
35/* XXL devices */
36@media (min-width: 1400px) {
37 .container {
38 max-width: 1320px;
39 }
40}Media Types#
1/* Screen (default) */
2@media screen {
3 body {
4 font-size: 16px;
5 }
6}
7
8/* Print */
9@media print {
10 .no-print {
11 display: none;
12 }
13
14 body {
15 font-size: 12pt;
16 color: black;
17 }
18
19 a {
20 text-decoration: none;
21 color: inherit;
22 }
23
24 /* Show URLs after links */
25 a[href]::after {
26 content: " (" attr(href) ")";
27 }
28}
29
30/* All media types */
31@media all {
32 /* Applies everywhere */
33}Logical Operators#
1/* AND - all conditions must match */
2@media (min-width: 768px) and (max-width: 1024px) {
3 .tablet-only {
4 display: block;
5 }
6}
7
8/* OR - any condition matches (comma) */
9@media (max-width: 767px), (orientation: portrait) {
10 .mobile-or-portrait {
11 flex-direction: column;
12 }
13}
14
15/* NOT - negate entire query */
16@media not screen and (color) {
17 /* Non-color screens */
18}
19
20/* ONLY - hide from older browsers */
21@media only screen and (min-width: 768px) {
22 /* Modern browsers only */
23}Feature Queries#
1/* Orientation */
2@media (orientation: portrait) {
3 .layout {
4 flex-direction: column;
5 }
6}
7
8@media (orientation: landscape) {
9 .layout {
10 flex-direction: row;
11 }
12}
13
14/* Aspect ratio */
15@media (aspect-ratio: 16/9) {
16 .video-container {
17 /* Perfect 16:9 */
18 }
19}
20
21@media (min-aspect-ratio: 1/1) {
22 /* Landscape or square */
23}
24
25/* Resolution */
26@media (min-resolution: 2dppx) {
27 /* Retina displays */
28 .logo {
29 background-image: url('logo@2x.png');
30 }
31}
32
33@media (min-resolution: 192dpi) {
34 /* High DPI screens */
35}User Preferences#
1/* Color scheme */
2@media (prefers-color-scheme: dark) {
3 :root {
4 --bg-color: #1a1a1a;
5 --text-color: #f0f0f0;
6 }
7}
8
9@media (prefers-color-scheme: light) {
10 :root {
11 --bg-color: #ffffff;
12 --text-color: #333333;
13 }
14}
15
16/* Reduced motion */
17@media (prefers-reduced-motion: reduce) {
18 *,
19 *::before,
20 *::after {
21 animation-duration: 0.01ms !important;
22 animation-iteration-count: 1 !important;
23 transition-duration: 0.01ms !important;
24 }
25}
26
27/* Reduced transparency */
28@media (prefers-reduced-transparency: reduce) {
29 .overlay {
30 background: solid-color;
31 }
32}
33
34/* Contrast preference */
35@media (prefers-contrast: more) {
36 :root {
37 --border-color: black;
38 --text-color: black;
39 }
40}
41
42@media (prefers-contrast: less) {
43 :root {
44 --text-color: #666;
45 }
46}Hover and Pointer#
1/* Hover capability */
2@media (hover: hover) {
3 /* Device can hover (mouse) */
4 .button:hover {
5 background: blue;
6 }
7}
8
9@media (hover: none) {
10 /* No hover capability (touch) */
11 .button {
12 /* Larger touch targets */
13 padding: 1rem 2rem;
14 }
15}
16
17/* Pointer precision */
18@media (pointer: fine) {
19 /* Precise pointer (mouse) */
20 .small-control {
21 width: 20px;
22 height: 20px;
23 }
24}
25
26@media (pointer: coarse) {
27 /* Imprecise pointer (touch) */
28 .small-control {
29 width: 44px;
30 height: 44px;
31 }
32}
33
34/* Any pointer/hover */
35@media (any-hover: hover) {
36 /* At least one input can hover */
37}
38
39@media (any-pointer: fine) {
40 /* At least one precise input */
41}Display Features#
1/* Display mode (PWA) */
2@media (display-mode: standalone) {
3 /* Running as installed app */
4 .install-prompt {
5 display: none;
6 }
7}
8
9@media (display-mode: fullscreen) {
10 .exit-fullscreen-hint {
11 display: block;
12 }
13}
14
15/* Dynamic range (HDR) */
16@media (dynamic-range: high) {
17 .hero-image {
18 /* Use HDR image */
19 }
20}
21
22/* Color gamut */
23@media (color-gamut: p3) {
24 .brand-color {
25 color: color(display-p3 1 0 0);
26 }
27}Container Queries#
1/* Define container */
2.card-container {
3 container-type: inline-size;
4 container-name: card;
5}
6
7/* Query container size */
8@container card (min-width: 400px) {
9 .card {
10 flex-direction: row;
11 }
12}
13
14@container (width > 600px) {
15 .card-title {
16 font-size: 1.5rem;
17 }
18}
19
20/* Container with shorthand */
21.sidebar {
22 container: sidebar / inline-size;
23}
24
25@container sidebar (min-width: 300px) {
26 .nav-item {
27 display: flex;
28 gap: 1rem;
29 }
30}Responsive Typography#
1/* Fluid typography */
2html {
3 font-size: 16px;
4}
5
6@media (min-width: 768px) {
7 html {
8 font-size: 18px;
9 }
10}
11
12@media (min-width: 1200px) {
13 html {
14 font-size: 20px;
15 }
16}
17
18/* Or use clamp */
19html {
20 font-size: clamp(16px, 2vw, 20px);
21}
22
23/* Responsive headings */
24h1 {
25 font-size: 2rem;
26}
27
28@media (min-width: 768px) {
29 h1 {
30 font-size: 3rem;
31 }
32}
33
34@media (min-width: 1200px) {
35 h1 {
36 font-size: 4rem;
37 }
38}Responsive Images#
1/* Art direction with media queries */
2.hero {
3 background-image: url('hero-mobile.jpg');
4 background-size: cover;
5}
6
7@media (min-width: 768px) {
8 .hero {
9 background-image: url('hero-tablet.jpg');
10 }
11}
12
13@media (min-width: 1200px) {
14 .hero {
15 background-image: url('hero-desktop.jpg');
16 }
17}
18
19/* Resolution-based images */
20.logo {
21 background-image: url('logo.png');
22}
23
24@media (min-resolution: 2dppx) {
25 .logo {
26 background-image: url('logo@2x.png');
27 background-size: 100px 50px;
28 }
29}Navigation Pattern#
1/* Mobile navigation */
2.nav {
3 display: none;
4}
5
6.nav-toggle {
7 display: block;
8}
9
10.nav.is-open {
11 display: flex;
12 flex-direction: column;
13 position: fixed;
14 inset: 0;
15 background: white;
16}
17
18/* Desktop navigation */
19@media (min-width: 768px) {
20 .nav {
21 display: flex;
22 gap: 1rem;
23 }
24
25 .nav-toggle {
26 display: none;
27 }
28}Grid Responsive Pattern#
1.grid {
2 display: grid;
3 gap: 1rem;
4 grid-template-columns: 1fr;
5}
6
7@media (min-width: 576px) {
8 .grid {
9 grid-template-columns: repeat(2, 1fr);
10 }
11}
12
13@media (min-width: 992px) {
14 .grid {
15 grid-template-columns: repeat(3, 1fr);
16 }
17}
18
19@media (min-width: 1200px) {
20 .grid {
21 grid-template-columns: repeat(4, 1fr);
22 }
23}
24
25/* Or use auto-fit */
26.grid-auto {
27 display: grid;
28 gap: 1rem;
29 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
30}Best Practices#
Strategy:
✓ Mobile-first approach
✓ Use min-width queries
✓ Set logical breakpoints
✓ Test on real devices
Performance:
✓ Minimize media queries
✓ Use container queries for components
✓ Combine related styles
✓ Consider critical CSS
Accessibility:
✓ Respect prefers-reduced-motion
✓ Support prefers-color-scheme
✓ Test with prefers-contrast
✓ Ensure touch targets
Avoid:
✗ Device-specific breakpoints
✗ Too many breakpoints
✗ Hiding content on mobile
✗ Fixed pixel values only
Conclusion#
Media queries are essential for responsive design. Use min-width for mobile-first approaches, leverage user preference queries for accessibility, and consider container queries for component-level responsiveness. Always test across devices and respect user preferences for motion, color scheme, and contrast.