{"id":7267,"date":"2025-09-29T10:46:45","date_gmt":"2025-09-29T15:46:45","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=7267"},"modified":"2025-09-29T10:46:46","modified_gmt":"2025-09-29T15:46:46","slug":"learn-media-queries","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/learn-media-queries\/","title":{"rendered":"How much do you really know about media queries?"},"content":{"rendered":"\n<p>Earlier this year, I realized that I knew very little about possibly <em>most<\/em> of the media queries.<\/p>\n\n\n\n<p>Maybe that&#8217;s not surprising \u2014 since I never hear about them.<\/p>\n\n\n\n<p>Beyond the classics like <code>@media(min-width: 400px)<\/code> and the user-preference media queries such as&nbsp;<code>@media (prefers-reduced-motion: reduce)<\/code>, and&nbsp;<em>maaaybe<\/em>&nbsp;orientation, I can\u2019t say that I was using media queries a whole lot. Especially since flexbox, grid layout, and&nbsp;<code>calc()<\/code>&nbsp;became fairly normalized, in addition to newer sizing values such as&nbsp;<code>min-content<\/code>,&nbsp;<code>max-content<\/code>,&nbsp;<code>fit-content<\/code>, and more recently,&nbsp;<code>stretch<\/code>.<\/p>\n\n\n\n<p>But there are&nbsp;<em>so<\/em>&nbsp;many descriptors! Most of these I&#8217;ve never used:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>any-hover<\/code><\/li>\n\n\n\n<li><code>any-pointer<\/code><\/li>\n\n\n\n<li><code>aspect-ratio<\/code><\/li>\n\n\n\n<li><code>color<\/code><\/li>\n\n\n\n<li><code>color-gamut<\/code><\/li>\n\n\n\n<li><code>color-index<\/code><\/li>\n\n\n\n<li><code>display-mode<\/code><\/li>\n\n\n\n<li><code>dynamic-range<\/code><\/li>\n\n\n\n<li><code>environment-blending<\/code><\/li>\n\n\n\n<li><code>forced-colors<\/code><\/li>\n\n\n\n<li><code>grid<\/code><\/li>\n\n\n\n<li><code>height<\/code><\/li>\n\n\n\n<li><code>horizontal-viewport-segments<\/code><\/li>\n\n\n\n<li><code>hover<\/code><\/li>\n\n\n\n<li><code>inverted-colors<\/code><\/li>\n\n\n\n<li><code>monochrome<\/code><\/li>\n\n\n\n<li><code>nav-controls<\/code><\/li>\n\n\n\n<li><code>orientation<\/code><\/li>\n\n\n\n<li><code>overflow-block<\/code><\/li>\n\n\n\n<li><code>overflow-inline<\/code><\/li>\n\n\n\n<li><code>pointer<\/code><\/li>\n\n\n\n<li><code>prefers-color-scheme<\/code><\/li>\n\n\n\n<li><code>prefers-contrast<\/code><\/li>\n\n\n\n<li><code>prefers-reduced-data<\/code><\/li>\n\n\n\n<li><code>prefers-reduced-motion<\/code><\/li>\n\n\n\n<li><code>prefers-reduced-transparency<\/code><\/li>\n\n\n\n<li><code>resolution<\/code><\/li>\n\n\n\n<li><code>scan<\/code><\/li>\n\n\n\n<li><code>scripting<\/code><\/li>\n\n\n\n<li><code>update<\/code><\/li>\n\n\n\n<li><code>vertical-viewport-segments<\/code><\/li>\n\n\n\n<li><code>video-color-gamut<\/code><\/li>\n\n\n\n<li><code>video-dynamic-range<\/code><\/li>\n\n\n\n<li><code>width<\/code><\/li>\n<\/ul>\n\n\n\n<p>It\u2019s not that I thought media queries were <em>only<\/em> for responsive design, but out of sight, out of mind, right? Nobody talks about them. Granted, some of them have few use-cases, but after being more mindful of them for a few months, I\u2019ve come to the conclusion that many of them&nbsp;<em>definitely<\/em>&nbsp;deserve more attention.<\/p>\n\n\n\n<p>Plus, there are more ways to write media queries now. This includes an <code>@custom-media<\/code> at-rule for saving media queries as custom properties, which is super cool.<\/p>\n\n\n\n<p>Let\u2019s dig in.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hoverpointerany-hoverany-pointer\"><code>hover<\/code>\/<code>pointer<\/code>\/<code>any-hover<\/code>\/<code>any-pointer<\/code><\/h2>\n\n\n\n<p>Modern devices can be used in many different ways. For example, it\u2019s not uncommon to hook a mouse up to a tablet, which is why we shouldn\u2019t think of tablets as touchscreen devices anymore. In fact, it\u2019s now unwise to use media queries to query for what specific device they &#8220;are&#8221;, which is why the media types <code>tty<\/code>, <code>tv<\/code>, <code>projection<\/code>, <code>handheld<\/code>, <code>braille<\/code>, <code>embossed<\/code>, <code>aural<\/code>, and <code>speech<\/code> were deprecated (<code>all<\/code>, <code>print<\/code>, and <code>screen<\/code> are the only types now, but all of them will likely be deprecated eventually).<\/p>\n\n\n\n<p>These days it\u2019s more prudent to query the device\u2019s capabilities and how the user has set it up, and that\u2019s where the <code>hover<\/code>, <code>pointer<\/code>, <code>any-hover<\/code>, and <code>any-pointer<\/code> media query descriptors come into it. At first glance, <code>hover<\/code> and <code>pointer<\/code> sound like the same thing, and while you could use them interchangeably for a high-level use-case, using them <em>together<\/em> is what truly enables us to target capabilities:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* Primary input mechanism is a mouse *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">hover:<\/span> hover) <span class=\"hljs-keyword\">and<\/span> (<span class=\"hljs-attribute\">pointer:<\/span> fine) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* Primary input mechanism is a joystick *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">hover:<\/span> hover) <span class=\"hljs-keyword\">and<\/span> (<span class=\"hljs-attribute\">pointer:<\/span> coarse) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* Primary input mechanism is touch *\/<\/span>\n<span class=\"hljs-comment\">\/* (also targets joystick-less controllers) *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">hover:<\/span> none) <span class=\"hljs-keyword\">and<\/span> (<span class=\"hljs-attribute\">pointer:<\/span> coarse) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* Primary input mechanism is a stylus *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">hover:<\/span> none) <span class=\"hljs-keyword\">and<\/span> (<span class=\"hljs-attribute\">pointer:<\/span> fine) {\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>As you might\u2019ve guessed from <code>@media (hover: none) and (pointer: coarse)<\/code> targeting joystick-less controllers (e.g., the D-pad-only controllers that come with old-ish TVs and game consoles) in addition to touchscreen devices. It\u2019s not a fool-proof method, but it doesn\u2019t make any <em>overly<\/em> bold assumptions about input mechanisms.<\/p>\n\n\n\n<p>Here\u2019s a simple use-case:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">button<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n\n  <span class=\"hljs-comment\">\/* Default hover styles *\/<\/span>\n\n  @media (<span class=\"hljs-attribute\">hover<\/span>: none) and (pointer: coarse) {\n    <span class=\"hljs-comment\">\/* High-visibility hover styles when obscured by fingers *\/<\/span>\n  }\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The possibilities are endless, and you can of course query just one descriptor (e.g., <code>@media (hover: none)<\/code>), but they\u2019re rarely useful individually. A more powerful usage is in the combinative way demonstrated above, but instead of declaring alternative hover styles for touchscreen devices, providing a more touch-friendly UI, perhaps by using the <code>display<\/code> property to show\/hide different components altogether.<\/p>\n\n\n\n<p>It\u2019s also worth mentioning that <code>hover<\/code> and <code>pointer<\/code> query the <em>primary<\/em> input mechanism, whereas their <code>any-hover<\/code> and <code>any-pointer<\/code> counterparts query <em>all<\/em> input mechanisms. For example, the following code targets touchscreen devices with a mouse or stylus hooked up as an additional input mechanism, which might be a more accurate representation of the user\u2019s setup:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">hover:<\/span> none) <span class=\"hljs-keyword\">and<\/span> (<span class=\"hljs-attribute\">pointer:<\/span> coarse) <span class=\"hljs-keyword\">and<\/span> (<span class=\"hljs-attribute\">any-pointer:<\/span> fine) {\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\" id=\"forced-colors\"><code>forced-colors<\/code><\/h2>\n\n\n\n<p>Users can choose color schemes at the OS or browser level, or create their own. As an example, Firefox allows us to change the color of text, backgrounds, and links, whereas High Contrast Mode in Windows offers more customization options and has themes to choose from. In an ideal world we wouldn\u2019t need to do anything here, but if something turns out to be inaccessible or just looks odd, we can use the <code>forced-colors<\/code> media query descriptor to correct it:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">forced-colors:<\/span> active) {\n  <span class=\"hljs-comment\">\/* Corrective styles, like applying borders to controls that might not otherwise have them. *\/<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If something must be a certain color, simply apply <code>forced-color-adjust: none<\/code> along with the necessary property and value:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-id\">#this-must-be-blue<\/span> {\n  <span class=\"hljs-attribute\">color<\/span>: blue;\n  <span class=\"hljs-attribute\">forced-color-adjust<\/span>: none;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>It\u2019s also worth noting that when <code>forced-colors<\/code> is set to <code>active<\/code>, the user\u2019s preferred color scheme will be set to either <code>light<\/code> or <code>dark<\/code> depending on their chosen theme. You can query the assigned color scheme using <code>@media (prefers-color-scheme: light)<\/code> and <code>@media (prefers-color-scheme: dark)<\/code>. In addition, <code>prefers-contrast<\/code> will be set to <code>more<\/code>, <code>less<\/code>, or <code>custom<\/code>.<\/p>\n\n\n\n<p>You can <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/@media\/forced-colors\">learn more about <code>forced-colors<\/code> at MDN.<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"widthheight\"><code>width<\/code>\/<code>height<\/code><\/h2>\n\n\n\n<p>\u201c<code>width<\/code> and <code>height<\/code>? I already know about those!\u201d<\/p>\n\n\n\n<p>Yes, these are certainly the most commonly used media queries, but did you know that a new syntax with comparison operators was introduced about three years ago? I like the operators because they can be inclusive or exclusive of the value in question. For example, we can express \u201cmore than\u201d using <code>&gt;<\/code> or \u201cmore than or equal to\u201d using <code>&gt;=<\/code>, which enables us to drop the <code>min-<\/code>\/<code>max-<\/code> prefixes (which are only inclusive) and standardize the <code>width<\/code> and <code>height<\/code> keywords across the board:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">width:<\/span> <span class=\"hljs-number\">900px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is 900px *\/<\/span>\n}\n\n<span class=\"hljs-keyword\">@media<\/span> (width &lt; <span class=\"hljs-number\">900px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is less than 900px *\/<\/span>\n}\n\n<span class=\"hljs-keyword\">@media<\/span> (width &gt; <span class=\"hljs-number\">900px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is more than 900px *\/<\/span>\n}\n\n<span class=\"hljs-keyword\">@media<\/span> (width &lt;= <span class=\"hljs-number\">900px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is less than or equal to 900px *\/<\/span>\n}\n\n<span class=\"hljs-keyword\">@media<\/span> (width &gt;= <span class=\"hljs-number\">900px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is more than or equal to 900px *\/<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>There\u2019s also a between-this-and-that syntax, which oddly requires \u2018lessy\u2019 operators but is otherwise easy to remember:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-number\">900px<\/span> &lt; width &lt; <span class=\"hljs-number\">1200px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is 901-1199px (exclusive) *\/<\/span>\n}\n\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-number\">900px<\/span> &lt;= width &lt;= <span class=\"hljs-number\">1200px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is 900-1200px (inclusive) *\/<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If you\u2019re not keen on this syntax (yeah, it\u2019s a little weird), you can still use the old syntax. Or, even better, use a little of both:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (width &gt; <span class=\"hljs-number\">900px<\/span>) <span class=\"hljs-keyword\">and<\/span> (width &lt; <span class=\"hljs-number\">1200px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is 901-1199px (exclusive) *\/<\/span>\n}\n\n<span class=\"hljs-keyword\">@media<\/span> (width &gt;= <span class=\"hljs-number\">900px<\/span>) <span class=\"hljs-keyword\">and<\/span> (width &lt;= <span class=\"hljs-number\">1200px<\/span>) {\n  <span class=\"hljs-comment\">\/* Styles when viewport width is 900-1200px (inclusive) *\/<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"learn-more\">It&#8217;s worth noting that logical properties like <code>inline-size<\/code> and <code>block-size<\/code> also work, but it often makes more sense in @media queries to deal with physical properties since the browser window itself doesn&#8217;t change when the flow changes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"inverted-colors\"><code>inverted-colors<\/code><\/h2>\n\n\n\n<p>Since there are a variety of viewing modes (light, dark, high-contrast, etc.) already, having a mode that inverts colors might seem unnecessary, but it\u2019s useful when light or dark mode isn\u2019t available (because inverting the colors somewhat toggles the mode) and when the user has a Color Vision Deficiency (because inverting the colors creates new colors). While the former issue can be fixed by respecting light-dark mode preferences and implementing light-dark mode toggling, the latter issue requires color inversion.<\/p>\n\n\n\n<p>We can query this mode using the <code>inverted-colors<\/code> media query descriptor, and what we want to do with it is revert shadows and non-UI media back to \u2018normal,\u2019 otherwise the non-UI media will look extremely odd and the shadows will appear as highlights. To invert a shadow color (or any color), convert it to HSL format using the relative color syntax, and add <code>180<\/code> to the Hue (<code>h<\/code>):<\/p>\n\n\n\n<p>For media, <code>filter: invert(1)<\/code> will do the trick:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.box-shadow<\/span> {\n\n  <span class=\"hljs-comment\">\/* When not inverted, normal box shadow *\/<\/span>\n  @media (<span class=\"hljs-attribute\">inverted-colors<\/span>: none) {\n    box-shadow: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">8px<\/span> limegreen;\n  }\n\n  <span class=\"hljs-comment\">\/* When inverted, add 180 to Hue\/h to revert *\/<\/span>\n  <span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">inverted-colors:<\/span> inverted) {\n    <span class=\"hljs-selector-tag\">box-shadow<\/span>: 0 0 8<span class=\"hljs-selector-tag\">px<\/span> <span class=\"hljs-selector-tag\">hsl<\/span>(<span class=\"hljs-selector-tag\">from<\/span> <span class=\"hljs-selector-tag\">limegreen<\/span> <span class=\"hljs-selector-tag\">calc<\/span>(<span class=\"hljs-selector-tag\">h<\/span> + 180) <span class=\"hljs-selector-tag\">s<\/span> <span class=\"hljs-selector-tag\">l<\/span>);\n  }\n\n}\n\n<span class=\"hljs-comment\">\/* Same thing for text shadows *\/<\/span>\n<span class=\"hljs-selector-class\">.text-shadow<\/span> {\n  @media (<span class=\"hljs-attribute\">inverted-colors<\/span>: none) {\n    text-shadow: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">8px<\/span> limegreen;\n  }\n  <span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">inverted-colors:<\/span> inverted) {\n    <span class=\"hljs-selector-tag\">text-shadow<\/span>: 0 0 8<span class=\"hljs-selector-tag\">px<\/span> <span class=\"hljs-selector-tag\">hsl<\/span>(<span class=\"hljs-selector-tag\">from<\/span> <span class=\"hljs-selector-tag\">limegreen<\/span> <span class=\"hljs-selector-tag\">calc<\/span>(<span class=\"hljs-selector-tag\">h<\/span> + 180) <span class=\"hljs-selector-tag\">s<\/span> <span class=\"hljs-selector-tag\">l<\/span>);\n  }\n}\n\n<span class=\"hljs-comment\">\/* Same thing for drop shadows *\/<\/span>\n<span class=\"hljs-selector-class\">.drop-shadow<\/span> {\n  @media (<span class=\"hljs-attribute\">inverted-colors<\/span>: none) {\n    filter: <span class=\"hljs-built_in\">drop-shadow<\/span>(<span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">8px<\/span> limegreen);\n  }\n  <span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">inverted-colors:<\/span> inverted) {\n    <span class=\"hljs-selector-tag\">filter<\/span>: <span class=\"hljs-selector-tag\">drop-shadow<\/span>(0 0 8<span class=\"hljs-selector-tag\">px<\/span> <span class=\"hljs-selector-tag\">hsl<\/span>(<span class=\"hljs-selector-tag\">from<\/span> <span class=\"hljs-selector-tag\">limegreen<\/span> <span class=\"hljs-selector-tag\">calc<\/span>(<span class=\"hljs-selector-tag\">h<\/span> + 180) <span class=\"hljs-selector-tag\">s<\/span> <span class=\"hljs-selector-tag\">l<\/span>));\n  }\n}\n\n<span class=\"hljs-selector-class\">.non-ui<\/span><span class=\"hljs-selector-pseudo\">:is(img<\/span>, <span class=\"hljs-selector-tag\">svg<\/span>, <span class=\"hljs-selector-tag\">video<\/span>, ...) {\n\n  <span class=\"hljs-attribute\">box-shadow<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">8px<\/span> black;\n\n  @media (<span class=\"hljs-attribute\">inverted-colors<\/span>: inverted) {\n    <span class=\"hljs-comment\">\/* Reverts the media and shadow at the same time *\/<\/span>\n    filter: <span class=\"hljs-built_in\">invert<\/span>(<span class=\"hljs-number\">1<\/span>);\n  }\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You can see it in action here (make sure to toggle inverted colors to see the UI change but images\/shadows stay the same):<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_gbaZJLK\" src=\"\/\/codepen.io\/anon\/embed\/gbaZJLK?height=520&amp;theme-id=1&amp;slug-hash=gbaZJLK&amp;default-tab=result\" height=\"520\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed gbaZJLK\" title=\"CodePen Embed gbaZJLK\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>While forced colors are better as long as users can choose themes, some operating systems don\u2019t support it (macOS doesn\u2019t).<\/p>\n\n\n\n<p>As of September 2025, only Safari supports the\u00a0inverted-colors\u00a0media query descriptor <code>prefers-reduced-motion<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"orientation\"><code>orientation<\/code><\/h2>\n\n\n\n<p>An <code>orientation<\/code> query is a rather simple media query descriptor that resolves to <code>portrait<\/code> if the viewport is larger vertically or <code>landscape<\/code> if it\u2019s larger horizontally.<\/p>\n\n\n\n<p>The thing with orientation is that users hold their handheld device differently based on it, which could mean having to code a slightly different layout for each orientation. Even if you\u2019re lucky enough to avoid that issue, you\u2019re still likely to run into issues with aspect ratios or relative units (e.g., viewport or percentage units) where something looks proportionate in one orientation but very exaggerated or de-exaggerated in the other.<\/p>\n\n\n\n<p>Targeting a specific orientation is easy enough:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">orientation:<\/span> portrait) {\n  ...\n}\n\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">orientation:<\/span> landscape) {\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>As for optimizing layouts for certain orientations on touchscreen devices, you\u2019ll want to combine the <code>orientation<\/code> descriptor with the \u2018touchscreen descriptors\u2019 mentioned earlier:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">orientation:<\/span> landscape) <span class=\"hljs-keyword\">and<\/span> (<span class=\"hljs-attribute\">hover:<\/span> none) <span class=\"hljs-keyword\">and<\/span> (<span class=\"hljs-attribute\">pointer:<\/span> coarse) {\n  <span class=\"hljs-comment\">\/* Landscape touchscreen styles *\/<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Generally speaking, due to the diversity of devices and media queries available today, avoid using <code>orientation<\/code> to detect the device type. For example, vertical monitors do exist (you\u2019ll see them at airports, for instance), so don\u2019t assume that <code>portrait<\/code> means handheld.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"overflow-inlineoverflow-block\"><code>overflow-inline<\/code>\/<code>overflow-block<\/code><\/h2>\n\n\n\n<p>The <code>overflow-inline<\/code> and <code>overflow-block<\/code> media query descriptors with the <code>scroll<\/code> value match vendors that support overflow content on their respective axes. We\u2019re basically talking about web browsers here, as well as windows that display HTML content and have a scrolling mechanisms.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* Vendor supports inline-axis scrolling *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">overflow-inline:<\/span> scroll) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* Vendor supports block-axis scrolling *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">overflow-block:<\/span> scroll) {\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>overflow-inline<\/code> and <code>overflow-block<\/code> media query descriptors with the <code>none<\/code> value match vendors that <em>don\u2019t<\/em> support overflow content on their respective axes. To be clear, this doesn\u2019t mean that the document has <code>overflow: hidden<\/code> declared, it means that scrolling isn\u2019t supported at all (e.g., a HTML document that\u2019s rendered as an OS-level widget or on a digital billboard).<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* Vendor doesn\u2019t support inline-axis scrolling *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">overflow-inline:<\/span> none) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* Vendor doesn\u2019t support block-axis scrolling *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">overflow-block:<\/span> none) {\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>A more common use-case exists for <code>overflow-block<\/code>, which accepts another value: <code>paged<\/code>. Naturally, <code>paged<\/code> refers to printed documents and HTML-based ebooks such as EPUBs, with printed documents obviously being the most common of the two.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* Vendor supports block-axis scrolling, but is paged media *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">overflow-block:<\/span> paged) {\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The spec alludes to <a href=\"https:\/\/www.w3.org\/TR\/mediaqueries-5\/#media-types\">all media types being deprecated eventually<\/a>, so this is somewhat designed to replaced the <code>print<\/code> media type.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-prefers--family\">The <code>prefers-<\/code> family<\/h2>\n\n\n\n<p>The <code>prefers-<\/code> family of media query descriptors should be used to cater to users with preferences and comply with the WCAG (Web Content Accessibility Guidelines).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>prefers-color-scheme<\/code><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* User prefers light mode *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-color-scheme:<\/span> light) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* User prefers dark mode *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-color-scheme:<\/span> dark) {\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>I like to query this using JavaScript, check a \u2018dark mode\u2019 checkbox accordingly, and then use CSS\u2019s <code>light-dark()<\/code> function to style according to the inferred (or user-specified) mode:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/* If dark mode is inferred, check dark mode box *\/<\/span>\n<span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-built_in\">window<\/span>.matchMedia(<span class=\"hljs-string\">\"(prefers-color-scheme: dark)\"<\/span>).matches) {\n  <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\"#dark-mode\"<\/span>).checked = <span class=\"hljs-literal\">true<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">\/* But users can change at will *\/\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"checkbox\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"dark-mode\"<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* If dark mode isn\u2019t checked *\/<\/span>\n<span class=\"hljs-selector-pseudo\">:root<\/span><span class=\"hljs-selector-pseudo\">:has(<\/span><span class=\"hljs-selector-id\">#dark-mode<\/span><span class=\"hljs-selector-pseudo\">:indeterminate)<\/span> {\n  <span class=\"hljs-attribute\">color-scheme<\/span>: light;\n}\n\n<span class=\"hljs-comment\">\/* If dark mode is checked *\/<\/span>\n<span class=\"hljs-selector-pseudo\">:root<\/span><span class=\"hljs-selector-pseudo\">:has(<\/span><span class=\"hljs-selector-id\">#dark-mode<\/span><span class=\"hljs-selector-pseudo\">:checked)<\/span> {\n  <span class=\"hljs-attribute\">color-scheme<\/span>: dark;\n}\n\n<span class=\"hljs-selector-tag\">body<\/span> {\n  <span class=\"hljs-comment\">\/* Then set values conditionally *\/<\/span>\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-built_in\">light-dark<\/span>(white, black);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_jEWObrL\" src=\"\/\/codepen.io\/anon\/embed\/jEWObrL?height=450&amp;theme-id=1&amp;slug-hash=jEWObrL&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed jEWObrL\" title=\"CodePen Embed jEWObrL\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><code>prefers-contrast<\/code><\/h3>\n\n\n\n<p>There are four possible values for <code>prefers-contrast<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-comment\">\/* User has no contrast preference *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-contrast:<\/span> no-preference) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* User prefers more contrast *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-contrast:<\/span> more) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* User prefers less contrast *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-contrast:<\/span> less) {\n  ...\n}\n\n<span class=\"hljs-comment\">\/* User has forced a color theme *\/<\/span>\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-contrast:<\/span> custom) {\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You\u2019re unlikely to use <code>no-preference<\/code> or <code>more<\/code> because the WCAG has defined a minimum level of color contrast that websites must adhere to. In addition, <code>prefers-contrast: custom<\/code> means that the user has specified a color theme preference via forced colors mode that\u2019s neither a low or high contrast theme. It\u2019s a matter of semantics that again has no practical use, so simply use <code>low<\/code> for the minority of users that prefer low contrast due to migraines, Dyslexia, and so on. This doesn\u2019t violate WCAG as long as there\u2019s a mechanism for switching low-contrast mode off.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>prefers-reduced-data<\/code><\/h3>\n\n\n\n<p><code>prefers-reduced-data: reduce<\/code> targets users that prefer to consume less data when browsing while connected to their cellular network, whereas <code>prefers-reduced-data: no-preference<\/code> naturally targets those who have no preference. Personally, I\u2019d love to see more websites reduce their size for those with slower connections and\/or smaller data allowances, perhaps by swapping heavy decorative background images for something else:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">div<\/span> {\n  @media (<span class=\"hljs-attribute\">prefers-reduced-data<\/span>: no-preference) {\n    <span class=\"hljs-comment\">\/* Heavy decorative image *\/<\/span>\n    background-image: <span class=\"hljs-built_in\">url<\/span>(&lt;url&gt;);\n  }\n\n  <span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-reduced-data:<\/span> reduce) {\n    <span class=\"hljs-comment\">\/* Literally anything else *\/<\/span>\n    <span class=\"hljs-selector-tag\">background<\/span>: &lt;<span class=\"hljs-selector-tag\">value<\/span>&gt;;\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Or loading fonts conditionally:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-reduced-data:<\/span> no-preference) {\n  <span class=\"hljs-keyword\">@font-face<\/span> {\n    <span class=\"hljs-attribute\">font-family<\/span>: lexend;\n    <span class=\"hljs-attribute\">src<\/span>: &lt;value&gt;;\n  }\n}\n\n<span class=\"hljs-selector-tag\">body<\/span> {\n  <span class=\"hljs-comment\">\/* If user prefers reduced data, fallback font sans-serif will be used *\/<\/span>\n  <span class=\"hljs-attribute\">font-family<\/span>: lexend, sans-serif;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>As of October 2025, no web browser supports this.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>prefers-reduced-motion*<\/code><\/h3>\n\n\n\n<p>The key to <code>prefers-reduced-motion<\/code>, which accepts the same values as <code>prefers-reduced-data<\/code> (<code>no-preference<\/code> and <code>reduce<\/code>), is simply to reduce (or remove, in extreme cases) transitions and animations for those with vestibular disorders, which interestingly <a href=\"https:\/\/web.dev\/learn\/accessibility\/motion\">affect 35% of adults by aged 40<\/a>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">button<\/span> {\n  @media (<span class=\"hljs-attribute\">prefers-reduced-motion<\/span>: no-preference) {\n    <span class=\"hljs-comment\">\/* Continuously pulsate *\/<\/span>\n    animation: pulse <span class=\"hljs-number\">1s<\/span> infinite;\n  }\n\n  <span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-reduced-motion:<\/span> reduce) {\n    <span class=\"hljs-comment\">\/* Pulsate once and not so intensely *\/<\/span>\n    <span class=\"hljs-selector-tag\">animation<\/span>: <span class=\"hljs-selector-tag\">scaleUpDown<\/span> 1<span class=\"hljs-selector-tag\">s<\/span>;\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\"><code>prefers-reduced-transparency<\/code> <\/h3>\n\n\n\n<p>Same here \u2014 your options are <code>no-preference<\/code> and <code>reduce<\/code>.<\/p>\n\n\n\n<p>I\u2019d normally consider this one to be an edge case, but with Apple\u2019s new Liquid Glass aesthetic being available to everybody now, I expect it to surge in popularity. If you must implement it, at least reduce transparency for those that don\u2019t like it or find it to be inaccessible:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">div<\/span> {\n  @media (<span class=\"hljs-attribute\">prefers-reduced-transparency<\/span>: no-preference) {\n    background: <span class=\"hljs-built_in\">hsl<\/span>(<span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> \/ <span class=\"hljs-number\">60%<\/span>);\n  }\n\n  <span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-reduced-transparency:<\/span> reduce) {\n    <span class=\"hljs-selector-tag\">background<\/span>: <span class=\"hljs-selector-tag\">hsl<\/span>(0 0 0 \/ 80%);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>As of September 2025, only Chrome and Edge support this.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"resolution\"><code>resolution<\/code><\/h2>\n\n\n\n<p><code>resolution<\/code>, <code>min-resolution<\/code>, and <code>max-resolution<\/code> accept values of the <code>&lt;resolution&gt;<\/code> data type (<code>dpi<\/code>, <code>dpcm<\/code>, <code>dppx<\/code>\/<code>x<\/code>). A fantastic use-case for this is to serve higher-resolution images to higher-resolution devices, as you would when using the <code>srcset<\/code> and <code>sizes<\/code> HTML attributes. And remember, we can use the new range syntax here, so <code>resolution &gt; 1x<\/code> instead of <code>min-resolution: 1.01x<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">div<\/span> {\n  <span class=\"hljs-attribute\">background-image<\/span>: <span class=\"hljs-built_in\">url<\/span>(<span class=\"hljs-string\">\"\/image-1x.jpg\"<\/span>);\n\n  @media (resolution &gt; 1x) {\n    <span class=\"hljs-attribute\">background-image<\/span>: <span class=\"hljs-built_in\">url<\/span>(<span class=\"hljs-string\">\"\/image-2x.jpg\"<\/span>);\n  }\n\n  <span class=\"hljs-keyword\">@media<\/span> (resolution &gt; <span class=\"hljs-number\">2<\/span>x) {\n    <span class=\"hljs-selector-tag\">background-image<\/span>: <span class=\"hljs-selector-tag\">url<\/span>(\"\/<span class=\"hljs-selector-tag\">image-3x<\/span><span class=\"hljs-selector-class\">.jpg<\/span>\");\n  }\n\n  <span class=\"hljs-keyword\">@media<\/span> (resolution &gt; <span class=\"hljs-number\">3<\/span>x) {\n    <span class=\"hljs-selector-tag\">background-image<\/span>: <span class=\"hljs-selector-tag\">url<\/span>(\"\/<span class=\"hljs-selector-tag\">image-4x<\/span><span class=\"hljs-selector-class\">.jpg<\/span>\");\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\" id=\"nesting-media-queries\">Nesting media queries<\/h2>\n\n\n\n<p>CSS nesting has had full browser support since August 2023, enabling us to nest CSS rules inside other CSS rules, and that includes at-rules such as media queries. If you\u2019ve been using a CSS preprocessor such as LESS, Scss, or Sass for this, well\u2026you don\u2019t need to anymore. Instead, to use an earlier example, you can nest media queries like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.box-shadow<\/span> {\n  @media (<span class=\"hljs-attribute\">inverted-colors<\/span>: none) {\n    box-shadow: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">8px<\/span> limegreen;\n  }\n  <span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">inverted-colors:<\/span> inverted) {\n    <span class=\"hljs-selector-tag\">box-shadow<\/span>: 0 0 8<span class=\"hljs-selector-tag\">px<\/span> <span class=\"hljs-selector-tag\">hsl<\/span>(<span class=\"hljs-selector-tag\">from<\/span> <span class=\"hljs-selector-tag\">limegreen<\/span> <span class=\"hljs-selector-tag\">calc<\/span>(<span class=\"hljs-selector-tag\">h<\/span> + 180) <span class=\"hljs-selector-tag\">s<\/span> <span class=\"hljs-selector-tag\">l<\/span>);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This enables you to write media queries more contextually.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"all-in-all\">All in all<\/h2>\n\n\n\n<p>If you were anxious about exploring the now-many different types of media queries and their syntaxes, I\u2019d say that\u2019s fair. However, while catering to today\u2019s diversity of devices and user preferences is without a doubt getting more complex, these media queries are actually pretty easy to use once you know how.<\/p>\n\n\n\n<p>Besides, WCAG 3.0, which could set the standard for the design of even more inclusive patterns, will be here eventually. This\u2019d mean having the legal requirement of catering for more user preferences regardless of how edge case-y they are, and as we\u2019ve seen in recent years, new and amended accessibility laws (and similar laws such as GDPR) tend to cause a last-minute frenzy as the deadline for compliance draws closer. My advice? Get ahead of the curve and start putting those media queries to use!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are a ton more @media queries than &#8220;width&#8221; and &#8220;prefers-reduced-motion&#8221;. Let&#8217;s have a long, along with use-cases.<\/p>\n","protected":false},"author":37,"featured_media":7284,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[7,45],"class_list":["post-7267","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-css","tag-media-query"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/09\/How-much-do-you-really-know-about-media-queries_.jpg?fit=1140%2C676&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7267","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/37"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=7267"}],"version-history":[{"count":7,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7267\/revisions"}],"predecessor-version":[{"id":7302,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7267\/revisions\/7302"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/7284"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=7267"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=7267"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=7267"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}