CSS Media Queries: A Complete Beginner's Guide
Everything you need to know about using media queries to build responsive, accessible websites that adapt to any device.
Everything you need to know about using media queries to build responsive, accessible websites that adapt to any device.
Last updated: February 2026
Media queries are a CSS feature that lets you apply styles conditionally, based on characteristics of the device or viewport displaying your page. They are the primary tool for building responsive web designs that adapt gracefully to phones, tablets, laptops, desktops, and everything in between. Without media queries, a website would render identically on a 375-pixel-wide phone and a 2560-pixel-wide desktop monitor, which would be either impossibly cramped on the phone or absurdly empty on the desktop.
Media queries were introduced in CSS3 and have been supported by all major browsers since around 2012. They work by evaluating a condition (like “is the viewport wider than 768 pixels?”) and applying a block of CSS rules only when that condition is true. As the condition changes (for example, when the user resizes their browser window or rotates their phone), the styles update immediately without any JavaScript or page reload. You can see which media features your current device reports using the DisplayPixels @media helper.
A media query consists of an optional media type, zero or more media feature conditions, and a block of CSS rules. Here is the general structure:
@media [media-type] and (media-feature) {
/* CSS rules here */
}
Let us break down each part:
The media type specifies the broad category of device. The most common values are screen (for displays), print (for print output), and all (the default, matching everything). In practice, most developers omit the media type or use screen, as the distinction between screen and other types matters mainly for print stylesheets.
/* Applies only when printing */
@media print {
.no-print { display: none; }
}
/* Applies to screens only */
@media screen and (min-width: 768px) {
.sidebar { display: block; }
}
Media features are the conditions that make media queries powerful. They are enclosed in parentheses and test specific characteristics of the viewport or device. The most commonly used features are width, height, orientation, resolution, prefers-color-scheme, and prefers-reduced-motion. Many features accept min- and max- prefixes to create range conditions.
You can combine multiple conditions using logical operators. The and keyword requires all conditions to be true. A comma acts as a logical OR, matching if any condition is true. The not keyword negates the entire query.
/* Both conditions must be true */
@media (min-width: 768px) and (orientation: landscape) {
/* ... */
}
/* Either condition can be true */
@media (max-width: 480px), (orientation: portrait) {
/* ... */
}
/* Negation */
@media not print {
/* Applies to everything except print */
}
Width-based media queries are by far the most frequently used type. They respond to the viewport width (the visible area of the browser window, not the screen's physical resolution). The min-width and max-width features create breakpoints where your layout changes.
/* Mobile-first: base styles for small screens */
.container {
padding: 1rem;
display: flex;
flex-direction: column;
}
/* Tablet and up */
@media (min-width: 768px) {
.container {
flex-direction: row;
padding: 2rem;
}
}
/* Desktop and up */
@media (min-width: 1200px) {
.container {
max-width: 1140px;
margin: 0 auto;
}
}
The CSS Level 4 specification introduced range syntax using standard comparison operators, which is now supported in all modern browsers:
/* Equivalent to (min-width: 768px) and (max-width: 1199px) */
@media (768px <= width < 1200px) {
.container {
max-width: 720px;
}
}
This range syntax is more readable and less error-prone than using min- and max- pairs, especially when defining specific ranges. It eliminates the classic off-by-one-pixel issue where max-width: 767px and min-width: 768px do not overlap but might cause a gap with fractional pixel widths on some browsers.
Height queries (min-height, max-height) work the same way but are used less often. They are useful for adjusting layouts on short viewports, such as laptops with small screens in landscape mode, or for ensuring that sticky headers do not consume too much vertical space on short displays. You can check your current viewport dimensions using the DisplayPixels screen size tool.
The orientation media feature detects whether the viewport is in portrait (taller than wide) or landscape (wider than tall) mode. This is particularly useful for mobile devices that physically rotate.
@media (orientation: portrait) {
.gallery {
grid-template-columns: 1fr 1fr;
}
}
@media (orientation: landscape) {
.gallery {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
}
Note that orientation is determined by the viewport dimensions, not by a physical sensor. A desktop browser window that is taller than it is wide will report portrait orientation. This makes orientation queries useful beyond mobile devices, for example, to adjust layouts when a user has a very narrow browser window on a desktop.
The prefers-color-scheme media feature detects whether the user has requested a light or dark color theme through their operating system settings. This is how websites can automatically switch between light and dark modes without requiring a manual toggle (though providing one as well is best practice).
/* Light mode (default) */
:root {
--bg: #ffffff;
--text: #111111;
--accent: #0066ee;
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
:root {
--bg: #0d1117;
--text: #e6edf3;
--accent: #58a6ff;
}
}
Using CSS custom properties (variables) with prefers-color-scheme is the cleanest approach because you define your colors once and reference them throughout your stylesheet. The media query only needs to redefine the variables, and all elements using those variables update automatically.
For this site, DisplayPixels uses exactly this pattern. If you switch your operating system between light and dark mode, the entire color scheme adapts. The color-scheme meta tag and CSS property ensure that browser-native UI elements (scrollbars, form controls) also adapt to the selected theme.
When implementing dark mode, avoid simply inverting colors. Dark backgrounds should use very dark grays (#0d1117 or #1a1a2e) rather than pure black (#000000), because pure black on OLED screens creates an uncomfortable contrast with bright text. Text on dark backgrounds should be slightly muted (#e6edf3 rather than pure white #ffffff) to reduce eye strain.
The prefers-reduced-motion feature detects whether the user has enabled a reduced motion setting in their operating system. People with vestibular disorders, motion sensitivity, or certain neurological conditions can experience dizziness, nausea, or disorientation from animations and parallax effects. Respecting this preference is both an accessibility best practice and, in some jurisdictions, a legal compliance consideration.
/* Default: animations enabled */
.card {
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
}
/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
.card {
transition: none;
}
.card:hover {
transform: none;
}
}
A more robust approach is to use prefers-reduced-motion: no-preference as the condition for enabling animations, so the default (for users whose preference cannot be determined) is no animation:
/* Base: no animation */
.card {
transition: none;
}
/* Only animate if user has not requested reduced motion */
@media (prefers-reduced-motion: no-preference) {
.card {
transition: transform 0.3s ease;
}
}
This “motion-first” vs “no-motion-first” decision is analogous to mobile-first responsive design. The safer default is no motion, with animations added progressively for users who are comfortable with them.
The resolution media feature lets you target devices based on their pixel density, typically to serve higher-resolution images to high-DPI screens. The related -webkit-min-device-pixel-ratio feature is a legacy WebKit syntax that remains widely used for compatibility. For a deeper explanation of device pixel ratio, see our article on device pixel ratio explained.
/* Standard resolution */
.hero {
background-image: url('hero-1x.jpg');
}
/* High-DPI screens (2x and above) */
@media (min-resolution: 192dpi),
(-webkit-min-device-pixel-ratio: 2) {
.hero {
background-image: url('hero-2x.jpg');
}
}
/* Very high-DPI screens (3x) */
@media (min-resolution: 288dpi),
(-webkit-min-device-pixel-ratio: 3) {
.hero {
background-image: url('hero-3x.jpg');
}
}
In modern development, the srcset attribute on <img> elements and the <picture> element handle most responsive image needs more elegantly than media queries. However, resolution media queries remain essential for CSS background images and for adjusting fine details like border widths or icon sizes based on pixel density.
The resolution value is specified in dpi (dots per inch) or dppx (dots per pixel unit). A device pixel ratio of 2 equals 192 dpi (because the CSS reference pixel is defined as 1/96th of an inch, so 2x is 2 × 96 = 192 dpi). The dppx unit maps directly to the device pixel ratio, so 2dppx equals a 2x display.
Mobile-first design is a strategy where you write your base CSS for the smallest screens and then use min-width media queries to progressively add complexity for larger screens. This approach has several practical advantages.
First, mobile styles are typically simpler: single-column layouts, stacked elements, full-width components. By making these the default, your CSS is leaner and more straightforward. Complexity is added only when there is more screen space to use it.
Second, mobile-first aligns with how CSS works. Without any media queries, all styles apply everywhere. By writing simple base styles and adding media queries for larger screens, you ensure that if a media query fails to load or is not supported, the user sees a functional (if basic) layout. Desktop-first design, by contrast, risks serving a broken wide layout to a small screen if the media queries fail.
Third, mobile-first encourages you to prioritize content. When you design for a small screen first, you are forced to decide what matters most and present it clearly. As screen size increases, you add supplementary content and more elaborate layouts, rather than trying to cram a complex desktop design into a phone screen.
/* Base styles (mobile) */
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
/* Tablet: 2 columns */
@media (min-width: 640px) {
.grid {
grid-template-columns: 1fr 1fr;
}
}
/* Desktop: 3 columns */
@media (min-width: 1024px) {
.grid {
grid-template-columns: 1fr 1fr 1fr;
gap: 1.5rem;
}
}
/* Large desktop: 4 columns with max width */
@media (min-width: 1400px) {
.grid {
grid-template-columns: repeat(4, 1fr);
max-width: 1320px;
margin: 0 auto;
}
}
While there is no single correct set of breakpoints, certain ranges have emerged as practical defaults. For a more detailed discussion, see our responsive design breakpoints guide. Here are the ranges most developers use as a starting point:
| Breakpoint | Target |
|---|---|
| 0 – 479px | Small phones |
| 480 – 767px | Large phones, small tablets |
| 768 – 1023px | Tablets in portrait |
| 1024 – 1279px | Tablets in landscape, small laptops |
| 1280 – 1439px | Standard laptops and desktops |
| 1440px+ | Large desktops |
The important principle is to let your content determine your breakpoints, not the other way around. Start with your mobile layout, gradually widen the viewport, and add a breakpoint when the design starts to look awkward or waste space. This produces breakpoints that serve your specific content rather than arbitrary device categories.
CSS frameworks like Tailwind CSS, Bootstrap, and others define their own breakpoint systems. If you are using a framework, it is usually best to stick with its breakpoints for consistency. Tailwind uses 640, 768, 1024, 1280, and 1536 pixels. Bootstrap uses 576, 768, 992, 1200, and 1400 pixels. Both are reasonable systems, and the specific numbers matter less than using them consistently.
Real-world layouts often require combining multiple conditions. The and operator lets you target very specific scenarios:
/* Tablet in landscape with a dark theme */
@media (min-width: 768px) and (max-width: 1023px)
and (orientation: landscape)
and (prefers-color-scheme: dark) {
.header {
background: #1a1a2e;
padding: 0.5rem;
}
}
Be cautious with overly specific combinations; they can make your CSS hard to maintain and debug. In most cases, width-based breakpoints handle layout, and separate user preference queries handle theming and motion. Combining them is useful for edge cases but should not be the foundation of your responsive strategy.
CSS Level 4 also introduced the @media (hover: hover) and @media (pointer: fine) features, which detect whether the primary input device supports hover states and whether it is precise (like a mouse) or coarse (like a finger on a touchscreen). These are valuable for adjusting interactive element sizes and hover-dependent interfaces:
/* Increase tap target size for touch devices */
@media (pointer: coarse) {
button, a {
min-height: 44px;
min-width: 44px;
}
}
/* Only show hover effects for mouse users */
@media (hover: hover) {
.card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
}
Container queries, now supported in all major browsers, represent a significant evolution beyond traditional media queries. While media queries respond to the viewport, container queries respond to the size of a specific parent element. This makes truly reusable components possible: a card component can adapt its layout based on whether it is placed in a narrow sidebar or a wide main content area, without the parent needing to know about the card's internal styling.
/* Define a containment context */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* Default (small container) */
.card {
display: flex;
flex-direction: column;
}
/* When the container is wide enough */
@container card (min-width: 400px) {
.card {
flex-direction: row;
align-items: center;
}
.card img {
width: 40%;
}
}
Container queries solve a long-standing problem in component-based architectures. With media queries alone, a component's responsive behavior is tied to the page width, which means the same component cannot intelligently adapt when used in containers of different sizes on the same page. Container queries decouple the component's responsiveness from the viewport, making components truly self-contained.
To use container queries, you first establish a containment context on the parent element using container-type: inline-size. Then, inside @container blocks, you write conditions based on the container's width. The syntax mirrors media queries, making the learning curve minimal for developers already familiar with @media.
Testing is critical to ensure your media queries work as intended across a range of conditions. Here are the most effective methods:
Every modern browser includes a responsive design mode in its developer tools. In Chrome or Edge, open DevTools (F12) and click the device toolbar toggle (Ctrl+Shift+M). This lets you simulate any viewport width, height, and device pixel ratio without physically having every device. You can also select from preset device profiles (iPhone, iPad, Galaxy, Pixel) that set the viewport to each device's default dimensions.
Our @media helper tool shows you in real time which media features your current device and browser report. This is useful for verifying that your media queries match what you expect on a real device, especially for features like prefers-color-scheme, prefers-reduced-motion, and resolution that cannot be easily checked visually.
While browser emulation covers most cases, testing on actual devices remains important for verifying touch interactions, real-world performance, and the subtle rendering differences between browsers on different platforms. At minimum, test on a current iPhone (Safari), a current Android phone (Chrome), and a desktop browser. Services like BrowserStack and LambdaTest provide access to real devices in the cloud if you do not have a physical device library.
<meta name="viewport" content="width=device-width, initial-scale=1">, mobile browsers will render your page at a desktop width (typically 980px) and zoom out, making your media queries effectively useless on mobile devices.em units respect the user's font size preference, improving accessibility. 48em is equivalent to 768px at the default 16px font size, but it will trigger at a wider pixel value if the user has a larger base font, giving them more space per character.min-width queries in ascending order so each progressively larger breakpoint overrides the previous one naturally through the CSS cascade.@media print block that removes navigation, backgrounds, and other screen-only elements.min-width applies styles when the viewport is at least the specified width (styles apply from that width and up). max-width applies styles when the viewport is at most the specified width (styles apply from that width and down). Mobile-first design uses min-width queries to progressively add styles for larger screens. Desktop-first design uses max-width queries to override styles for smaller screens.
Using em values for breakpoints is technically more robust because they respect the user's default font size setting. A breakpoint at 48em will trigger at a different pixel width if the user has increased their base font size, which is the more accessible behavior. However, pixel values are more intuitive to work with and are used by most CSS frameworks. In practice, both approaches work well. If accessibility is a priority, em-based breakpoints are the safer choice.
All modern browsers include responsive design tools in their developer tools. In Chrome and Edge, press F12, then click the device toolbar icon (or press Ctrl+Shift+M). In Firefox, press F12 and click the responsive design mode button. In Safari, enable the Develop menu in preferences, then choose Develop > Enter Responsive Design Mode. These tools let you simulate any viewport size and device pixel ratio. You can also use the DisplayPixels @media helper tool to see which media queries are currently active on your device.
A media query responds to the viewport (the browser window) dimensions and characteristics. A container query responds to the dimensions of a specific parent element. This means a component styled with container queries adapts based on its own available space rather than the overall page width. Container queries are ideal for reusable components that might appear in differently sized contexts (sidebars, main content areas, modals) within the same page.
Media queries themselves have negligible performance impact. The browser evaluates them very efficiently, and unused CSS rules (those inside non-matching media queries) are parsed but not applied, so they do not affect rendering speed. However, loading large CSS files with extensive media queries can slightly increase download time. For optimization, consider using separate stylesheet files for different media with the media attribute on the <link> tag, which allows browsers to prioritize downloading the relevant stylesheet.