Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-conditional] CSS.supports for media queries? #5272

Open
mathiasbynens opened this issue Jun 30, 2020 · 7 comments
Open

[css-conditional] CSS.supports for media queries? #5272

mathiasbynens opened this issue Jun 30, 2020 · 7 comments
Labels
css-conditional-5 Current Work

Comments

@mathiasbynens
Copy link
Contributor

mathiasbynens commented Jun 30, 2020

Spec: https://drafts.csswg.org/css-conditional-3/#dom-css-supports

Use case: Given a media query like (prefers-reduced-data: reduce), I want to determine whether the host environment supports this query (regardless of whether the query matches). (Currently, one way to do this is to manually write a feature test which injects some CSS with media queries into the page, and then check if it had an effect.)

CSS.supports is super handy for feature detection, but it doesn't support feature-detection for media query expressions.

matchMedia can be used to figure out whether or not a given media query matches, but not whether or not it is supported. E.g. matchMedia('(prefers-this-doesnt-exist: lolwat)') returns an object with matches: false, but there's no indication whether or not it can ever match / is supported in the current implementation.

Potential solutions:

  • CSS.supports() could be extended to support media queries, i.e. CSS.supports('@media (...)'). The spec + implementations would have to branch on whether or not the conditionText parameter looks like a media query, which may not be ideal.
  • The object returned by matchMedia('(prefers-this-doesnt-exist: lolwat)') could be extended with a supported: true/false property. This doesn't seem ideal, since it has nothing to do with matching media.
  • We add a new API specifically for this case, perhaps something like CSS.supportsMedia('(prefers-reduced-data: reduce)').

Apologies if this has been discussed previously; a quick search didn't reveal anything relevant.

@frivoal
Copy link
Collaborator

frivoal commented Jun 30, 2020

can you explain a little more why you want to determine if the query is supported regardless of whether it matches? Not saying there's not reason to do that, but knowing your reason may help figure out what to do about it.

@mathiasbynens
Copy link
Contributor Author

The DevTools patch I linked to is an example: we want to show UI to emulate the prefers-reduced-data media feature, but only if the user has enabled the Chrome flag that makes that Web Platform feature available.

@Loirooriol
Copy link
Contributor

Loirooriol commented Jun 30, 2020

What about

let testMedia = str => matchMedia(`${str}, not all and ${str}`).matches;
testMedia("(prefers-this-doesnt-exist: lolwat)"); // false
testMedia("(prefers-color-scheme: light)"); // true
testMedia("(prefers-color-scheme: dark)"); // true
testMedia("(prefers-color-scheme: lolwat)"); // false

or

let testMedia = str => matchMedia(str).media === str;
testMedia("(prefers-this-doesnt-exist: lolwat)"); // false
testMedia("(prefers-color-scheme: light)"); // true
testMedia("(prefers-color-scheme: dark)"); // true
testMedia("(prefers-color-scheme: lolwat)"); // false

Edit: the 2nd suggestion does no longer work because any <general-enclosed> is valid syntax, even if the browser doesn't recognize it.

@mathiasbynens
Copy link
Contributor Author

I like it! Much simpler than the workaround I came up with, but also a little more magical / less direct.

@tunetheweb
Copy link
Member

tunetheweb commented Feb 26, 2021

On a similar note (let me know if you want this raised as a separate issue), how can this be detected in pure CSS?

For example with prefers-reduced-data support starting to come in Chrome I'd like to start using it to, for example, only load custom fonts when not in data saver mode. However, (at least for now) as this is new and not yet supported I still want to load the custom font by default (maybe in future when better supported can change this default, but this is what I'm thinking of now while support rolls out).

So ideally I'd be able to do something like this:

@supports not (prefers-reduced-data: no-preference) || @media(prefers-reduced-data: no-preference) {
   @font-face {
       font-family: Lato
       src: ...
   }

   @font-face {
       font-family: Poppins
       src: ...
   }
}

body {
  font-family: 'Lato', san-serif
}

h1 {
  font-family: 'Poppins', san-serif
}

That way I don't have to update every single instance of the font-family use across all my CSS but can just take care of it once, at the font-face definition. But this isn't possible AFAIK, firstly because @supports can't check media items, and secondly because you can't || @supports and @media even if it did.

Similarly, I preload my fonts so want to do that conditionally:

<link rel="preload" href="/static/fonts/Lato-Regular.woff2"
  as="font" type="font/woff2"
  media="(prefers-reduced-data: no-preference)"
  crossorigin>

But can't because this will only work for those browsers that recognise prefers-reduced-data and there's no way to add a fallback for the other browsers AFAIK so above would basically turn off preload for all, and alternatives would keep preload where I don't want it (prefers-reduced-data: reduce).

Is my understanding correct or is there a way to handle this in pure CSS? If not should there be?

@tomayac
Copy link
Contributor

tomayac commented Aug 17, 2023

Note the updated #5272 (comment). This is related to #7595 (comment). I just updated my previous blog post accordingly.

@romainmenke
Copy link
Member

romainmenke commented Aug 17, 2023

#5272 (comment)

let testMedia = str => matchMedia(`${str}, not all and ${str}`).matches;

This suggestion would only cover a small number of possible media queries.

Examples where this string interpolation of media queries would not work as expected :

  • (width) or (height)
  • screen
  • only screen
  • not screen
  • not (width)
  • all variations and more complicated examples of the above

It would only work for and separated queries and media queries without a type or modifier:

  • (width)
  • (width) and (height)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-conditional-5 Current Work
Projects
None yet
Development

No branches or pull requests

7 participants