Go Back

Media Queries

Definition

Media queries are a CSS technique that enables developers to apply different style rules based on the characteristics of the device rendering the content. They form the technical foundation of responsive web design, allowing websites to adapt their layout and appearance to different screen sizes, resolutions, orientations, and other device capabilities.

Introduced in CSS3, media queries use the @media rule to conditionally apply CSS when specific device conditions are met. This technique allows a single website to provide an optimal viewing experience across a wide range of devices, from desktop computers to smartphones, without requiring separate websites for different devices.

Syntax and Structure

The basic syntax of a media query consists of:

  1. The @media rule
  2. An optional media type (e.g., screen, print)
  3. One or more expressions that check for specific conditions
  4. The CSS rules to apply when conditions are met
@media [media-type] and ([feature]: [value]) {
  /* CSS rules to apply when conditions are met */
}

Basic Example

/* Base styles for all devices */
body {
  font-size: 16px;
  padding: 10px;
}

/* Styles for screens at least 768px wide */
@media screen and (min-width: 768px) {
  body {
    font-size: 18px;
    padding: 20px;
  }
}

/* Styles for screens at least 1200px wide */
@media screen and (min-width: 1200px) {
  body {
    font-size: 20px;
    padding: 30px;
    max-width: 1140px;
    margin: 0 auto;
  }
}

Media Types

Media types specify the general category of device the styles should apply to:

  • all: Default; matches all devices
  • screen: Computers, tablets, phones, and similar screens
  • print: Print preview mode and printed pages
  • speech: Screen readers and other audio browsers

Example with Media Type

/* Styles for printed documents */
@media print {
  body {
    font-size: 12pt;
    color: black;
    background: white;
  }
  
  nav, .ads, .social-buttons {
    display: none; /* Hide navigation and other elements when printing */
  }
  
  a::after {
    content: " (" attr(href) ")"; /* Show URLs after links when printing */
  }
}

Media Features

Media features describe specific characteristics of the user agent, output device, or environment:

Viewport Dimensions

  • width, min-width, max-width: Viewport width
  • height, min-height, max-height: Viewport height
/* Apply when viewport is between 768px and 1200px wide */
@media (min-width: 768px) and (max-width: 1199px) {
  .container {
    width: 750px;
  }
}

Display Quality

  • resolution: Pixel density (dpi/dpcm/dppx)
  • orientation: Portrait or landscape
  • aspect-ratio: Width-to-height ratio
/* High-resolution (retina) displays */
@media (min-resolution: 2dppx) {
  .logo {
    background-image: url('logo@2x.png');
    background-size: 200px 50px;
  }
}

/* Landscape orientation */
@media (orientation: landscape) {
  .gallery {
    display: flex;
    flex-direction: row;
  }
}

Device Capabilities

  • hover: Ability to hover over elements
  • pointer: Presence and accuracy of pointing device
  • color: Number of bits per color component
  • color-gamut: Approximate range of colors
/* Styles for touch devices without hover capability */
@media (hover: none) and (pointer: coarse) {
  button {
    min-height: 44px; /* Larger touch targets */
    min-width: 44px;
  }
}

/* Styles for devices that support wide color gamuts */
@media (color-gamut: p3) {
  .vibrant-element {
    color: color(display-p3 1 0 0); /* Pure red in Display P3 */
  }
}

User Preferences

  • prefers-reduced-motion: Motion sensitivity preference
  • prefers-color-scheme: Light or dark theme preference
  • prefers-contrast: Contrast preference
  • prefers-reduced-data: Data usage preference
/* Respect user preference for reduced motion */
@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

/* Dark mode support */
@media (prefers-color-scheme: dark) {
  :root {
    --text-color: #f0f0f0;
    --background-color: #121212;
  }
}

Logical Operators

Media queries can use logical operators to create more complex conditions:

  • and: Both conditions must be true
  • not: Negates the query
  • , (comma): Acts as an "or" operator; any condition can be true
  • only: Used to hide media queries from older browsers
/* AND operator: both conditions must be met */
@media (min-width: 768px) and (orientation: landscape) {
  /* Apply when viewport is at least 768px wide AND in landscape orientation */
}

/* OR operator (comma): either condition can be met */
@media (max-width: 767px), (orientation: portrait) {
  /* Apply when viewport is narrower than 768px OR in portrait orientation */
}

/* NOT operator: negates the entire query */
@media not all and (min-width: 1200px) {
  /* Apply when NOT on a screen at least 1200px wide */
}

Common Breakpoints

While breakpoints should be based on content rather than specific devices, these common breakpoints serve as useful starting points:

/* Small devices (phones, 576px and up) */
@media (min-width: 576px) { ... }

/* Medium devices (tablets, 768px and up) */
@media (min-width: 768px) { ... }

/* Large devices (desktops, 992px and up) */
@media (min-width: 992px) { ... }

/* Extra large devices (large desktops, 1200px and up) */
@media (min-width: 1200px) { ... }

/* Extra extra large devices (1400px and up) */
@media (min-width: 1400px) { ... }

Mobile-First vs. Desktop-First Approach

Mobile-First (using min-width):

/* Base styles for mobile */
body {
  font-size: 16px;
}

/* Tablet styles */
@media (min-width: 768px) {
  body {
    font-size: 18px;
  }
}

/* Desktop styles */
@media (min-width: 1200px) {
  body {
    font-size: 20px;
  }
}

Desktop-First (using max-width):

/* Base styles for desktop */
body {
  font-size: 20px;
}

/* Tablet styles */
@media (max-width: 1199px) {
  body {
    font-size: 18px;
  }
}

/* Mobile styles */
@media (max-width: 767px) {
  body {
    font-size: 16px;
  }
}

Implementing Media Queries

In CSS Files

Media queries can be placed directly in CSS files:

/* styles.css */
.container {
  width: 100%;
  padding: 15px;
}

@media (min-width: 768px) {
  .container {
    width: 750px;
    margin: 0 auto;
  }
}

Media queries can also be included in the media attribute of <link> elements:

<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="mobile.css" media="(max-width: 767px)">
<link rel="stylesheet" href="tablet.css" media="(min-width: 768px) and (max-width: 1199px)">
<link rel="stylesheet" href="desktop.css" media="(min-width: 1200px)">

Using @import

Media queries can be used with CSS @import rules (though this method can impact performance):

/* main.css */
@import url('base.css');
@import url('mobile.css') (max-width: 767px);
@import url('tablet.css') (min-width: 768px) and (max-width: 1199px);
@import url('desktop.css') (min-width: 1200px);

Within JavaScript

Media queries can be tested with JavaScript using window.matchMedia():

const mediaQuery = window.matchMedia('(min-width: 768px)');

function handleScreenChange(e) {
  if (e.matches) {
    console.log('Viewport is at least 768px wide');
    // Execute desktop-specific JavaScript
  } else {
    console.log('Viewport is narrower than 768px');
    // Execute mobile-specific JavaScript
  }
}

// Initial check
handleScreenChange(mediaQuery);

// Listen for changes
mediaQuery.addEventListener('change', handleScreenChange);

Common Patterns and Examples

Responsive Navigation

/* Mobile: hamburger menu */
.nav-links {
  display: none;
}

.hamburger {
  display: block;
}

.nav-links.active {
  display: flex;
  flex-direction: column;
}

/* Desktop: horizontal navigation */
@media (min-width: 768px) {
  .nav-links {
    display: flex;
    flex-direction: row;
  }
  
  .hamburger {
    display: none;
  }
}

Responsive Grid Layout

.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

@media (min-width: 576px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 992px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

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

Responsive Typography

:root {
  /* Base font size (16px) */
  font-size: 100%;
}

h1 {
  font-size: 2rem; /* 32px */
}

@media (min-width: 768px) {
  h1 {
    font-size: 2.5rem; /* 40px */
  }
}

@media (min-width: 1200px) {
  h1 {
    font-size: 3rem; /* 48px */
  }
}

/* Fluid typography using calc() */
h2 {
  font-size: calc(1.25rem + 1vw);
}