Skip to content

Media Queries: The Cornerstone of Responsive Design

Imagine you're a fashion designer tasked with creating well-fitting clothes for people of different body types. You can't make everyone wear the same size—you need different versions for different body shapes. In web development, CSS Media Queries play a similar role: they allow your website to automatically adjust styles based on different device characteristics, ensuring perfect presentation on phones, tablets, and desktop computers.

What Are Media Queries?

Media Queries are a powerful feature introduced in CSS3 that allow you to apply different style rules based on device characteristics such as screen width, height, resolution, orientation, etc. Simply put, media queries are like smart switches: when a device meets specific conditions, corresponding styles are activated; when those conditions aren't met, the styles are ignored.

Before media queries appeared, developers often needed to create multiple versions of pages to adapt to different devices, which was extremely costly to maintain. The emergence of media queries completely changed this situation, making it possible for one codebase to adapt to multiple platforms.

Basic Syntax

The basic syntax structure of media queries is as follows:

css
/* Basic syntax */
@media media-type and (media-feature) {
  /* Styles applied when conditions are met */
  .element {
    property: value;
  }
}

Let's look at a practical example:

css
/* When screen width is less than or equal to 768px */
@media screen and (max-width: 768px) {
  .container {
    width: 100%;
    padding: 10px;
  }

  .sidebar {
    display: none; /* Hide sidebar on small screens */
  }
}

This media query means: when users are using a screen device (screen) and the screen width doesn't exceed 768px, apply the style rules within the curly braces. In this example, the container will take up the full width and the sidebar will be hidden, providing a better user experience on small screens.

Media Types

Media types are used to specify device categories. Although the CSS specification defines multiple media types, the most commonly used in actual development are:

screen - Screen Devices

This is the most commonly used media type, applicable to computer screens, tablets, phones, and all other screen devices:

css
@media screen {
  body {
    font-family: Arial, sans-serif;
  }
}

These styles are applied when users print a page. Print styles typically hide navigation bars, sidebars, and other non-essential elements to optimize paper usage:

css
@media print {
  .navigation,
  .sidebar,
  .footer {
    display: none; /* Remove these elements when printing */
  }

  body {
    font-size: 12pt; /* Points are more suitable for printing */
    color: black;
    background: white;
  }
}

all - All Devices

Applies to all media types. If no media type is specified, all is the default:

css
/* These two approaches have the same effect */
@media all and (min-width: 600px) {
}
@media (min-width: 600px) {
}

In modern development, since screen covers the vast majority of scenarios, many developers omit the media type and write media features directly.

Media Features

Media features are the core of media queries; they describe the specific characteristics of devices. Let's explore the most commonly used ones in detail.

max-width - Maximum Width

Matches when the viewport width is less than or equal to the specified value:

css
/* Adapt to mobile devices: screen width not exceeding 480px */
@media (max-width: 480px) {
  .header {
    font-size: 18px;
  }

  .content {
    padding: 8px;
  }
}

Assuming a user accesses with a phone (screen width 375px), these styles will be activated because 375 ≤ 480. However, if a user accesses with a desktop computer (screen width 1920px), these styles will not be applied.

min-width - Minimum Width

Matches when the viewport width is greater than or equal to the specified value:

css
/* Adapt to large screen devices: screen width at least 1024px */
@media (min-width: 1024px) {
  .container {
    max-width: 1200px;
    margin: 0 auto; /* Center container */
  }

  .sidebar {
    width: 300px;
    float: left;
  }
}

When the screen width is 1440px, since 1440 ≥ 1024, these styles will be applied, displaying a sidebar and using a more spacious layout.

width - Exact Width

Precisely matches a specific width (rarely used in practice because it's difficult to control precisely):

css
@media (width: 768px) {
  /* Only activated when screen width is exactly 768px */
}

Height features are similar to width features but target viewport height:

css
/* When viewport height is small (like landscape phones) */
@media (max-height: 500px) {
  .header {
    height: 50px; /* Reduce header height */
  }

  .content {
    padding-top: 10px; /* Reduce padding to save vertical space */
  }
}

This is particularly useful when handling landscape devices, helping you optimize vertical space utilization.

orientation - Device Orientation

Detects whether the device is in landscape or portrait mode:

css
/* Portrait (portrait): height greater than width */
@media (orientation: portrait) {
  .gallery {
    grid-template-columns: 1fr 1fr; /* Two-column layout */
  }
}

/* Landscape (landscape): width greater than height */
@media (orientation: landscape) {
  .gallery {
    grid-template-columns: repeat(4, 1fr); /* Four-column layout */
  }
}

When a user rotates their phone from portrait to landscape, the image gallery will automatically switch from two columns to four columns, making full use of horizontal space.

aspect-ratio - Aspect Ratio

Detects the viewport's aspect ratio:

css
/* 16:9 widescreen monitor */
@media (aspect-ratio: 16/9) {
  .video-container {
    width: 100%;
  }
}

/* Minimum aspect ratio */
@media (min-aspect-ratio: 1/1) {
  /* When width is greater than or equal to height */
}

resolution - Resolution

Used to detect device pixel density, commonly used to adapt to high-definition screens (like Retina displays):

css
/* Standard screen */
.logo {
  background-image: url("logo-1x.png");
}

/* High-definition screen (2x pixel density) */
@media (min-resolution: 192dpi), (min-resolution: 2dppx) {
  .logo {
    background-image: url("logo-2x.png");
    background-size: 100px 50px; /* Display size remains unchanged */
  }
}

On iPhones or MacBooks with retina screens, this code will load high-resolution images to ensure icons are sharp and clear.

Logical Operators

Media queries support logical operators that allow you to combine multiple conditions.

and - Logical AND

All conditions must be satisfied:

css
/* Must satisfy all: screen device + width between 600px and 900px */
@media screen and (min-width: 600px) and (max-width: 900px) {
  .container {
    width: 90%;
    padding: 20px;
  }
}

Only when users are using a screen device and the viewport width is between 600px and 900px will these styles be applied. If the width is 500px or 1000px, the styles will not be applied.

, (comma) - Logical OR

Satisfy any one condition, equivalent to "OR" operation:

css
/* Applied when width is less than 480px OR greater than 1200px */
@media (max-width: 480px), (min-width: 1200px) {
  .responsive-text {
    font-size: 14px;
  }
}

This is useful when adapting to both mobile and ultra-large screens—both extreme scenarios can share the same style treatment.

not - Logical NOT

Exclude specific conditions:

css
/* Non-screen devices (like print) */
@media not screen {
  body {
    background: white;
    color: black;
  }
}

/* Width not between 600px and 900px */
@media not all and (min-width: 600px) and (max-width: 900px) {
  /* Only activated when width < 600px or > 900px */
}

Note that not negates the entire media query, not individual conditions.

only - Qualifier

only is mainly used for compatibility with old browsers to prevent incorrect style application in browsers that don't support media queries:

css
@media only screen and (min-width: 768px) {
  /* Only screen devices that support media queries will apply these styles */
}

In modern development, since old browsers are now rare, the use of only has decreased.

Practical Application Scenarios

Responsive Navigation Bar

Let's look at a complete example showing how to create a responsive navigation bar with media queries:

css
/* Default styles (desktop) */
.navbar {
  display: flex;
  justify-content: space-between;
  padding: 15px 30px;
  background-color: #333;
}

.nav-menu {
  display: flex;
  gap: 20px;
  list-style: none;
}

.nav-toggle {
  display: none; /* Hide hamburger menu button on desktop */
}

/* Tablet: 768px to 1024px */
@media (min-width: 768px) and (max-width: 1024px) {
  .navbar {
    padding: 12px 20px;
  }

  .nav-menu {
    gap: 15px;
    font-size: 14px;
  }
}

/* Mobile: less than 768px */
@media (max-width: 767px) {
  .navbar {
    flex-direction: column;
    padding: 10px 15px;
  }

  .nav-toggle {
    display: block; /* Show hamburger menu button */
    cursor: pointer;
  }

  .nav-menu {
    display: none; /* Hide menu by default */
    flex-direction: column;
    width: 100%;
    gap: 0;
  }

  .nav-menu.active {
    display: flex; /* Show after button click */
  }

  .nav-menu li {
    padding: 12px 0;
    border-bottom: 1px solid #555;
  }
}

In this example:

  • Desktop (width ≥ 1024px): Shows horizontal navigation bar with menu items displayed side by side
  • Tablet (768px ≤ width < 1024px): Fine-tunes spacing and font size to fit medium screens
  • Mobile (width < 768px): Switches to vertical layout, uses hamburger menu to save horizontal space

Responsive Grid System

css
.grid-container {
  display: grid;
  gap: 20px;
  padding: 20px;
}

/* Large screens: 4 columns */
@media (min-width: 1200px) {
  .grid-container {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Medium screens: 3 columns */
@media (min-width: 900px) and (max-width: 1199px) {
  .grid-container {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Tablet: 2 columns */
@media (min-width: 600px) and (max-width: 899px) {
  .grid-container {
    grid-template-columns: repeat(2, 1fr);
    gap: 15px;
  }
}

/* Phone: 1 column */
@media (max-width: 599px) {
  .grid-container {
    grid-template-columns: 1fr;
    gap: 10px;
    padding: 10px;
  }
}

As screen width changes, the grid automatically adjusts column count. On a 1400px desktop monitor it shows 4 columns, on a 750px tablet it shows 2 columns, and on a 375px phone it shows 1 column.

Nested Media Queries

Although uncommon, media queries can be nested when needed:

css
@media screen {
  .container {
    padding: 20px;
  }

  @media (max-width: 768px) {
    .container {
      padding: 10px; /* Reduce padding on small screens */
    }
  }
}

However, in modern development it's recommended to use flat, independent media queries for better readability and maintenance.

Using Media Queries in HTML

Besides using them in CSS, media queries can also be used directly in HTML <link> tags:

html
<!-- Default stylesheet -->
<link rel="stylesheet" href="base.css" />

<!-- Load only on large screens -->
<link rel="stylesheet" href="desktop.css" media="(min-width: 1024px)" />

<!-- Load only on small screens -->
<link rel="stylesheet" href="mobile.css" media="(max-width: 767px)" />

<!-- Print styles -->
<link rel="stylesheet" href="print.css" media="print" />

The advantage of this approach is reducing unnecessary CSS downloads. For example, when accessing on a mobile device, desktop.css won't be downloaded at all, saving bandwidth.

Detecting Media Queries with JavaScript

Sometimes you need to execute different logic in JavaScript based on media query results:

javascript
// Create media query object
const mediaQuery = window.matchMedia("(max-width: 768px)");

// Check if currently matches
if (mediaQuery.matches) {
  console.log("Currently mobile device");
  // Execute mobile-specific logic
} else {
  console.log("Currently desktop device");
}

// Listen for media query changes
mediaQuery.addEventListener("change", (e) => {
  if (e.matches) {
    console.log("Switched to mobile view");
    // Adjust UI components
  } else {
    console.log("Switched to desktop view");
  }
});

This is useful when you need to dynamically load components, initialize plugins, or adjust interaction behaviors based on screen size. For example, using hover effects on desktop and touch events on mobile.

Common Problems and Best Practices

Problem 1: Media Queries Not Working

The most common reason is forgetting to add the viewport meta tag in HTML:

html
<!-- This tag must be added, otherwise mobile devices will render in desktop mode -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

Without this tag, mobile browsers will pretend to be desktop browsers (typically 980px wide), causing your mobile media queries to never trigger.

Problem 2: Chaotic Breakpoint Settings

It's recommended to use a consistent breakpoint system rather than setting them arbitrarily. Recommend using a mobile-first approach (from small to large):

css
/* Recommended: Mobile-first breakpoint system */
/* Mobile (default, no media query needed) */
/* 0 - 767px */

/* Tablet */
@media (min-width: 768px) {
  /* 768px and above */
}

/* Desktop */
@media (min-width: 1024px) {
  /* 1024px and above */
}

/* Large desktop */
@media (min-width: 1200px) {
  /* 1200px and above */
}

This mobile-first approach is more in line with modern development practices and performs better than desktop-first (using max-width). Avoid using too many breakpoints (recommend no more than 4-5), otherwise the code becomes difficult to maintain.

Problem 3: Style Override Order

The order of media queries is important. If using min-width (mobile-first), arrange them from small to large:

css
/* ✅ Correct: from small to large */
.container {
  width: 100%;
} /* Base styles (mobile) */

@media (min-width: 600px) {
  .container {
    width: 90%;
  }
}

@media (min-width: 1024px) {
  .container {
    width: 1000px;
  }
}

If using max-width (desktop-first), arrange them from large to small:

css
/* ✅ Correct: from large to small */
.container {
  width: 1000px;
} /* Base styles (desktop) */

@media (max-width: 1023px) {
  .container {
    width: 90%;
  }
}

@media (max-width: 599px) {
  .container {
    width: 100%;
  }
}

Best Practice Recommendations

  1. Mobile First: Prioritize small screen styling, then use min-width to progressively enhance, ensuring optimal mobile performance.

  2. Use Relative Units: Use em or rem instead of px in media queries, so breakpoints adjust accordingly when users change browser default font size:

css
/* Use em: 1em ≈ 16px (browser default) */
@media (min-width: 48em) {
  /* Approximately 768px */
}
  1. Avoid Targeting Specific Devices: Don't write "iPhone 6 specific" or "iPad specific" media queries. Devices are constantly changing; breakpoints should be based on actual content needs.

  2. Test on Real Devices: Browser developer tools device simulation is useful, but be sure to test on actual devices, as actual rendering may have subtle differences.

Summary

Media queries are the core tool of responsive design, allowing you to intelligently adjust page styles based on device characteristics. By reasonably using media types, media features, and logical operators, you can create websites that perform excellently on all devices.

Key takeaways:

  • Always add viewport meta tag
  • Use standardized breakpoint systems
  • Pay attention to media query order
  • Prioritize mobile user experience
  • Design breakpoints based on content, not devices