How to Nest Media Queries Within Media Queries

Is it possible to nest media queries within media queries?

You should be able to nest @media rules this way in CSS3, but it isn't yet supported by most browsers. See this answer for details.

You would have to fully expand and repeat the top-level media queries for the inner rules for it to work across browsers (and I imagine the SCSS processor would generate something similar):

@media only screen 
and (min-device-width: 320px)
and (max-device-width: 480px) {
/* Code for both portrait and landscape */
}

@media only screen
and (min-device-width: 320px)
and (max-device-width: 480px)
and (orientation: portrait) {

/* Code for just portrait */

}

@media only screen
and (min-device-width: 320px)
and (max-device-width: 480px)
and (orientation: landscape) {

/* Code for just landscape */

}

Nesting Media Queries

No. You need to use the and operator and write that as two queries. You can, however, do this in SCSS, which will compile to CSS, but it will combine them by unfolding them and using the and operator.

This is a common problem, and once I first wrote LESS or SCSS, I didn't ever want to go back to writing this long-hand.

Long-handed CSS:

@media (-webkit-min-device-pixel-ratio: 2) and (max-width: 768px) and (min-width: 320px),
(min-resolution: 192dpi) and (max-width: 768px) and (min-width: 320px) {
body {
border: 1px solid red;
}
}
@media (-webkit-min-device-pixel-ratio: 2) and (max-width: 320px),
(min-resolution: 192dpi) and (max-width: 320px) {
body {
border: 1px solid blue;
}
}

Nesting queries may work, but support varies across browsers.

Nesting CSS @supports and @media queries

Both examples are valid CSS according to section 3 of the spec, and for the time being they seem to be consistently supported by browsers that understand both @supports rules and nested @media rules (also new to CSS3).

Although both examples will only apply the background: blue declaration when both the @media and @supports conditions are met,

  • A will apply either background: green or background: blue if and only if the (min-width: 50em) media query is met;
  • B will apply either declaration if and only if the browser understands @supports and supports flex-wrap: wrap.

Since your two examples mean subtly different things, which one you choose will depend on your use case:

  • If you do not want browsers that don't support @supports or flex-wrap: wrap to see either declaration, and to instead always apply background: red, choose B.
  • Otherwise, if you want any browser (that understands media queries anyway) to apply background: green at the specified viewport width, even if it will never apply background: blue due to not supporting @supports or flex-wrap: wrap, choose A.

Nesting @media rules in element

I think that it depends on the amount of the code you are going to write. It works without any problem, but hundreds of different media queries nested in each class could be hard to maintain. In my opinion a good practice, especially for big projects, would be to use separate files for each media query threshold, in order to keep your CSS organized as much as possible.
For example:

style.less

.class1 {
width: 100%;
}

.class2 {
color: #000;
}

@media screen and (min-width: 740px) {
@import "min740.less";
}

min740.less

.class1 {
width: 50%;
}

.class2 {
color: #faa;
}

If you are going to write separate components, like buttons or typographies, you can keep all the related media queries in the same file, in order to have a completely separate CSS module (your 2nd example basically).

In terms of speed and performances, obviously is always recommended to use compiled LESS in production, but considering your examples, the single media query selector would be more efficient, since in the "example1 way" the media query selector will be replicated multiple times:

.class1 {
width: 100%;
}
@media screen and (min-width: 740px) {
.class1 {
width: 50%;
}
}
.class2 {
width: 100%;
}
@media screen and (min-width: 740px) {
.class2 {
width: 50%;
}
}

Can you nest a media query inside another media query?

Unfortunately you can't but pairing them up works fine too

@media screen and (max-width:1024px) and (-webkit-min-device-pixel-ratio:0){

}

Can we nest media queries (SASS) that doesn't add to the overall size of the compiled output via Gulp?

This issue in Sass Github is related to this problem. And you have this:

These optimizations are no longer planned. Sass does what it can to eliminate extra whitespace and choose the smallest possible representation for values, but it's primary focus is being the best preprocessing language it can be rather than the best CSS compressor.

So actually you should use PostCSS and maybe postcss-combine-media-query plugin. Or I found this gulp plugin. My recommendation for CSS optimizations and compression is PostCSS.

But if you want to solve this issue only with Sass, you can use output buffering as said by heygrady in the issue linked above.

Nesting @media rules in CSS

For those simply looking for an answer to "Which browsers support nesting of @media rules?", the short answer is that all modern browsers, including Firefox, Safari, Chrome (and its derivatives), and Microsoft Edge, now support nesting of @media at-rules as described in CSS Conditional 3. The code in the question with the nested @media at-rules should now work correctly everywhere, with the exception of Internet Explorer (which is no longer being updated with new features, meaning no version of IE will ever support this feature).

This feature did not exist in CSS2.1, since only media types existed at the time which you could simply group with a comma, which explains why support for this was very poor at the time this question was first asked.

What follows is an analysis of the original question with these historical limitations in mind.


There's a bit of terminology confusion that needs clearing up in order for us to understand what exactly is happening.

The code you have refers to @media rules, and not so much media queries — the media query itself is the component that follows the @media token, whereas the rule is the entire block of code consisting of @media, the media query, and the rules nested within its set of curly braces.

This may cause confusion among many when it comes to using media queries in CSS, as well as your specific case where a @media rule in an imported stylesheet works correctly even when the @import is accompanied by another media query. Notice that media queries can occur in both @media and @import rules. They're the same thing, but they're being used to restrictively apply style rules in different ways.

Now, the actual issue here is that nested @media rules are not valid in CSS2.1 because you're not allowed to nest any at-rules within @media rules. However, things seem quite different in CSS3. Namely, the Conditional Rules module states very clearly that @media rules can be nested, even providing an example:

For example, with this set of nested rules:

@media print { /* rule (1) */
/* hide navigation controls when printing */
#navigation { display: none }
@media (max-width: 12cm) { /* rule (2) */
/* keep notes in flow when printing to narrow pages */
.note { float: none }
}
}

the condition of the rule marked (1) is true for print media, and the condition of the rule marked (2) is true when the width of the display area (which for print media is the page box) is less than or equal to 12cm. Thus the rule ‘#navigation { display: none }’ applies whenever this style sheet is applied to print media, and the rule ‘.note { float: none }’ is applied only when the style sheet is applied to print media and the width of the page box is less than or equal to 12 centimeters.

Furthermore, it looks like Firefox is following this specification and processing the rules accordingly, whereas the other browsers are still treating it the CSS2.1 way.

The grammar in the Syntax module hasn't been updated to reflect this yet, though; it still disallows nesting of at-rules within @media rules as with CSS2.1. This specification is slated for a rewrite anyway, so I guess this doesn't matter.

Basically, CSS3 allows it (pending rewriting the Syntax module), but not CSS2.1 (because it neither defines media queries nor allows nested @media rule blocks). And while at least one browser has begun supporting the new spec, I wouldn't call other browsers buggy; instead, I'll say that they simply haven't caught up yet as they're really conforming to an older, more stable spec.

Lastly, the reason why your @import works is because @import is able to work conditionally with the help of a media query. However this has no relation to the @media rule in your imported stylesheet. These are in fact two separate things, and are treated as such by all browsers.

To make your code work consistently across browsers, you can either use your @import statement, or, since both of your rules use min-width, simply remove the nesting of your @media rules:

@media screen and (min-width: 480px) {
body {
background-color: #6aa6cc;
color: #000;
}
}

@media screen and (min-width: 768px) {
body {
background-color: #000;
color: #fff;
}
}

How to get a SASS nested nested media query to work with the use of the media query or operator

This appears to be a hyper-specific case that appears is part misbehavior in Sass and part ambiguous expectations.

Sass handles nesting combined with comma delimited media queries without problems... until you start specifying a display type on both the inner and outer query:

/* without `screen` */
.foo {
@media (min-width: 20em) {
color: yellow;

@media all and (max-width: 40em), (orientation: portrait) {
color: green;
}
}
}

/* without `only` */
.bar {
@media screen and (min-width: 20em) {
color: yellow;

@media all and (max-width: 40em), (orientation: portrait) {
color: green;
}
}
}

/* with `only screen` */
.buzz {
@media only screen and (min-width: 20em) {
color: red;

@media all and (max-width: 40em) {
color: blue;
}
}
}

Output:

/* without `screen` */
@media (min-width: 20em) {
.foo {
color: yellow;
}
}
@media all and (min-width: 20em) and (max-width: 40em), (min-width: 20em) and (orientation: portrait) {
.foo {
color: green;
}
}

/* without `only` */
@media screen and (min-width: 20em) {
.bar {
color: yellow;
}
}
@media screen and (min-width: 20em) and (orientation: portrait) {
.bar {
color: green;
}
}

/* with `only screen` */
@media only screen and (min-width: 20em) {
.buzz {
color: red;
}
}

In both cases where both the inner and outer query contains a display type (all, screen), the compiled results do not correctly match what was written. This appears to be a case of Sass trying to write something that resembles a valid media query (since it knows that screen and all is not valid).

So only specify the display type once.

.element {
@media (min-width: 825px) and (max-width: 999px) {
font-size: 10.4vw;

@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
font-size: 9.6vw;
}
}
}

Compiles to:

@media (min-width: 825px) and (max-width: 999px) {
.element {
font-size: 10.4vw;
}
}
@media all and (min-width: 825px) and (max-width: 999px) and (-ms-high-contrast: none), (min-width: 825px) and (max-width: 999px) and (-ms-high-contrast: active) {
.element {
font-size: 9.6vw;
}
}

Defining CSS media queries within selectors

Short answer, no. There are no performance issues in defining media queries within CSS selectors.

But let's dive in...

As described in Anselm Hannemann great article Web Performance: One or Thousands of Media Queries there is no performance loss from adding the media queries in the manner you are.

As long as the same set of media queries are being used in each selector there is no major performance hit other than your CSS file might be a bit larger.

.foo {
@media (min-width: 600px) { ... }
@media (min-width: 1000px) { ... }
@media (min-width: 1500px) { ... }
}

.bar {
@media (min-width: 600px) { ... }
@media (min-width: 1000px) { ... }
@media (min-width: 1500px) { ... }
}

However, it does matter how many different media queries you use. Different being different min-widths, max-widths and so on.



Related Topics



Leave a reply



Submit