Tree diagram with examples for printing, for mobile devices, and for all other devices

@media

The site can adapt to circumstances thanks to this directive.

Time to read: over 15 min

Briefly

A directive that allows you to set different styles for different screen parameters — width, height, orientation, and even device type.

Example

Let's make an element with the class block a flex container when the screen width is 900 pixels or more:

        
          
          @media (min-width: 900px) {  .block {    display: flex;  }}
          @media (min-width: 900px) {
  .block {
    display: flex;
  }
}

        
        
          
        
      

How to Understand

When laying out adaptive websites, it's often necessary for a certain set of styles to apply only under specific conditions. For example, the text should turn green only in the horizontal orientation of a smartphone. Or a block should take the entire width of its parent if the screen width is greater than or equal to 1500 pixels. This is what media queries are for. They help adapt the layout for different screens and devices without writing excess code.

How to Write

In general terms, the syntax looks like this:

        
          
          @media [device type] [device characteristic] {  /* CSS rules */}
          @media [device type] [device characteristic] {
  /* CSS rules */
}

        
        
          
        
      

For example:

        
          
          @media print and (orientation: landscape) {  .block {    font-size: 25pt;  }}
          @media print and (orientation: landscape) {
  .block {
    font-size: 25pt;
  }
}

        
        
          
        
      

Here, the device type is print (printer), and the device characteristic is orientation: landscape (landscape orientation). This means that when printing on a page in landscape orientation, the font size in the block will be 25 points.

Device Types

There are three types of devices we can specify:

  • all — the media query will apply to all devices. If no type is specified, this one will be applied by default;
  • print — styles inside such a media query will apply when printing on printers or exporting to PDF, including in document preview mode;
  • screen — for devices with screens.

In most cases, when you write styles only for the screen, there is no need to specify screen or all. The print type is the only one that has real practical usage.

Characteristics

Possible device characteristics can be divided into several categories.

Device Characteristics

The screen of modern devices can be divided into several parts using a fold or hinge between screens. Individual areas of the screen are called segments.

horizontal-viewport-segments — checks how many segments the screen is divided into horizontally.

vertical-viewport-segments — checks how many segments the screen is divided into vertically.

The value in both cases: a positive integer.

        
          
          @media (horizontal-viewport-segments: 1) { … }
          @media (horizontal-viewport-segments: 1) {}

        
        
          
        
      

overflow-block — checks how the device handles content that doesn't fit on the screen along the block axis.

Values:

  • none — the content is cut off, everything beyond the page is inaccessible;
  • scroll — the content can be scrolled;
  • optional-paged — the content can be scrolled, but if necessary, it can be split into pages. For example, using the property break-inside;
  • paged — content is divided into pages. As in the case of printing on a printer.
        
          
          @media (overflow-block: paged) { … }
          @media (overflow-block: paged) {}

        
        
          
        
      

overflow-inline — checks whether content that goes beyond the viewport can be scrolled along the inline axis.

Values:

  • none — the content is cut off, everything beyond the page is inaccessible;
  • scroll — the content can be scrolled.
        
          
          @media (overflow-inline: scroll) { … }
          @media (overflow-inline: scroll) {}

        
        
          
        
      

grid — checks whether the screen is raster (all modern screens) or grid (older phones or text terminals).

Values: 0 for raster screens and 1 for grid screens.

        
          
          @media (grid: 1) { … }
          @media (grid: 1) {}

        
        
          
        
      

resolution, min-resolution, max-resolution — checks the device's resolution in dpi or dpcm.

Value: a number with the necessary units of measurement. Units of measurement for device resolution.

        
          
          @media (max-resolution: 300dpi) { … }
          @media (max-resolution: 300dpi) {}

        
        
          
        
      

Page and Browser Window Characteristics

width, min-width, max-width — checks the width of the browser window, minimum or maximum width. Value: a positive integer or decimal number with any available units of measurement.

        
          
          @media (max-width: 1280px) { … }
          @media (max-width: 1280px) {}

        
        
          
        
      

height, min-height, max-height — checks the height of the browser window, minimum or maximum height. Value: a positive integer or decimal number with any available units of measurement.

        
          
          @media (min-height: 30rem) { … }
          @media (min-height: 30rem) {}

        
        
          
        
      

orientation — the orientation of the browser window. If the height of the browser window is greater than its width, then this is portrait orientation. Conversely, if the width is greater than the height, then this is landscape orientation.

Values:

  • landscape — landscape, horizontal orientation;
  • portrait — portrait, vertical orientation.
        
          
          @media (orientation: landscape) { … }
          @media (orientation: landscape) {}

        
        
          
        
      

aspect-ratio, min-aspect-ratio, max-aspect-ratio — the ratio between the width and height of the window, minimum and maximum ratio. Value: two positive integers separated by a slash.

        
          
          @media (aspect-ratio: 16 / 9) { … }
          @media (aspect-ratio: 16 / 9) {}

        
        
          
        
      

Display Quality

display-mode — checks in what mode the site or application is running.

Values:

  • browser — the site or application is running in a browser tab;
  • fullscreen — the site or application is opened in fullscreen mode;
  • minimal-ui — the application is launched as a separate program, with minimal navigation elements;
  • picture-in-picture — the application is launched in picture-in-picture mode, as a separate window above all other programs, which can be moved;
  • standalone — the application is running as a native program, without browser navigation elements.

Not all of these modes are currently supported by browsers. Check support on Can I Use.

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

        
        
          
        
      

scan — checks the rendering process on the device.

Values:

  • interlace — interlaced rendering, where frames are divided into rows and these rows are output alternately, even and odd;
  • progressive — progressive rendering, without a specific order of frames.
        
          
          @media (scan: interlace) { … }
          @media (scan: interlace) {}

        
        
          
        
      

update — screen refresh rate.

Values:

  • none — does not refresh;
  • slow — slow;
  • fast — fast.
        
          
          @media (update: slow) { … }
          @media (update: slow) {}

        
        
          
        
      

Color

color-gamut — the approximate range of colors supported by the browser and output device.

Values:

  • srgb — the device supports the sRGB color space;
  • p3 — the device supports colors from the Display P3 space;
  • rec2020 — the device supports the REC. 2020 color space.
        
          
          @media (color-gamut: p3) { … }
          @media (color-gamut: p3) {}

        
        
          
        
      

color, min-color, max-color — the number of bits per color on the output device.

Value: zero or a positive integer. If zero, the device is monochrome.

        
          
          @media (0 < color >= 8) { … }
          @media (0 < color >= 8) {}

        
        
          
        
      

color-index, min-color-index, max-color-index — the number of colors the device can display.

Value: zero or a positive integer. If zero, the device has no color table. Generally, this means the device is monochrome.

        
          
          @media (min-color-index: 1200) { … }
          @media (min-color-index: 1200) {}

        
        
          
        
      

monochrome, min-monochrome, max-monochrome — the number of bits per color on a monochrome output device.

Value: zero or a positive integer. If zero, the device is not monochrome.

        
          
          @media (monochrome: 0) { … }
          @media (monochrome: 0) {}

        
        
          
        
      

dynamic-range — a combination of brightness level, color depth, and contrast ratio for video in the browser or output device.

Values:

  • standard — if the device has a screen;
  • high — the device supports high brightness, depth, and contrast.
        
          
          @media (dynamic-range: high) { … }
          @media (dynamic-range: high) {}

        
        
          
        
      

Interaction

hover — checks whether the primary device allows pointing at elements.

Values:

  • none — there is no device for hovering the cursor (for example, a mouse), or the device cannot emulate hover. Many mobile devices emulate hover when interacting with fingers;
  • hover — there is a pointing device.
        
          
          @media (hover: hover) { … }
          @media (hover: hover) {}

        
        
          
        
      

any-hover — checks whether any input devices can point at elements.

Values:

  • none — there are no input devices with pointing capabilities;
  • hover — at least one input device can control the pointer. Touchscreen devices will always have at least the capability to control the cursor with a finger or stylus.
        
          
          @media (any-hover: hover) { … }
          @media (any-hover: hover) {}

        
        
          
        
      

pointer — checks whether the primary input device is a pointing device and how precise it is.

Values:

  • none — the primary input device is not a pointing device;
  • coarse — the primary input device is a pointing device with limited precision. Like a finger in the case of a touchscreen;
  • fine — the primary input device is a pointing device with high precision. Like a mouse cursor.
        
          
          @media (pointer: coarse) { … }
          @media (pointer: coarse) {}

        
        
          
        
      

any-pointer — checks whether any input devices are pointing devices and how precise they are.

Values:

  • none — at least one input device is not a pointing device;
  • coarse — at least one input device is a pointing device with limited precision. Like a finger in the case of a touchscreen;
  • fine — at least one input device is a pointing device with high precision. Like a mouse cursor.
        
          
          @media (any-pointer: fine) { … }
          @media (any-pointer: fine) {}

        
        
          
        
      

Characteristics with the video- prefix

video-dynamic-range — a combination of brightness level, color depth, and contrast ratio for video in the browser or output device.

Values:

  • standard — if the device has a screen;
  • high — the device supports high brightness, depth, and contrast.
        
          
          @media (video-dynamic-range: high) { … }
          @media (video-dynamic-range: high) {}

        
        
          
        
      

Scripts

scripting — checks whether scripts are enabled.

Values:

  • none — scripts are disabled, inaccessible;
  • initial-only — scripts are available only at the moment of document loading. After loading, scripts do not work;
  • enabled — scripts are supported and available.
        
          
          @media (scripting: initial-only) { … }
          @media (scripting: initial-only) {}

        
        
          
        
      

User Preferences

prefers-color-scheme — determines which theme the user prefers — light or dark.

Values:

  • light — the user prefers a light theme;
  • dark — the user prefers a dark theme.
        
          
          @media (prefers-color-scheme: dark) { … }
          @media (prefers-color-scheme: dark) {}

        
        
          
        
      

prefers-reduced-motion — determines whether animations are turned off in the user's system settings.

Values:

  • no-preference — the user has not turned off animations in the operating system;
  • reduce — the user has turned off animations in the operating system.
        
          
          @media (prefers-reduced-motion: reduce) { … }
          @media (prefers-reduced-motion: reduce) {}

        
        
          
        
      

forced-colors — checks whether the browser limits the number of colors in the interface.

Values:

  • none — no special color palette is selected;
  • active — a special color palette is enabled.
        
          
          @media (forced-colors: active) { … }
          @media (forced-colors: active) {}

        
        
          
        
      

inverted-colors — checks whether colors are inverted by the browser or OS.

Values:

  • none — color inversion mode is not enabled in the browser or OS;
  • inverted — color inversion mode is enabled in the browser or OS.
        
          
          @media (inverted-colors: inverted) { … }
          @media (inverted-colors: inverted) {}

        
        
          
        
      

prefers-contrast — determines whether settings for increasing or decreasing the contrast between the background color and text are set.

Values:

  • no-preference — the contrast adjustment setting is not enabled;
  • less — the reduced contrast setting is enabled;
  • more — increased contrast setting is enabled;
  • custom — the contrast adjustment setting is enabled, with custom settings, defined colors. Similarly to forced-colors: active.
        
          
          @media (prefers-contrast: custom) { … }
          @media (prefers-contrast: custom) {}

        
        
          
        
      

Deprecated

device-aspect-ratio — the ratio between the width and height of the output device. Use aspect-ratio.

device-width — the width of the device's display. Use width.

device-height — the height of the device's display. Use height.

Logical Operators

In a media query, multiple conditions can be listed separated by commas. In this case, styles will apply to any of the specified conditions. For example:

        
          
          @media (orientation: landscape), (max-width: 960px) {  .text {    color: tomato;  }}
          @media (orientation: landscape), (max-width: 960px) {
  .text {
    color: tomato;
  }
}

        
        
          
        
      

This code will apply to all devices with landscape screen orientation or all devices with a screen width of less than 960 pixels.

Often, the keyword and can be used in media queries, while the keywords not and only are used less frequently.

If we specify both the device type and characteristics, and must be placed after the type.

        
          
          @media print and (min-width: 320px) {  .link {    text-decoration: underline;  }}
          @media print and (min-width: 320px) {
  .link {
    text-decoration: underline;
  }
}

        
        
          
        
      

and is also placed between characteristics.

        
          
          @media (min-width: 320px) and (max-width: 640px) {  .link {    text-decoration: underline;  }}
          @media (min-width: 320px) and (max-width: 640px) {
  .link {
    text-decoration: underline;
  }
}

        
        
          
        
      

The keyword not is used to negate an expression. It has low priority and is applied as a last step. For example:

        
          
          @media not screen and (min-width: 380px) {  .block {    display: flex;  }}
          @media not screen and (min-width: 380px) {
  .block {
    display: flex;
  }
}

        
        
          
        
      

Here, the expression "for all screens with a minimum width of 380 pixels" will be computed first and then inverted to "for all devices except devices with screens with a minimum width of 380 pixels". This will be read by the browser as:

        
          
          @media not (screen and (min-width: 380px)) {  .block {    display: flex;  }}
          @media not (screen and (min-width: 380px)) {
  .block {
    display: flex;
  }
}

        
        
          
        
      

When using not in media queries separated by a comma, only the part of the expression with not is negated. For example:

        
          
          @media not screen and (height: 500px), print and (height: 700px) {  .text {    color: tomato;  }}
          @media not screen and (height: 500px), print and (height: 700px) {
  .text {
    color: tomato;
  }
}

        
        
          
        
      

To better understand how this example will be executed, you can add additional grouping parentheses:

        
          
          @media (not (screen and (height: 500px))), print and (height: 700px) {  .text {    color: tomato;  }}
          @media (not (screen and (height: 500px))), print and (height: 700px) {
  .text {
    color: tomato;
  }
}

        
        
          
        
      

Since the comma in the media query only means enumeration, not in the first part of the expression will not apply to the second, and only the part "for all screens with a browser window height of 500 pixels" will be inverted.

The keyword only is sometimes used before specifying the device type — it ensures that older browsers that do not support media queries do not apply the specified styles. Modern browsers do not react to only.

        
          
          @media only screen and (max-width: 600px) {  body {    background-color: cornflowerblue;  }}
          @media only screen and (max-width: 600px) {
  body {
    background-color: cornflowerblue;
  }
}

        
        
          
        
      

Syntax of Ranges

In modern browsers, you can use range syntax for all conditions where the value is a number. The new operators <, >, >=, and <= provide a more intuitive way to indicate, for example, for which screen sizes to apply rules from the media query. In fact, the operators are not new; everyone is familiar with them from school mathematics, but this is a new feature in media queries.

Suppose we want the color to turn red at widths greater than 680 pixels and less than 1280 pixels.

Using the old syntax, you would write two rules joined by a logical operator:

        
          
          @media (min-width: 680px) and (max-width: 1280px) {  p {    color: red;  }}
          @media (min-width: 680px) and (max-width: 1280px) {
  p {
    color: red;
  }
}

        
        
          
        
      

In the new syntax, you would use one rule where you set the endpoints and apply the new operators.

        
          
          @media (680px <= width >= 1280px) {  p {    color: red;  }}
          @media (680px <= width >= 1280px) {
  p {
    color: red;
  }
}

        
        
          
        
      

Tips

💡 For mobile-first layout, it's better to use media queries with min-width and place them in order of increasing screen width; for desktop-first layout — max-width, and place expressions in reverse order.

💡 Unfortunately, you still cannot use custom properties inside media queries. This would have been very convenient. Then we could extract breakpoints into variables and not have to remember them every time. We wouldn't have to look for the width at which the transition between mobile and tablet should occur.

In practice

Advice 1

🛠 Media expressions can be nested in media expressions and other directives:

        
          
          @media (min-width: 520px) {  @media (max-width: 1080px) {    .cell {      background: peachpuff;    }  }}
          @media (min-width: 520px) {
  @media (max-width: 1080px) {
    .cell {
      background: peachpuff;
    }
  }
}

        
        
          
        
      
        
          
          @supports (position: sticky) {  @media (min-width: 1080px) {    .block {      position: sticky;    }  }}
          @supports (position: sticky) {
  @media (min-width: 1080px) {
    .block {
      position: sticky;
    }
  }
}

        
        
          
        
      

Advice 2

🛠 If preprocessors are used in the project, it is convenient to use mixins for frequently used media queries.

For example, the code in SCSS:

        
          
          $tablet-min: 768px;@mixin tablet {  @media (min-width: $tablet-min) {    @content;  }}
          $tablet-min: 768px;

@mixin tablet {
  @media (min-width: $tablet-min) {
    @content;
  }
}

        
        
          
        
      

Using the mixin:

        
          
          .header {  color: red;  @include tablet {    color: white;  }}
          .header {
  color: red;

  @include tablet {
    color: white;
  }
}

        
        
          
        
      

Or using LESS:

        
          
          @tablet: 768px;.tablet(@rules) {  @media (min-width: @tablet) {    @rules();  }}
          @tablet: 768px;

.tablet(@rules) {
  @media (min-width: @tablet) {
    @rules();
  }
}

        
        
          
        
      

Usage:

        
          
          .header {  color: red;  .tablet({    color: white;  });}
          .header {
  color: red;

  .tablet({
    color: white;
  });
}