home about me

CSS Media Queries to respect your users

You should always respect the choices your users make. There are a few media queries you can use to easily make your site or app experience more in line with what your users want.

Color Scheme

One of the best ways to give your users true value on the media queries front is having both a dark and light color scheme, and respecting the user’s device’s/browser’s setting in that regard.

The two possible options for prefers-color-scheme are light (which is the default), and dark. This can easily be combined with CSS custom properties (variables) to implement color schemes for your app:

:root {
  --button-bg-color: white;
  --button-text-color: black;
}

@media (prefers-color-scheme: dark) {
  :root {
    --button-bg-color: black;
    --button-text-color: white;
  }
}

.c-button {
  background-color: var(--button-bg-color);
  color: var(--button-text-color);
}

This example will switch the color based on the user’s preference, if their browser supports the feature, all without having to provide two sets of CSS definition for every component.

Higher/Lower Contrast

Just like with the color scheme example above, you can use media queries to match your user’s preference regarding contrast. prefer-contrast can have the values no-preference (default), more, less or custom.

The important one here is more, which has accessibility implications: A user demanding higher contrast might have a harder time reading text on screen, and you can help them by increasing the contrast between text and background, or even increasing the font size or weight.

Setting less is, well, less common, and it has less accessibility implications if simply ignored.

Reduce Motion

prefers-reduced-motion lets you know a user desires to not see (moving) animations. Querying against it is as easy as checking @media (prefers-reduced-motion: reduce). Browsers that do not yet support this feature will simply ignore the assignment:

.c-modal {
  transform: translateY(-100%);
  transition: transform 0.4s ease;
}

.c-modal.-open {
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .c-modal {
    transition: none;
  }
}

This (simplified) example has a modal sliding in from the top, but if the user set the option to reduce motion on screen, it will skip the movement and simply pop into existence. You could also use the media query to change the animation to something non-moving, for example transitioning the opacity instead.
Remember: This option is about reducing motion, not reducing transitions.

The opposite media query would be @media (prefers-reduced-motion: no-preference) to indicate that the user did not request less animations. As with the above example, browsers without support would simply skip the whole block though.

Javascript

You can query any of those settings in Javascript, too. window.matchMedia offers the possibility to check against CSS media queries, and call a method whenever changes are made - for example when the user’s phone activates night mode.

let mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)')

// can take a MediaQueryList or MediaQueryListEvent
function handleColorScheme(mql) {
  if (mql.matches) {
    // dark color scheme
  } else {
    // light color scheme
  }
}

// handle immediately
handleColorScheme(mediaQueryList)

// handle future changes
mediaQueryList.addEventListener('change', handleColorScheme)