Back to Blog
Development 11 min read March 14, 2026

Modern CSS Media Queries Beyond Width and Height

Most developers know @media (max-width: 768px), but CSS media queries in 2026 cover far more than viewport dimensions. User preferences, input capabilities, display modes, and even component-level context are all queryable — and using them correctly is the difference between a site that feels native and one that merely fits the screen.

Beyond Width: The Full Picture

The @media rule was introduced in CSS2 back in 1998, but for most of the following decade it was used almost exclusively to target print stylesheets. Responsive web design, popularised by Ethan Marcotte's 2010 article, brought viewport-width queries into the mainstream. For years, that was the whole story: you wrote breakpoints, you adjusted layouts, you called it responsive.

The modern CSS Media Queries specification — currently at Level 5 — is a different beast entirely. It introduces a category called media features that lets you query not just the size of the viewport but the capabilities and preferences of the device and the person using it. You can ask whether the user prefers dark mode, whether they have asked the OS to reduce animations, whether the primary input is a mouse or a finger, and whether the display is running as a standalone installed app.

These queries are not niche. Dark mode alone is enabled by a majority of users on mobile platforms. Touch-only input is the norm for the 116 smartphones and 14 tablets in the DeviceSpecsHub database — that is over 70% of all tracked devices. Writing CSS that ignores these realities is writing CSS for a world that no longer exists.

This guide walks through every major non-dimension media feature, explains what it detects, shows real code examples, and flags the browser support situation so you know what you can ship today versus what needs a progressive enhancement wrapper.

prefers-color-scheme: Respecting the User's Theme

prefers-color-scheme is the most widely adopted non-dimension media feature. It reads the operating system's light/dark mode setting and lets you apply a matching stylesheet. The two values are light and dark.

CSS
/* Base styles are light — override for dark */
body {
  background: #ffffff;
  color: #1e293b;
}

@media (prefers-color-scheme: dark) {
  body {
    background: #0f172a;
    color: #e2e8f0;
  }

  a {
    color: #67e8f9; /* cyan-300 — readable on dark backgrounds */
  }
}

The common mistake is to write all your dark-mode styles as overrides at the end of your stylesheet. This works, but it creates specificity battles and makes the code hard to maintain. A better pattern is to use CSS custom properties (variables) and only change the variable values inside the media query:

CSS
:root {
  --bg: #ffffff;
  --text: #1e293b;
  --border: #e2e8f0;
  --accent: #0891b2; /* cyan-600 */
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f172a;
    --text: #e2e8f0;
    --border: #1e293b;
    --accent: #67e8f9; /* cyan-300 — lighter for dark bg */
  }
}

/* All components reference variables — no duplication */
.card {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
}

This approach means you define each component's styles once and the theme switch happens automatically. It also makes it trivial to add a manual theme toggle later — you just apply a data-theme="dark" attribute to :root and mirror the media query values there.

Important: If you are using a JavaScript framework with a theme provider (React, Vue, etc.), make sure your CSS variable approach is consistent with how the framework applies the theme class. A common bug is having both a prefers-color-scheme media query and a .dark class that set conflicting values. Pick one source of truth.

Testing prefers-color-scheme

In Chrome DevTools, open the Rendering panel (⋮ → More tools → Rendering) and find "Emulate CSS media feature prefers-color-scheme". This lets you toggle between light and dark without changing your OS setting, which is far faster for development. Firefox has an equivalent in its DevTools toolbar.

prefers-reduced-motion: Animations That Don't Hurt

Some users experience motion sickness, vertigo, or seizures triggered by animations and transitions. macOS, iOS, Android, and Windows all expose a system-level "reduce motion" setting. The prefers-reduced-motion media feature reads that setting.

The values are no-preference (default — animations are fine) and reduce (the user has asked for less motion). The correct approach is to write your full animations first, then override them inside the media query:

CSS
/* Full animation by default */
.hero-image {
  animation: float 3s ease-in-out infinite;
}

.modal {
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Respect the user's preference */
@media (prefers-reduced-motion: reduce) {
  .hero-image {
    animation: none;
  }

  .modal {
    transition: opacity 0.15s ease; /* Fade is fine — movement is not */
  }

  /* Nuclear option: disable ALL transitions and animations */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

The "nuclear option" at the bottom is a useful safety net for large codebases where you cannot audit every animation individually. It is aggressive — it will also kill useful micro-interactions like button press feedback — so use it as a starting point and then selectively re-enable the transitions that are purely opacity-based and safe.

In JavaScript, you can read the same preference with window.matchMedia('(prefers-reduced-motion: reduce)').matches. This is useful for controlling animations driven by JavaScript libraries (GSAP, Framer Motion, etc.) that CSS cannot reach.

Accessibility note: prefers-reduced-motion is not just a nice-to-have. The WCAG 2.1 Success Criterion 2.3.3 (AAA) explicitly requires that motion animation triggered by interaction can be disabled. Many large organisations now require WCAG AA compliance as a minimum, and respecting this preference is increasingly expected even at that level.

hover and pointer: Knowing Your Input Device

This is one of the most practically useful and most underused media feature pair in CSS. The hover feature tells you whether the primary pointing device can hover over elements without activating them. The pointer feature tells you the precision of that pointing device.

FeatureValueMeaningTypical Device
hoverhoverCan hover without activatingDesktop mouse, laptop trackpad
hovernoneCannot hover (or no pointer)Touchscreen phone, tablet, keyboard-only
pointerfineHigh-precision pointerMouse, stylus, trackpad
pointercoarseLow-precision pointerFinger on touchscreen
pointernoneNo pointer deviceKeyboard-only, TV remote

The key insight is that these features describe the primary input device. A laptop with a touchscreen reports hover: hover and pointer: finebecause the trackpad is the primary input, even though the touchscreen is also present. The any-hover and any-pointer variants let you check if any input device has that capability.

CSS
/* Only show hover effects when hovering is actually possible */
@media (hover: hover) and (pointer: fine) {
  .card:hover {
    transform: translateY(-4px);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
  }

  .nav-link::after {
    content: '';
    display: block;
    height: 2px;
    background: currentColor;
    transform: scaleX(0);
    transition: transform 0.2s ease;
  }

  .nav-link:hover::after {
    transform: scaleX(1);
  }
}

/* Make touch targets larger on coarse-pointer devices */
@media (pointer: coarse) {
  .button {
    min-height: 44px; /* Apple HIG minimum tap target */
    min-width: 44px;
    padding: 12px 20px;
  }

  .checkbox-label {
    padding: 12px 0; /* Expand the tap area */
  }
}

The 44px minimum tap target size comes from Apple's Human Interface Guidelines and is echoed by Google's Material Design (48px) and WCAG 2.5.5 (24px minimum, 44px recommended). Using pointer: coarse to apply these sizes only on touch devices means you are not wasting space on desktop layouts where a mouse can hit a 16px target without difficulty.

Why hover effects on touchscreens are a problem

On iOS and Android, a "hover" state is simulated on the first tap. This means if you have a hover effect that changes background colour or shows a tooltip, the user has to tap twice to activate the underlying link — once to trigger the hover state, and once to actually navigate. Wrapping all your hover effects in @media (hover: hover) eliminates this problem entirely.

prefers-contrast: High-Contrast Mode Support

Windows High Contrast Mode and similar accessibility settings on other platforms are used by people with low vision, colour blindness, or other visual impairments. The prefers-contrast media feature lets you detect and respond to these settings.

ValueMeaning
no-preferenceNo contrast preference set
moreUser prefers higher contrast
lessUser prefers lower contrast (rare)
forcedOS is forcing a colour scheme (Windows High Contrast)
CSS
/* Enhance borders and text contrast when requested */
@media (prefers-contrast: more) {
  .card {
    border: 2px solid #000000; /* Stronger border */
  }

  .muted-text {
    color: #374151; /* Darker than the default slate-500 */
  }

  .badge {
    outline: 2px solid currentColor; /* Ensure badges are visible */
  }
}

/* Handle Windows Forced Colors mode */
@media (forced-colors: active) {
  .custom-checkbox {
    forced-color-adjust: none; /* Opt out of forced colours for this element */
    border: 2px solid ButtonText;
    background: ButtonFace;
  }
}

The forced-colors: active query is specifically for Windows High Contrast Mode, where the OS replaces all colours with a small system palette. Custom-styled form controls often break completely in this mode because their visual styling is entirely CSS-based. The forced-color-adjust: none property lets you opt a specific element out of the forced colour scheme so you can apply your own high-contrast styles.

prefers-reduced-data: Respecting Data Limits

This is the newest and least supported of the preference queries, but it is worth knowing about. prefers-reduced-data detects when a user has enabled a "data saver" or "low data" mode on their device or browser. The intended use is to serve lower-resolution images, skip autoplay video, and avoid loading non-essential resources.

CSS
/* Serve smaller images on data-saver connections */
@media (prefers-reduced-data: reduce) {
  .hero-background {
    background-image: url('/hero-small.webp'); /* 50KB instead of 500KB */
  }

  .decorative-video {
    display: none; /* Skip the background video entirely */
  }
}

/* In JavaScript: skip analytics and tracking pixels */

As of early 2026, prefers-reduced-data is supported in Chromium-based browsers behind a flag but has not shipped in stable Firefox or Safari. Use it as progressive enhancement — it will not hurt browsers that do not support it, and it will benefit users on the browsers that do.

display-mode: Detecting Installed PWAs

Progressive Web Apps can be installed to a device's home screen and launched in a standalone window without browser chrome. The display-mode media feature lets you detect this and adjust your UI accordingly — for example, hiding a "Install App" banner when the app is already installed, or showing a custom title bar.

ValueMeaning
browserRunning in a standard browser tab
standaloneInstalled PWA, no browser UI
minimal-uiInstalled PWA with minimal browser controls
fullscreenRunning fullscreen (games, video apps)
CSS
/* Hide the install prompt when already installed */
.install-banner {
  display: block;
}

@media (display-mode: standalone) {
  .install-banner {
    display: none;
  }

  /* Add padding for the status bar on mobile */
  .app-header {
    padding-top: env(safe-area-inset-top);
  }
}

/* In JavaScript: same check */
const isInstalled = window.matchMedia('(display-mode: standalone)').matches;

The env(safe-area-inset-top) value is worth noting here. On iPhones with a Dynamic Island or notch, the safe area inset ensures your header does not overlap the system UI. This is not a media query feature itself, but it is commonly paired withdisplay-mode: standalone because the notch overlap only becomes a problem when the browser chrome is removed.

Container Queries: The Component-Level Revolution

Container queries are not strictly a media feature — they query the size of a parent element rather than the viewport — but they belong in any modern responsive CSS discussion because they solve a problem that viewport-based media queries fundamentally cannot.

The problem: a card component that appears in a narrow sidebar should look different from the same card in a wide main content area. With viewport media queries, you cannot express this cleanly because the viewport width is the same in both cases. With container queries, you can.

CSS
/* 1. Establish a containment context on the parent */
.card-grid {
  container-type: inline-size;
  container-name: card-container;
}

/* 2. Query the container's width, not the viewport's */
@container card-container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 120px 1fr;
    gap: 1rem;
  }

  .card-image {
    aspect-ratio: 1;
    border-radius: 8px;
  }
}

/* Shorthand — container name is optional for simple cases */
.sidebar {
  container-type: inline-size;
}

@container (max-width: 300px) {
  .nav-item span {
    display: none; /* Icon-only nav in narrow sidebars */
  }
}

Container queries shipped in all major browsers in 2023 and are now safe to use without a polyfill. They are particularly powerful for design systems and component libraries where the same component needs to adapt to many different layout contexts without knowing anything about the page it is placed in.

Container queries and the DeviceSpecsHub Viewport Reference: The Viewport Reference page shows CSS viewport sizes for 185+ devices. Container queries let you build components that adapt to their container rather than the viewport — which means those viewport numbers become a starting point for your container breakpoints rather than the whole story.

Combining Queries: The Real Power

The real power of modern media queries comes from combining them. You can use and, or (written as a comma), and not to build precise targeting rules.

CSS
/* Touch device in dark mode: large tap targets with dark colours */
@media (pointer: coarse) and (prefers-color-scheme: dark) {
  .button {
    min-height: 48px;
    background: #0e7490; /* cyan-800 — visible on dark bg */
  }
}

/* Desktop with reduced motion: no hover animations */
@media (hover: hover) and (prefers-reduced-motion: reduce) {
  .card {
    /* Keep the hover state visible but remove the transform */
    transition: background-color 0.15s ease;
  }

  .card:hover {
    background: #f8fafc; /* Subtle colour change instead of movement */
  }
}

/* Narrow viewport OR narrow container */
@media (max-width: 640px) {
  .sidebar { display: none; }
}

@container (max-width: 400px) {
  .sidebar { display: none; }
}

/* Range syntax (CSS Media Queries Level 4) */
@media (400px <= width <= 768px) {
  /* Tablet-only styles — cleaner than min/max pair */
}

The range syntax at the bottom is a CSS Media Queries Level 4 feature that is now supported in all major browsers. It is significantly more readable than the old @media (min-width: 400px) and (max-width: 768px) pattern and should be preferred in new code.

Browser Support in 2026

FeatureChromeFirefoxSafariEdgeSafe to Ship?
prefers-color-scheme76+67+12.1+79+Yes — full support
prefers-reduced-motion74+63+10.1+79+Yes — full support
hover / pointer38+64+9+12+Yes — full support
prefers-contrast96+101+14.1+96+Yes — full support
forced-colors89+89+No79+Progressive enhancement
display-mode45+47+13+79+Yes — full support
Container queries105+110+16+105+Yes — full support
prefers-reduced-dataFlag onlyNoNoFlag onlyProgressive enhancement only
Range syntax (@media)104+63+16.4+104+Yes — full support

The practical takeaway: every feature in this guide except prefers-reduced-data and forced-colors is safe to ship without a fallback in 2026. Both of those should be treated as progressive enhancement — they will not break anything in unsupported browsers, they will just not apply.

Practical Checklist: What to Add to Every Project

Here is a minimal baseline of non-dimension media queries that every production website should include. Think of this as the responsive CSS equivalent of a security checklist — not optional extras, but standard practice.

QueryWhat to DoPriority
prefers-color-scheme: darkProvide a dark theme via CSS variablesHigh
prefers-reduced-motion: reduceDisable or replace all animations and transitionsHigh
pointer: coarseEnsure all interactive elements are at least 44px tallHigh
hover: hoverWrap all :hover effects so they only apply on hover-capable devicesMedium
prefers-contrast: moreStrengthen borders and darken muted textMedium
display-mode: standaloneHide install prompts; add safe-area paddingLow (PWA only)
forced-colors: activeFix custom form controls that break in Windows High ContrastLow
Container queriesReplace viewport breakpoints in reusable componentsMedium

The first three — dark mode, reduced motion, and coarse pointer — should be in every project from day one. They cover the vast majority of users who have accessibility or preference settings enabled, and they take less than an hour to implement correctly if you use CSS custom properties from the start.

The hover and container query items are slightly more involved but pay dividends on complex UIs. The remaining items are situational — add them when they are relevant to your specific project rather than as boilerplate.

If you are building for a wide range of devices — and if you are reading a site called DeviceSpecsHub, you probably are — the device database is a useful sanity check. Filter by category to see what input types and viewport sizes are common in your target audience, then use that data to prioritise which queries matter most for your specific project.

DS
DeviceSpecsHub Editorial
Published March 14, 2026

Share this article

Related Articles