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
orbackground: 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 supportsflex-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
orflex-wrap: wrap
to see either declaration, and to instead always applybackground: 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 applybackground: blue
due to not supporting@supports
orflex-wrap: wrap
, choose A.
Mixing an @supports with an @media query in CSS
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 ;)
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;
}
}
Mixing @supports and @media queries
At-rules such as @media
, @supports
and @keyframes
are separate rules that cannot be grouped together by their at-keywords. That is, it's not possible to write a single rule with a single pair of curly braces that combines two different at-keywords as you are trying to do. So, unfortunately, nesting is your only option here.
The best you can do is write both statements — and their opening/closing braces — on the same lines:
@supports not (-ms-high-contrast: active) { @media (min-width: 1400px) {
}}
This is basically nesting them as shown in the linked question, minus the excess line breaks and indentation.
Is it possible to do a CSS @supports check on a @media rule?
This does not seem to work. Should it work?
No; @supports
only supports property declarations, not at-rules or indeed any other grammatical construct in CSS. You're not looking to check for support for the @media
rule anyway; you're trying to check for support for specific media features. But @supports
doesn't support that either, even though media features share the same declaration syntax with property declarations.
To that end, you don't need the @supports
rule at all. To check if a browser supports a certain media feature, simply write a @media
rule with a media query list containing both the media feature and its negation:
@media not all and (pointer), (pointer) {
p { color: green; }
}
<p>If this text is green, your browser supports the <code>pointer</code> media feature.
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.
Why does `not (some-width: Xem)` media query never fire?
When Media Queries was first introduced, it required the not
keyword to be followed by a media type in order for the media query to be valid. It seems strange, but that's just how the grammar was defined (see the media_query
production).
This is now fixed in Media Queries level 4 (see the <media_not>
production), so what you have should work as expected in browsers that conform to MQ4. However, none of the browsers that have begun shipping level 4 media features has implemented the new grammar yet.
In the meantime, you'll need to add a media type. If the media type is not important, use all
:
not all and (max-device-width: X)
Updated fiddle
Unknown property name when using media queries with React & Bootstrap 4
Normal css doesn't support nested media queries. The style file you provided looks like it's a scss
file which hasn't been compiled to css
, so the browser doesn't understand its syntax.
To manually convert it to css
@media (max-width: 767.98px) {
.my-custom-color {
color: blue;
text-align: center;
}
}
Targeting Microsoft Edge With CSS and A Certain Width
Edge just recently switched to a Chromium based browser (in 2019) and will now behavior much more as expected. The calc() function now rounds decimals properly, which will save a lot of headache in the future. That being said, you still will need target older version for the next couple of years, for people who don't update the browsers as often.
Use this to target IE10/Edge+ pre-chromium base with widths set:
@media all and (-ms-high-contrast: none) and (min-width : 1700px),
(-ms-high-contrast: active) and (min-width : 1700px) {
}
Another option is to use JavasScript to add classes.
The example below is old... will update once I can find another older PC to test on some more... the switch to chrome is making me update some of my code as well.
navigator.browser=function(){var e=navigator.appName;var t=navigator.userAgent;var n;var r=t.match(/(edge|opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);if(r&&(n=t.match(/version\/([\.\d]+)/i))!=null){r[2]=n[1]}if(r){r={name:r[1].toLowerCase(),versionExt:r[2]}}else{r={name:e.toLowerCase(),versionExt:navigator.appVersion}}var i=r.versionExt.split(".");r.version=parseInt(i[0]);if(typeof i[1]=="string"&&i[1].match(/^[\d]+$/i)!=null){r.sub=parseInt(i[1]);r.subversion=parseFloat(r.version+"."+r.sub)}return r}()
$(document).ready(function(){
if (/edge/i.test(navigator.userAgent)) {
var ua = navigator.userAgent.toLowerCase();
var pos = ua.indexOf('edge/');
var version = ua.substr(pos + 5);
var parts = version.split(".");
var mainVersion = parts[0];
$('html').addClass('edge');
$('html').addClass('edge-' + mainVersion);
if (navigator.browser.name == 'netscape') {
$('html').addClass('edge-pre-chromium');
}
else {
$('html').addClass('edge-chromium');
}
}
else if (/windows/i.test(navigator.userAgent) && navigator.browser.name == 'netscape') {
$('html').addClass('edge');
$('html').addClass('edge-pre-chromium');
}
});
Hope that helps. I know this is a bit old, but hopefully can help some others in the future.
UPDATE
The calc() function is still rounding up in the Chromium version, sadly. The JavaScript above seems to be detecting the different version correctly.
Pure CSS target of IE12+.
@media only screen and (min-width : 1700px) {
_:-ms-lang(x), _:-webkit-full-screen, .selector { property:value; }
}
Credit for the above goes to: How to Identify Microsoft Edge browser via CSS?
Related Topics
Make Text in Select Element Wrap When Too Long
CSS Image Layouting Before Image Loaded
Differencebetween Perspective and Transform's Perspective Properties in CSS
Display:Block Not Working in Chrome or Safari
How to Create a Row of Elements of Equal Width Inside an Inline Container? Possibly Using Flexbox
Why Border of <Tr> Not Showing in Ie
How to Fade in Background Image by CSS3 Animation
Re-Order Entire Page with CSS Flexbox
What Is Correct Media Query for iPad Pro
3 Columns, Middle One with Flexible Width
How to Make a Link Inside a Div Fill the Entire Space Inside the Div
"Vw" CSS Units in Calc in Chrome Not Working
Preventing Relayout Due to Scrollbar
Dynamic Variable Names in Less CSS
How to Revert Back to Normal After Display:None for Table Row
Svg Spritesheet Targeting with CSS