Media features

Responsive design wouldn't be possible without media queries. Before media queries there was no way of knowing what kind of device people were using to visit your website. Designers had to make assumptions. Those assumptions were encoded into fixed-width designs or liquid layouts.

That all changed with the introduction of media queries. For the first time designers could meet people halfway. Designers could adjust their layouts to respond to people's devices.

Remember, a media query comprises an optional media type and a mandatory media feature. There hasn't been much change in media types over the years. There are still just four possible values:

@media all
@media screen
@media print
@media speech

Media features, on the other hand, have expanded greatly. Designers now can meet users beyond halfway, adapting designs to fit far more than just screen size.

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.

Source

Viewport dimensions

By far the most popular media queries on the web are the ones dealing with viewport width. But even here, you're presented with a choice. You can use the max-width media feature to apply styles below a certain width, or you can use the min-width media feature to apply styles above a certain width.

main {
  display: grid;
  grid-template-columns: 2fr 1fr;
}

@media (max-width: 45em) {
  main {
    display: block;
  }
}
@media (min-width: 45em) {
  main {
    display: grid;
    grid-template-columns: 2fr 1fr;
  }
}

Personally, I like to use min-width. I apply layout styles in an additive way. I introduce new layout rules at each breakpoint instead of undoing previous rules.

This additive approach also works for height. Using min-height you can introduce more rules as more viewport height becomes available. For example, you might have a header element that you want to anchor to the top of the browser window if there's enough vertical space.

@media (min-height: 30em) {
  header {
    position: fixed;
  }
}

But you can use the max-height media feature if you prefer. Here, the header is anchored by default, but the stickiness is removed if there isn't enough vertical space.

header {
  position: fixed;
}
@media (max-height: 30em) {
  header {
    position: static;
  }
}

Choosing between min- and max- prefixes doesn't just apply to width and height. The aspect-ratio media feature offers the same choice. It also offers an unprefixed version if you want to apply styles at an exact ratio of width to height.

@media (min-aspect-ratio: 16/9) {
  // The ratio of width to height is at least 16 by 9.
}
@media (max-aspect-ratio: 16/9) {
  // The ratio of width to height is less than 16 by 9.
}
@media (aspect-ratio: 16/9) {
  // The ratio of width to height is exactly 16 by 9.
}

Providing different styles for different aspect ratios could quickly get out of hand. If you don't need that fine-grained level of control, the orientation media feature might better suit your needs. It has two possible values: portrait or landscape.

@media (orientation: portrait) {
  // The width is less than the height.
}
@media (orientation: landscape) {
  // The width is greater than the height.
}

Even though the terms "portrait" and "landscape" are most often used to refer to the orientation of mobile devices, the orientation media feature isn't device-specific. A full-screen browser window on a typical laptop will have an orientation value of landscape.

Displays

Different displays have different pixel densities, measured in dpi, dots per inch. You can adjust your styles for different pixel densities using the resolution media feature. Like aspect-ratio, resolution comes in three varieties: minimum, maximum, and exact.

@media (min-resolution: 300dpi) {
  // The display has a pixel density of at least 300 dots per inch.
}
@media (max-resolution: 300dpi) {
  // The display has a pixel density less than 300 dots per inch.
}
@media (resolution: 300dpi) {
  // The display has a pixel density of exactly 300 dots per inch.
}

You may never need to use any resolution media queries. Pixel density is usually only an issue for images, and responsive images are a way of dealing with pixel density directly in HTML.

On the other hand, CSS is where you define your animations and transitions. You can adjust those animations and transitions to respond to different refresh rates using the update media feature. This media feature reports one of three values: none, slow, and fast.

An update value of none means there's no refresh rate. A printed page, for example, can't be updated.

An update value of slow means the display can't refresh quickly. An e-ink display is one example of a screen with a slow refresh rate.

An update value of fast means the display refreshes fast enough to handle animations and transitions.

@media (update: fast) {
  a {
    transition-duration: 0.4s;
    transition-property: transform;
  }
  a:hover {
    transform: scale(150%);
  }
}

Not all aspects of the display are related to hardware capabilities. In the module on theming, you saw how to define properties in a web app manifest file. One of those properties is called display, and you can give it a value of fullscreen, standalone, minimum-ui, or browser. The corresponding display-mode media feature lets you tailor your styles for these different options.

Say you've provided a display value of standalone in your web app manifest. If someone adds your site to their home screen, the site will launch without any browser interface. You might decide to display a back button for those users.

button.back {
  display: none;
}
@media (display-mode: standalone) {
  button.back {
     display: inline;
  }
}

Color

There are numerous media features for querying the color capabilities of a device. If you want to adjust your styles for any display that only outputs shades of grey, you can use the monochrome media feature without any value.

@media (monochrome) {
  body {
    color: black;
    background-color: white;
  }
}

There's a corresponding color media feature.

@media (color) {
  body {
    color: maroon;
    background-color: linen;
  }
}

For color screens, you can write queries with the media features color-gamut, color-index, or dynamic-range. All of them report specific details about the color capabilities of the screen.

In this example, color values update in response to the dynamic-range media feature, which reports the combination of maximum brightness, color depth, and contrast ratio of the display. The possible values are standard or high. A high-definition screen that reports a dynamic-range value of high is given a different color space using the new CSS color() function.

.neon-red {
  color: hsl(355 100% 95%);
}
@media (dynamic-range: high) {
  .neon-red {
    color: color(display-p3 1 0 0);
  }
}

Interaction

Media features can also report the kind of input mechanism used to interact with your site: hover, any-hover, pointer, and any-pointer. See the module on interaction for more details.

User preference queries

Using CSS, you can collaborate with your users to make sure that they can access your content in a way that works for them. In this lesson, you've learned how to apply different CSS based on the dimensions and features of the user's device. But you can also apply different CSS based on the user's settings.

Dark and light mode

You can respond to your user's preference for a light or dark theme. Many users set this as a system preference.

Setting the color scheme for UI elementsx

The browser provides default colors for things like scrollbars and form elements. You can specify whether to use a light theme for those with color-scheme: light, or a dark theme with color-scheme: dark. You can also specify that the page supports both, with color-scheme: light dark. You can set this on the :root or html element to set the scheme for the entire page, or you can override it for specific elements.

You can also set a meta tag for color-scheme to set a page's scheme before your styles load. If you set color-scheme: normal on an element in the page, it will use the color-scheme value that you set in this meta tag.

<meta name="color-scheme" content="dark light">

prefers-color-scheme media feature

You can also define custom styles in response to a user's preferred color theme with a media query for prefers-color-scheme.

light-dark

If you are providing your users the choice between both a light and a dark theme, you may find it verbose to set each color inside of a media query. light-dark() lets you specify both in a single property.

To enable this, you need to set color-scheme: light dark on the element or one of its ancestors. You first set a color to use in light mode, and then a color to use in dark mode.

h1{
  color: light-dark( var(--text-light), var(--text-dark));
}

If a user has their system preference set to request light mode, the heading will be black. If their preference is dark mode, the heading will be white.

Contrast preferences

Your users may find it easier to read content with high or low contrast, and may set up their system to override your theme with what works best for them. Your role is to ensure that your site still works well with their preferences.

You may remember in the Cascade module that !important local user styles can override the authored styles that a web page provides. This allows users to use styles that work better for them.

Forced colors

Windows provides "Contrast themes" that users can select that override the themes on a website. These are often high contrast themes, and may be in light or dark mode. In CSS, this is called forced colors, and in most cases, your site will behave as expected in this mode. Buttons, links, inputs, and other content will use the theme's colors.

Occasionally, you may need to adjust your styles, for example if you are using elements in non-standard ways. You can use the @media (forced-colors: active) media query to apply styles when a user has enabled forced colors.

In some cases, a site's styles are integral to understanding the content itself, for example with a color picker or a graph with a color key. You can set forced-color-adjust: none; on an element to opt out of forced colors mode. Make sure to only opt out on specific elements, and to check that the content is still accessible in forced colors mode.

High contrast

Some users may also set their system to request increased contrast. You can adjust your styles in response with the prefers-contrast: more media query.

Reduced motion

You can respond to a user's preference for reduced motion with the prefers-reduced-motion media query. This is often used to provide alternate animations that avoid large movements that may be triggers for people with epilepsy, vestibular motion disorders, or migraine sensitivity. Read more in Considerations when working with animation.

Scripting

Your users may visit your site with JavaScript disabled, and you can adjust your CSS so that they can still access your content using the scripting media query.

@media (scripting: none) {
  /* Styles when JavaScript is disabled*/
 }

@media (scripting: initial-only) {
  /* Styles when JavaScript is available only for an initial render, for example with a printed page or server side rendering */
}

@media (scripting: enabled) {
   /* Styles when Javascript is enabled */
}

Check your understanding

Test your knowledge of media features

A media query can check for a device at a specific width like @media (width: 1024px)?

True
A specific width can only be accomplished by simultaneously checking for width above 1023px and below 1025px.
False
min-width and max-width are what is available.

A media query can check for a device at a specific aspect-ratio like @media (aspect-ratio: 4/3)?

True
Unique to aspect ratio, a single ratio can be matched.
False
This option does exist for aspect-ratio.

Which are valid color media queries?

@media (color)
Matches any color device.
@media (monochrome)
Matches any device without color capability.
@media (color-gamut: srgb)
Matches devices with sRGB color capability.
@media (min-color-index: 15000)
Matches devices with at least 15k colors available.
@media (dynamic-range: high)
Matches devices capable of HD color ranges.

Which of the following user preference media queries are valid?

@media (prefers-color-scheme: dark)
Matches when a user has their operating system set to dark mode.
@media (prefers-colors: high-definition)
Not real.
@media (prefers-reduced-motion: reduce)
Matches when a user has their operating system set to reduce motion.
@media (prefers-contrast: more)
Matches when a user has their operating system set to higher contrasts.
@media (prefers-site-speed: fast)
Not real.

What are valid values for color-scheme?

light
Correct!
dark
Correct!
night
Incorrect.
contrast
Incorrect.

How do you opt an element out of forced colors?

forced-colors: active
Incorrect.
forced-colors: inactive
Incorrect.
forced-colors-adjust: none
Correct!
forced-colors-adjust: normal
Incorrect.