Toolmingo
Guides10 min read

CSS Media Queries Cheat Sheet: Complete Reference with Examples

The definitive CSS media queries reference — syntax, breakpoints, feature queries, dark mode, print styles, and a quick-copy cheat sheet for responsive design.

Media queries are the foundation of responsive design. They let CSS apply rules conditionally — based on screen width, orientation, colour scheme preference, input type, and dozens of other features. This cheat sheet covers every syntax you'll reach for, from basic breakpoints to modern container queries.


Quick reference

Pattern Code
Mobile-first min-width @media (min-width: 768px) { }
Desktop-first max-width @media (max-width: 767px) { }
Range (both bounds) @media (min-width: 640px) and (max-width: 1023px) { }
Modern range syntax @media (width >= 768px) { }
Portrait orientation @media (orientation: portrait) { }
Dark mode @media (prefers-color-scheme: dark) { }
Reduced motion @media (prefers-reduced-motion: reduce) { }
Hover capable device @media (hover: hover) { }
Print styles @media print { }
High-DPI / Retina @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { }
Container query @container sidebar (min-width: 300px) { }

Basic syntax

A media query has an optional media type and one or more media features:

@media [media-type] [and (feature: value)] {
  /* rules */
}

Media types:

Type Matches
all Everything (default when omitted)
screen Screens (monitors, phones, tablets)
print Print preview and printed pages
speech Screen readers

You can omit the type — @media (min-width: 768px) defaults to all.

Logical operators:

Operator Example Meaning
and screen and (min-width: 768px) Both conditions must be true
, (or) screen, print Either condition matches
not not print Negates the whole query
only only screen and (...) Hides from old parsers (legacy)

Breakpoints

Mobile-first (recommended)

Write your base styles for small screens, then add min-width overrides as screens grow:

/* Base: mobile */
.container {
  padding: 1rem;
}

/* Tablet and up */
@media (min-width: 768px) {
  .container {
    padding: 2rem;
  }
}

/* Desktop and up */
@media (min-width: 1024px) {
  .container {
    max-width: 1280px;
    margin: 0 auto;
  }
}

Desktop-first

Write styles for large screens, override downward with max-width:

.sidebar {
  width: 300px;
}

@media (max-width: 1023px) {
  .sidebar {
    width: 100%;
  }
}

Common breakpoint systems

Tailwind CSS breakpoints (mobile-first):

Name Min-width
sm 640 px
md 768 px
lg 1024 px
xl 1280 px
2xl 1536 px

Bootstrap 5 breakpoints:

Name Min-width
sm 576 px
md 768 px
lg 992 px
xl 1200 px
xxl 1400 px

You don't have to use a framework's values — pick breakpoints based on where your content breaks, not device sizes.


Modern range syntax (Level 4)

The traditional min-/max- prefixes are wordy. CSS Media Queries Level 4 adds comparison operators:

/* Old syntax */
@media (min-width: 768px) and (max-width: 1023px) { }

/* New range syntax */
@media (768px <= width < 1024px) { }
/* or equivalently */
@media (width >= 768px) and (width < 1024px) { }

Supported in all modern browsers (Chrome 113+, Firefox 63+, Safari 16.4+).


Width and height

/* Minimum viewport width */
@media (min-width: 600px) { }

/* Maximum viewport width */
@media (max-width: 599px) { }

/* Exact range */
@media (min-width: 600px) and (max-width: 1199px) { }

/* Minimum viewport height */
@media (min-height: 600px) { }

/* Useful for landscape phones */
@media (max-height: 500px) and (orientation: landscape) {
  .hero {
    min-height: 100vh; /* avoid if keyboard pushes height down */
  }
}

Orientation

@media (orientation: portrait) {
  /* taller than wide */
  .gallery {
    grid-template-columns: 1fr;
  }
}

@media (orientation: landscape) {
  /* wider than tall */
  .gallery {
    grid-template-columns: repeat(3, 1fr);
  }
}

Note: a square viewport matches neither portrait nor landscape.


User preference queries

These react to operating system or browser settings — use them to respect user choices.

Dark mode

:root {
  --bg: #ffffff;
  --text: #111111;
  --card: #f8f8f8;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #111111;
    --text: #eeeeee;
    --card: #1e1e1e;
  }
}

body {
  background: var(--bg);
  color: var(--text);
}

Reduced motion

Always add this guard around any animation:

.spinner {
  animation: spin 1s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
    /* show a static fallback instead */
  }
}

/* Or use the positive value to add motion */
@media (prefers-reduced-motion: no-preference) {
  .hero-image {
    transition: transform 0.4s ease;
  }
}

Other preference queries

/* User prefers high contrast */
@media (prefers-contrast: more) {
  .button {
    border: 2px solid currentColor;
  }
}

/* User prefers less data (e.g. metered connection) */
@media (prefers-reduced-data: reduce) {
  .hero-video {
    display: none;
  }
}

/* Forced colours mode (Windows High Contrast) */
@media (forced-colors: active) {
  .icon {
    fill: ButtonText;
  }
}

Input and pointer queries

/* Device has a fine pointer (mouse) */
@media (pointer: fine) {
  .button {
    padding: 0.5rem 1rem;
  }
}

/* Device has a coarse pointer (touchscreen) */
@media (pointer: coarse) {
  .button {
    min-height: 44px; /* WCAG touch target */
    padding: 0.75rem 1.5rem;
  }
}

/* Device can hover (has a mouse) */
@media (hover: hover) {
  .card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  }
}

/* Device cannot hover reliably (touch) */
@media (hover: none) {
  .tooltip {
    display: none; /* hide hover-only tooltips */
  }
}

/* Common combination: mouse user */
@media (hover: hover) and (pointer: fine) {
  .nav-item:hover .dropdown {
    display: block;
  }
}

Resolution / DPI

Use these to serve higher-quality images on Retina and HiDPI displays:

/* 1× screens */
.logo {
  background-image: url('/logo.png');
}

/* 2× Retina and above */
@media (-webkit-min-device-pixel-ratio: 2),
       (min-resolution: 192dpi) {
  .logo {
    background-image: url('/logo@2x.png');
    background-size: 120px 40px; /* half the pixel size */
  }
}

/* 3× (iPhone Pro / Android flagships) */
@media (-webkit-min-device-pixel-ratio: 3),
       (min-resolution: 288dpi) {
  .logo {
    background-image: url('/logo@3x.png');
  }
}

Prefer <img srcset> or CSS image-set() over media queries for images — they're cleaner and let the browser decide.


Print styles

@media print {
  /* Hide UI chrome */
  nav,
  footer,
  .sidebar,
  .cookie-banner,
  button {
    display: none !important;
  }

  /* Ensure black text on white */
  body {
    color: #000;
    background: #fff;
    font-size: 12pt;
  }

  /* Expand links to show URL */
  a[href]::after {
    content: ' (' attr(href) ')';
    font-size: 0.8em;
    color: #666;
  }

  /* Avoid page breaks inside cards */
  .card,
  table,
  figure {
    break-inside: avoid;
  }

  /* Add page break before major sections */
  h1, h2 {
    break-after: avoid;
  }
}

Container queries

Container queries let a component respond to its parent's size instead of the viewport — essential for reusable components that appear in different contexts.

/* 1. Establish a containment context */
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

/* 2. Query the container */
@container sidebar (min-width: 300px) {
  .card {
    display: flex;
    flex-direction: row;
  }
}

/* Without a name — queries the nearest containment ancestor */
.card-wrapper {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .card {
    grid-template-columns: 200px 1fr;
  }
}

Container query units:

Unit Meaning
cqw 1% of container's inline size (width)
cqh 1% of container's block size (height)
cqi 1% of container's inline size
cqb 1% of container's block size
cqmin Smaller of cqi/cqb
cqmax Larger of cqi/cqb
.card h2 {
  font-size: clamp(1rem, 5cqw, 2rem);
}

Browser support: Chrome 105+, Firefox 110+, Safari 16+.


Combining queries

/* AND: both conditions must match */
@media screen and (min-width: 768px) and (orientation: landscape) {
  .panel {
    flex-direction: row;
  }
}

/* OR (comma): either matches */
@media (max-width: 640px), (orientation: portrait) {
  .nav {
    flex-direction: column;
  }
}

/* NOT: negates the whole query */
@media not print {
  .no-print-label {
    display: none;
  }
}

/* NOT with and (Level 4 — use parentheses) */
@media not (prefers-color-scheme: dark) {
  /* light mode only */
}

4 practical patterns

1. Responsive navigation

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

/* Desktop: horizontal links */
@media (min-width: 1024px) {
  .nav-links {
    display: flex;
    gap: 2rem;
  }
  .hamburger {
    display: none;
  }
}

2. Fluid typography with clamp (no media query needed)

/* Scales from 1rem at 320px to 1.5rem at 1280px */
h1 {
  font-size: clamp(1.5rem, 2.5vw + 0.5rem, 3rem);
}

Use clamp() for font sizes and spacing — it often eliminates multiple breakpoints.

3. Dark mode with class override

@media (prefers-color-scheme: dark) {
  :root:not(.light) {
    --bg: #111;
    --text: #eee;
  }
}

.dark {
  --bg: #111;
  --text: #eee;
}

Add .dark or .light to <html> via JS to let users override the system preference.

4. Safe area insets (notch / home bar)

/* Needed on iPhone X and later */
body {
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

/* Only apply on devices that need it */
@supports (padding: env(safe-area-inset-bottom)) {
  .fixed-footer {
    padding-bottom: calc(1rem + env(safe-area-inset-bottom));
  }
}

6 common mistakes

1. Writing desktop-first then struggling to override

/* Bad: specific desktop styles hard to undo on mobile */
.grid { display: grid; grid-template-columns: repeat(4, 1fr); }
@media (max-width: 768px) { .grid { display: block; } }

/* Good: start simple, enhance upward */
.grid { display: block; }
@media (min-width: 768px) { .grid { display: grid; grid-template-columns: repeat(4, 1fr); } }

2. Using max-width and min-width on the same breakpoint (overlap)

/* Bug: 768px matches both */
@media (min-width: 768px) { .box { color: blue; } }
@media (max-width: 768px) { .box { color: red; } }

/* Fix: use < instead of <= */
@media (min-width: 768px) { .box { color: blue; } }
@media (max-width: 767px) { .box { color: red; } }
/* or with Level 4 range: */
@media (width < 768px) { .box { color: red; } }

3. Forgetting the viewport meta tag

Without this in <head>, mobile browsers scale the page down and media queries fire at wrong widths:

<meta name="viewport" content="width=device-width, initial-scale=1">

4. Querying viewport width for components

If a component appears in a sidebar (300 px wide) and in the main content (800 px wide), viewport-based queries can't target both correctly. Use container queries instead.

5. Animating without prefers-reduced-motion

/* Always guard animations */
@media (prefers-reduced-motion: no-preference) {
  .fade-in {
    animation: fadeIn 0.5s ease;
  }
}

6. Using min-device-width (deprecated)

min-device-width queried the device screen size, not the browser viewport. It's deprecated and unreliable — always use min-width (viewport).


6 FAQ

Q: Should I use pixels or ems for breakpoints?
Em-based breakpoints (min-width: 48em) scale with the user's browser font size setting. If a user has set 20 px base text, your breakpoint triggers at 960 px instead of 768 px, which can improve readability. Pixel breakpoints are simpler but ignore font preferences. Both approaches are valid — pick one and stay consistent.

Q: How many breakpoints do I need?
Start with two or three (mobile/tablet/desktop). Add a breakpoint only when your content actually breaks — not to match common device widths. A fluid layout with clamp() and CSS Grid auto-fill often needs zero breakpoints.

Q: Are container queries a replacement for media queries?
Complementary, not a replacement. Use media queries for global layout (nav, page structure, print, dark mode). Use container queries for reusable components that must respond to their context (cards, sidebars, widgets).

Q: How do I test media queries quickly?
Chrome DevTools → Toggle Device Toolbar (Ctrl+Shift+M / Cmd+Shift+M). Drag the viewport width to see breakpoints fire in real time. You can also add custom device presets.

Q: What is the only keyword for?
@media only screen and (...) was introduced to hide styles from old browsers (IE 5–6) that didn't understand media features but would still apply the block. Modern browsers all support media features, so only is effectively obsolete — you can omit it.

Q: Can I use JavaScript to read media queries?
Yes. window.matchMedia('(min-width: 768px)').matches returns a boolean. Add a listener with .addEventListener('change', handler) to react when the query state changes:

const mq = window.matchMedia('(prefers-color-scheme: dark)');

function handleChange(e) {
  document.documentElement.classList.toggle('dark', e.matches);
}

mq.addEventListener('change', handleChange);
handleChange(mq); // run once on load

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools