7

I'm building a website with CSS grid for the first time. Since not all browsers support this, I have made a set of fallback styles, and I conditionally apply those with @supports not (display:grid). But I also want to use this as the mobile stylesheet, and only use CSS grids on the larger screens - this could be achieved by a simple media query @media screen and (max-width:700px). The problem now is - if either of these is true, that is, if either the browser doesn't support CSS grid or the browser window isn't wider than 700 pixels, I want to use my fallback stylesheet.

So my question is - how do I ask the browser for @supports or @media at the same time? Nesting them isn't going to work as that's essentially asking for both of them to be true, and it feels wrong to just have that entire stylesheet copy-pasted from @supports to @media.

Basically, I want something like this:

(@supports not (display:grid)) or (@media screen and (max-width:700px)){
    /*my stylesheet*/
}
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
vrugtehagel
  • 1,009
  • 1
  • 9
  • 20
  • @Anthony Useless and irrelevant comment (as I think you've now noticed, per the discussion under your answer). The OP already acknowledges that nesting is syntactically legal, but doesn't do what they want - it amounts to an "AND" operation, not an "OR" operation. Sadly a mod flag asking for your comment to be deleted was declined, so all I can do is suggest that you clean it up yourself and then flag mine. – Mark Amery Apr 23 '19 at 21:21
  • @MarkAmery tell me how you really feel. – Anthony Apr 24 '19 at 05:17
  • @Anthony I'm only telling you what you've already pointed out yourself elsewhere on this page, with the aim of getting a confusing comment nuked. What's the value in keeping it around? – Mark Amery May 02 '19 at 10:52

3 Answers3

10

There isn't a way to combine two different conditional at-rules into one with OR logic (AND logic, as you've stated, can be done by nesting, even though strictly speaking they're still two separate rules). Unless you have plumbing that can automatically duplicate your CSS across two separate conditional rules for you, you will have to do that manually.

If possible, consider approaching this from a progressive-enhancement point of view rather than a graceful-degradation one. That is, rather than applying fallback styles to browsers that either don't support grid or are displaying on smaller screens, apply grid styles to browsers that support grid and are displaying on larger screens — this is where the nesting of rules you mention then makes sense:

@supports (display: grid) {
    /* Or screen and (min-width: 701px),
       or not screen and (max-width: 700px),
       depending on your needs and preferences */
    @media screen and (min-width: 700px) {
        /* Grid styles */
    }
}

If you're not a fan of the extra indentation, you can reduce it somewhat, or just not indent at all ;)

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 1
    They could also use a `link` element with a `media` attribute to import the stylesheet, then have a separate stylesheet (or style block) that handles when `display: grid` is not supported. This would reduce the overhead a bit (still the same concept though, having to repeat the stylesheet for the two conditions). – Anthony May 25 '18 at 17:03
  • 3
    @Anthony: Yeah, that's true. It's also worth pointing out that the media attribute doesn't prevent the stylesheet from being loaded when the browser doesn't match the media query at load time, because it has to account for (the possibility of) changes that cause it to match the query after the fact, so that won't be a bandwidth saver either. – BoltClock May 25 '18 at 17:06
  • 2
    Note to any reader who (like me) initially does a double-take at the claim that *"There isn't a way to combine two different conditional at-rules into one with OR logic"* - yes, as you may have previously seen, you *can* combine two different media queries *within* an `@media` rule by separating them with commas. But what you unfortunately *can't* do is separate two different @-rules, like `@media` and `@supports`, using commas. – Mark Amery Apr 23 '19 at 18:54
2

This is a good use case for a CSS preprocessor. You can define a mixin containing your mobile/gridless styles, then use that mixin inside both an @supports and a @media block. That way you don't need to duplicate the styles in your source code.

For instance, in SCSS, you could write:

@mixin no-grid-css {
  /* Placeholder for mobile/no-grid styles */
  .foo {
    color: #baa;
  }
  .baz::after {
    content: "qux";
  }
}

@supports not (display:grid) {
  @include no-grid-css;  
}

@media screen and (max-width:700px) {
  @include no-grid-css;
}

When you compile this with sass styles.scss you'll get:

@supports not (display: grid) {
  /* Placeholder for mobile/no-grid styles */
  .foo {
    color: #baa;
  }

  .baz::after {
    content: "qux";
  }
}
@media screen and (max-width: 700px) {
  /* Placeholder for mobile/no-grid styles */
  .foo {
    color: #baa;
  }

  .baz::after {
    content: "qux";
  }
}

The downside of this approach is that the styles will still be duplicated in the CSS that gets sent to the user's browser. (Don't expect your web server's gzipping to save you, either - it won't do much to reduce the size penalty of duplicating a huge block of code.) So while it saves you from the maintenance headaches of duplicating the code, it doesn't save you from the performance penalty.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
-1

There is an example of nested conditional at-rules exactly like you are describing in the Mozilla documentation for @media rules:

/* Nested within another conditional at-rule */
@supports (display: flex) {
  @media screen and (min-width: 900px) {
    article {
      display: flex;
    }
  }
}
Anthony
  • 36,459
  • 25
  • 97
  • 163
  • However, this will only set `article{display:flex;}` whenever the browser support both flex and the screen is wide enough, not whenever the browser supports flex *or* the screen is wide enough – vrugtehagel May 25 '18 at 16:44
  • Which makes sense, because if the screen is wide enough and doesn't support flex, you wouldn't want to use that stylesheet. – Anthony May 25 '18 at 16:45
  • I see, you are wanting to load the stylesheet for the mobile/old-browser through these. Tricky. – Anthony May 25 '18 at 16:55
  • -1 because, as you acknowledge in the comments, this doesn't answer the question asked but rather was based on a misunderstanding. – Mark Amery Apr 23 '19 at 18:11