Media Queries For the Greater Good

I would like to share my views & experience on some of the more obscure CSS media queries and how they can make everyone's life better.

1. Reduced motion

@media
    (prefers-reduced-motion: reduce),
    (update: none),
    (update: slow) {}

Detect whether your users are on a device with a low refresh rate (such as E-Ink screens), or if they simply prefer reduced motion. Respecting these settings can greatly improve user experience, and may even have an impact on one's well-being.

Example Scenarios with reduced motion
CSS Animations

Prevent decorative animations/transitions when the user prefers reduced motion. We set the duration for animations and transitions to 1ms as 0 could lead to inconsistent effects across browsers, it also ensures TransitionEvents events are still fired.

:root {
  --animation-duration: 500ms;
}

@media
    (prefers-reduced-motion: reduce),
    (update: none),
    (update: slow) {
  :root {
    --animation-duration: 1ms;
  }
}
Graphics Controls

Ensure all animated content is stopped, and provide controls instead, e.g render a <video> element with controls and autoplay disabled.

const prefersReducedMotion =
    window.matchMedia(`
        (prefers-reduced-motion: reduce),'
        (update: none),
        (update: slow)
    `).matches;
if (prefersReducedMotion()) {
  video.controls = true;
  video.autoplay = false
}

Example from Apple (App Store):

2. Inaccurate pointers

@media (pointer: coarse) {}

I love this one. The above media query is applied when the pointer mechanism of your device (such as a mouse, touch, or a gamepad) is unable to accurately interact with interactive elements. This allows you to make conscious design decisions for those who do not operate with a mouse. I personally tend to make buttons and links a tad bigger when this media-query is met.

NOTE: I have not had the chance to test this feature on Feature-Phones, please let me know which pointer query is triggered on these devices.

Example Scenarios with “coarse” pointers.
Interactive Element Hitboxes

Make buttons bigger when only inaccurate pointers are available to the user. Inaccurate pointers include; Gamepads, your finger, Etch-a-Sketch, and any other pointer device that would make clicking an 8x8px rectangle an impossible task.

@media (pointer: coarse) {
  a[href],
  button,
  input,
  textarea,
  select {
    display: inline-block;
    padding: 0.5rem 0;
  }
}

3. Hover detection

@media (hover: hover) {}

Somewhat related to the last one, this media query detects if the current pointer device has the ability to “hover”. It may be overkill to wrap every hover state in one of these badboys, I personally tend to use it for complex interactions on hover (see example scenario).

Example Scenarios with “hover” pointers.
Contextual content on hover
@media (hover: hover) {
  .hidden-content {
    opacity: 0;
  }
  
  .parent:hover .hidden-content {
    opacity: 1;
  }
}
A UI pattern that shows contextual information on hover.
An iteration on top of the previous example, applying graceful degradation if the user is unable to hover.

4. Display Mode

@media (display-mode: standalone) {}
@media (display-mode: fullscreen) {}

Likely the least useful in this list, but still pretty cool — make design decisions based on whether the user is navigating to your app through the web/browser or a native experience.

Pim de Wit