Detecting media query support in CSS and JavaScript

Recently I needed a way to detect support for a media query in CSS and Javascript. To detect if a browser supports a certain CSS feature, you can use @supports () { … }, but that doesn’t work for media queries. In this article I’ll show you how you can detect support for media queries […]

The post Detecting media query support in CSS and JavaScript first appeared on Kilian Valkhof.


This content originally appeared on Kilian Valkhof and was authored by Kilian Valkhof

Recently I needed a way to detect support for a media query in CSS and Javascript. To detect if a browser supports a certain CSS feature, you can use @supports () { ... }, but that doesn’t work for media queries. In this article I’ll show you how you can detect support for media queries regardless of if they are turned on.

Why I needed this

For a presentation I did on prefers-reduced-data I wanted to apply something in one of two situations:

  • There was no support for prefers-reduced-data at all.
  • There was support for prefers-reduced-data and the value was “no-preference”.

For this, I couldn’t use just @media (prefers-reduced-data: no-preference) because that would be false if either there was no support (since the browser wouldnt understand the media query) or if it was supported but the user wanted to preserve data.

What I needed was a test for the media feature regardless of it’s value. It turns out we can do that by using the or notation in media queries.

Detecting media query support in CSS

To detect if a media query is supported in CSS at all, you can use the following CSS:

@media not all and (prefers-reduced-data), (prefers-reduced-data) {
  ...
}

That looks like a bit of weird, so lets dissect what it actually says. Firstly, let’s split the two media features and begin with the second one:

(prefers-reduced-data)

This one looks straightforward but there’s something weird: the media feature is missing a value! Usually, media features come with a value, like “min-width: 400px”, but this one doesn’t have a value.

That’s because some media features have a “shorthand” when they only have two options. Prefers-reduced-data has “no-preference” (off) and “reduce” (on). When you omit the value, it tests for it being on.

So here’s how this will resolve:

  • No preference: false
  • Reduce: true

But if the browser doesn’t support a media feature, it will automatically change to “not all”, which resolves to false, so we end with this:

  • No support: false
  • No preference: false
  • Reduce: true

not all and (prefers-reduced-data)

The notable thing here is not all and. “All” is the default media type, and it applies to both screen and print. You can omit it (and likely you usually do), but if you add it you need to add “and” in between it and the media feature (which is the part between parentheses).

not is how you can negate a media query. For example, @media not print {...} would apply everywhere except print.

With all being the default, what we’re really checking here for is “not (prefers-reduced-data)”. Unfortunately that’s invalid notation until supports for Media Queries level 4 lands, so we need to add the “all and” here.

Here’s how this resolves:

  • No support: false, since the browser still doesn’t understand it.
  • Support but off: true (its the negation of it being on).
  • Support but on: false

Combined

When the browser combines these values using the OR, only one of them has to be true for the media declaration to be applied:

No support:

  • not all and (prefers-reduced-data): false
  • (prefers-reduced-data): false

Combined: false

Support, but off:

  • not all and (prefers-reduced-data): true
  • (prefers-reduced-data): false

Combined: true

Support, but off:

  • not all and (prefers-reduced-data): false
  • (prefers-reduced-data): true

Combined: true

Anything in the media query will now be applied if the feature is supported, regardless of what its value is.

Detecting media query support in JavaScript

We can use the same media query in JavaScript using the window.matchMedia API:

const isSupported = window.matchMedia(
  `not all and (prefers-reduced-data), (prefers-reduced-data)`
  ).matches;

window.matchMedia returns an object with a “matches” boolean property that is either true or false. For more on the api, check out the using media queries in JavaScript section of my guide on media queries.

After I shared the above out on Twitter, Mathias pointed out a different method.

const query = '(prefers-reduced-data)';
const resolvedMediaQuery = window.matchMedia(query).media;

const isSupported = query === resolvedMediaQuery;

The window.matchMedia api also returns a “media” property, which is the normalized and resolved string representation of the query you tested. If matchMedia encounters something it doesn’t understand, that changes to not all, and if it does support the query it will return the query, regardless of if it matches (you can use the matches property for that).

So by comparing your input to the media, you either get:

No support:
'(prefers-reduced-data)' === 'not all' which is false.

Support:
'(prefers-reduced-data)' === '(prefers-reduced-data)' which is true.

Which one to use?

What I like about the first option, with the complex media query, is that all the logic happens inside CSS. I also like how you get a boolean, and don’t have to do string comparison.

The second can be a little bit easier to understand at a glance, but you need to make sure that your query input is the same as the browser normalizes it.

For example, if you test (prefers-reduced-data ) (notice the space), that would resolve “matches” to true in supported browsers because the white space is not important, but comparing the normalized media query would return false, since that normalization has removed that extra space. So string comparison can be tricky depending on your input.

When to use this?

We’re set to get a whole lot of new media features in the coming years, like prefers-reduced-data, prefers-contrast, screen-spanning and more.

While transitioning to all browsers supporting this, you’ll often want to turn on extra features for browsers that support it without causing issues in older browsers since the new default might not always be the best experience in older browsers.

With this media query you can split the behavior in older browsers without support and newer browsers with support.

The post Detecting media query support in CSS and JavaScript first appeared on Kilian Valkhof.


This content originally appeared on Kilian Valkhof and was authored by Kilian Valkhof


Print Share Comment Cite Upload Translate Updates
APA

Kilian Valkhof | Sciencx (2021-07-13T10:33:37+00:00) Detecting media query support in CSS and JavaScript. Retrieved from https://www.scien.cx/2021/07/13/detecting-media-query-support-in-css-and-javascript/

MLA
" » Detecting media query support in CSS and JavaScript." Kilian Valkhof | Sciencx - Tuesday July 13, 2021, https://www.scien.cx/2021/07/13/detecting-media-query-support-in-css-and-javascript/
HARVARD
Kilian Valkhof | Sciencx Tuesday July 13, 2021 » Detecting media query support in CSS and JavaScript., viewed ,<https://www.scien.cx/2021/07/13/detecting-media-query-support-in-css-and-javascript/>
VANCOUVER
Kilian Valkhof | Sciencx - » Detecting media query support in CSS and JavaScript. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/07/13/detecting-media-query-support-in-css-and-javascript/
CHICAGO
" » Detecting media query support in CSS and JavaScript." Kilian Valkhof | Sciencx - Accessed . https://www.scien.cx/2021/07/13/detecting-media-query-support-in-css-and-javascript/
IEEE
" » Detecting media query support in CSS and JavaScript." Kilian Valkhof | Sciencx [Online]. Available: https://www.scien.cx/2021/07/13/detecting-media-query-support-in-css-and-javascript/. [Accessed: ]
rf:citation
» Detecting media query support in CSS and JavaScript | Kilian Valkhof | Sciencx | https://www.scien.cx/2021/07/13/detecting-media-query-support-in-css-and-javascript/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.