Cutting the Mustard with CSS Media Queries

Share this article

Key Takeaways

  • Cutting the Mustard’ is a technique that uses JavaScript to check for browser capabilities before loading additional CSS and JavaScript to give the user an enhanced experience, otherwise only the necessary files for a core experience are loaded.
  • The author suggests using CSS media queries to conditionally load stylesheets based on the capabilities of the browser, thus avoiding the need for JavaScript and preventing older browsers from loading stylesheets intended for newer browsers.
  • The author proposes a method to load or run scripts only in supported browsers by using a harmless, non-default CSS property on the body element, and using JavaScript and getComputedStyle to determine if that property is set.
  • The author provides final code that combines all the techniques discussed, demonstrating a way to detect a relatively modern browser and prevent older browsers from applying styles or running scripts, allowing developers to focus on building for more modern browsers.

Cutting the Mustard is a term coined by Tom Maslen at the BBC. The method uses JavaScript that checks for browser capabilities before loading further CSS and JavaScript to give the user an ‘enhanced’ experience, otherwise the browser will only load the files necessary for a ‘core’ experience.

There has been a flurry of interest in cutting the mustard of late, for example Migrating to Flexbox by Cutting the Mustard and Server Side Mustard Cut, and in Progressive Enhancement in general.

Doing Better

In my experience, however, even a very basic ‘core’ experience can cause problems on some very old browsers, so I wanted to build on this idea and see if it was possible to deny really old browsers any CSS at all, leaving them with only the HTML.

Of course, the obvious solution is to use JavaScript to conditionally load all the CSS if the browser cuts the mustard, but this felt too heavy-handed for my liking; modern, capable browsers that didn’t load the JavaScript would be penalised by having no styles at all. So I looked for a CSS-only approach to the problem and I found an old post by Craig Buckler. After a fair bit of experimentation and adaptation, I came up with this:

<!-- in the <head> -->
<link rel="stylesheet" href="css/your-stylesheet.css"
      media="only screen and (min-resolution: 0.1dpcm)">
<link rel="stylesheet" href="css/your-stylesheet.css" 
      media="only screen and (-webkit-min-device-pixel-ratio:0) 
      and (min-color-index:0)">

Let’s examine what’s happening here.

How it Works

The first <link> element’s media query allows the stylesheet to load only in the following browsers:

  • IE 9+
  • FF 8+
  • Opera 12
  • Chrome 29+
  • Android 4.4+

The second <link> element’s media query allows the stylesheet to load only in:

  • Chrome 29+
  • Opera 16+
  • Safari 6.1+
  • iOS 7+
  • Android 4.4+

When combined, this technique will not load the stylesheet unless the browser is:

  • IE 9+
  • FF 8+
  • Opera 12, 16+
  • Chrome 29+
  • Safari 6.1+
  • iOS 7+
  • Android 4.4+

Note: the stylesheet is only loaded once no matter how many <link> elements there are.

It’s possible to combine the media queries into one link element by separating the declarations with a comma, like so:

<link rel="stylesheet" href="css/your-stylesheet.css"
      media="only screen and (min-resolution: 0.1dpcm),
      only screen and (-webkit-min-device-pixel-ratio:0)
      and (min-color-index:0)">

However, I personally like to keep them separate as I find it easier to see what’s going on.

So if you structure your markup in a semantic and accessible way, older browsers should still be able to see your un-styled content in plain HTML.

This is of course very opinionated, but it’s my view that anyone using these browsers still deserves to be able to get to what they need. It’s quite likely that by giving these browsers CSS intended for newer browsers, some things will just break, and that could mean a totally unusable page. Using this method they at least get a clean slate. More importantly, you’ll never need to test in those browsers again. You’re done with them! At least, that’s the theory.

Of course, your support needs are likely to vary, but the great thing about this technique is that you can build on it. For example, if you need to add support for IE8, you can use a conditional comment to load the same stylesheet only for that browser:

<!--[if IE 8]>
<link rel="stylesheet" href="css/your-stylesheet.css">
<![endif]-->

Or, if you need to support older WebKit devices with a pixel ratio of greater than 1, you could add another <link> element with a targeted media query, like this:

<link rel="stylesheet" href="css/your-stylesheet.css"
      media="only screen and (-webkit-min-device-pixel-ratio:1.1)">

By itself, this will load the stylesheet only for Android 2.2+ (I wasn’t able to test earlier versions), but since it’s included in addition to the other <link> elements, it’s effectively just adding support for this other group of browsers.

It’s also possible that you can alter the main <link> element’s media queries from how I’ve presented them here to get the custom support you need. However, it took quite a lot of testing to get this right, so be warned!

“But, they’re hacks!”

Yes, I suppose they are, though that depends on your definition. Media Queries are designed to test the capabilities of the browser before applying the CSS, and that’s exactly what we want to do in this case, albeit indirectly.

Still, hack or not, I’m pleased with this technique and it’s been working well for me in all the testing I’ve done so far, and I plan to use it on a production site soon.

Where it Doesn’t Work

In all my testing to date, I’ve found only one case where things don’t work as expected. On Android 4.4 the UC Browser doesn’t respond to the media query. From what I can tell, the UC Browser uses an older version of WebKit, which would explain things.

If you want to support this browser, it’s possible to resort to a little user agent sniffing to force the CSS to load:

if (navigator.userAgent.indexOf('UCBrowser') > -1) {
  var link  = document.createElement('link');
  link.rel  = 'stylesheet';
  link.href = 'css/your-stylesheet.css';
  document.getElementsByTagName('head')[0].appendChild(link);
}

As a bonus, as far as I can tell there’s no way to disable JavaScript in the Android UC Browser, so the stylesheet should always be loaded, barring network failures and such.

Of course, if you find there are other specific browsers you need to support, you can always add to the user agent sniff condition but I caution you to use it sparingly as it defeats the purpose of this being a CSS-only technique.

I’ve made a test page to test the base method on different browsers. If you find any browsers where things don’t work as expected, or if you find any other Media Queries that can add support for a particular browser or range of browsers, please let me know in the comments or raise an issue on the GitHub repository.

What About Loading Scripts?

Ok, so if you’re using CSS to detect browser support, there’s a good chance you’ll want to load or run some or all of your scripts only in browsers that you’re supporting. So how do we do that?

Well, there are several ways this can be achieved, but the simplest one I’ve found works like this:

  • In your stylesheet, insert a harmless, non-default CSS property on the body element.
  • Use JavaScript and getComputedStyle on the body element to determine if your property is set.
  • If it is, run or load your other JavaScript.

For example, the clear property has a default value of none. Setting it to both on the body is unlikely to have any impact on the display of your page (if it does then you’ll have to use a different property). So the code would look like this in your stylesheet:

body {
  clear: both;
}

And on your page (or in a script file):

var is_supported = false
  , val = '';
if (window.getComputedStyle) {
  val = window.getComputedStyle(document.body, null).getPropertyValue('clear');
} else if (document.body.currentStyle) {
  val = document.body.currentStyle.clear;
}

if (val == 'both') {
  is_supported = true;
}

Final Code

Hacky or not, what I’ve tried to show here is a reusable way to detect a relatively modern browser and to prevent older browsers from applying styles or running scripts, causing them to display only the HTML of your page. The code required is quite minimal and it should allow you to concentrate your efforts on building wonderful things for more modern browsers using more modern techniques without worry.

Although you may not need everything I’ve presented here, putting all the pieces together gives us this:

<head>
  <link rel="stylesheet" href="mq-test.css"
        media="only screen and (min-resolution: 0.1dpcm)">
  <link rel="stylesheet" href="mq-test.css"
        media="only screen and (-webkit-min-device-pixel-ratio:0)
        and (min-color-index:0)">
  <link rel="stylesheet" href="mq-test.css"
        media="only screen and (-webkit-min-device-pixel-ratio:1.1)">

  <!--[if IE 8]>
  <link rel="stylesheet" href="mq-test.css">
  <![endif]-->

  <script>
    if (navigator.userAgent.indexOf('UCBrowser') > -1) {
      var link  = document.createElement('link');
      link.rel  = 'stylesheet';
      link.href = 'mq-test.css';
      document.getElementsByTagName('head')[0].appendChild(link);
    }
  </script>
</head>
<body>
<!-- content here... -->
  <script>
    var is_supported = false
      , val = '';
    if (window.getComputedStyle) {
      val = window.getComputedStyle(document.body, null).getPropertyValue('clear');
    } else if (document.body.currentStyle) {
      val = document.body.currentStyle.clear;
    }

    if (val == 'both') {
      is_supported = true;
    }

    if (is_supported) {
      // Load or run JavaScript for supported browsers here.
    }
  </script>
</body>

I’ve made another test page with all of the extras (From time to time, SitePoint removes years-old demos hosted on separate HTML pages. We do this to reduce the risk of outdated code with exposed vulnerabilities posing a risk to our users. Thank you for your understanding.).

Credits

I couldn’t have done this without the use of BrowserStack, Can I Use and the work of the folks at Browserhacks and Jeff Clayton, so thanks to all those involved, and please let me know if you have any thoughts or feeback.

Frequently Asked Questions (FAQs) about CSS Media Queries and “Cutting the Mustard”

What does “cutting the mustard” mean in the context of CSS media queries?

In the context of CSS media queries, “cutting the mustard” is a term used to describe a technique where a website or web application checks if a user’s browser supports certain features before delivering the full experience. If the browser doesn’t “cut the mustard,” a simpler, more basic version of the site or app is delivered instead. This approach ensures that all users can access the site’s content, regardless of their browser’s capabilities.

How do I determine if a browser “cuts the mustard”?

To determine if a browser “cuts the mustard,” you can use a simple JavaScript test. This test checks if the browser supports certain features, such as querySelector and localStorage. If the browser passes the test, it’s considered to “cut the mustard” and can handle the full experience of your site or app.

Why is the “cutting the mustard” technique important?

The “cutting the mustard” technique is important because it ensures that your website or web application is accessible to all users, regardless of their browser’s capabilities. By delivering a simpler version of your site to browsers that don’t “cut the mustard,” you can ensure that all users can access your content.

Can I use CSS media queries without JavaScript?

Yes, you can use CSS media queries without JavaScript. However, using JavaScript in conjunction with CSS media queries allows you to deliver a more tailored experience to users based on their browser’s capabilities.

What are some examples of features that might be checked in a “cutting the mustard” test?

A “cutting the mustard” test might check for features such as querySelector, localStorage, and addEventListener. These are all features that are supported by modern browsers but may not be available in older browsers.

How can I implement a “cutting the mustard” test in my own website or web application?

To implement a “cutting the mustard” test, you can use a simple JavaScript test that checks for certain features. If the browser passes the test, you can then use CSS media queries to deliver the full experience of your site or app.

What happens if a browser doesn’t “cut the mustard”?

If a browser doesn’t “cut the mustard,” it will be delivered a simpler, more basic version of your site or app. This ensures that all users can access your content, regardless of their browser’s capabilities.

Can I customize the experience delivered to browsers that don’t “cut the mustard”?

Yes, you can customize the experience delivered to browsers that don’t “cut the mustard.” You can use CSS media queries to tailor the design and functionality of your site or app for these browsers.

Are there any downsides to using the “cutting the mustard” technique?

One potential downside to using the “cutting the mustard” technique is that it requires additional development time to create and test the simpler version of your site or app. However, the benefits of ensuring that all users can access your content often outweigh this drawback.

Is the “cutting the mustard” technique still relevant today?

Yes, the “cutting the mustard” technique is still relevant today. While modern browsers support a wide range of features, there are still many users who use older browsers that may not support these features. By using the “cutting the mustard” technique, you can ensure that your site or app is accessible to all users.

Andy KirkAndy Kirk
View Author

Andy is a full-time web developer for the University of Oxford and occasional freelancer. His interests include all things web-related but with a focus on front-end technologies and development. (Any views expressed in this article are those of Andy Kirk and do not represent the views of the University of Oxford.)

AdvancedCSSbrowser supportcutting the mustardfallback cssLouisL
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week