Proposal: Scripting detection using CSS media queries
I’ve been doing a lot of thinking about CSS media queries lately. I’m a big fan of media queries, as I think they bring a sense of sanity to feature detection. That’s a big reason why I was investigating CSS media queries in JavaScript1 and will continue to do so. I think we’re only scraping the surface of what can be done with media queries on the web. As part of my pondering over the holiday break, I scribbled down a few notes of ways I’d like to use media queries. I just proposed the first one to the CSS working group.
The Proposal
Yesterday, I sent an email2 to the CSS working group with my proposal. The basic idea is to allow you to determine if scripting is enabled in the browser using a media query. The proposal can be summed up with a few examples:
@media screen and (script) {
/* styles to apply only when scripting is enabled */
}
@media screen and not (script) {
/* styles to apply only when scripting is disabled */
}
So, just like you currently use device-width
, orientation
, and so on to detect features of the device, you could also use script
in the same way.
Rationale
In the realm of progressive enhancement, you don’t want to show page elements that can’t be used. This may be as simple as an arrow next to link indicating a dropdown menu is available. If JavaScript is disabled, you want the link to act like a regular link and not confuse people by having an arrow that means nothing. So you want to apply the style that shows the arrow only if JavaScript is enabled.
The most common approach to this problem is to add a class to the <html>
element via JavaScript. So somewhere on the page, you put:
<script>
document.documentElement.className += " js-enabled";
</script>
This adds the class js-enabled
via JavaScript. Of course, this only gets executed when JavaScript is enabled. You can then define CSS rules such as:
.arrow {
/* empty */
}
.js-enabled .arrow {
background: url(image.png) no-repeat;
}
It’s a bit of a hack, but this basic technique is in use by large sites such Twitter and the Yahoo! homepage, as well as being done automatically by Modernizr and YUI.
While this technique works, it has two downsides. First, you need to include that little JavaScript snippet (or a supporting library) to ensure the class ends up being added. Second, it alters the specificity of your rules, which can adversely affects the cascade.
Clarifications
I’m a big believer that common patterns should be codified and standardized so that the development community can move on to more interesting challenges3. As such, it seems that the community has spoken that we want to define different styles when JavaScript is enabled, and CSS media queries seem like the right approach.
The CSS Media Queries specification4 states:
A media query consists of a media type and zero or more expressions that check for the conditions of particular media features. Among the media features that can be used in media queries are ‘width’, ‘height’, and ‘color’. By using media queries, presentations can be tailored to a specific range of output devices without changing the content itself.
The term media feature is key. When I was first debating myself over whether scripting support is appropriate for a CSS media query, I went and read the specification. Script support is just as much a media feature as color depth and orientation. It’s a capability of that particular device at the time your page is loaded. Given that, I felt comfortable proposing the inclusion of script
as another media feature to test.
To be clear, my proposal’s goal is to easily indicate whether or not scripting is enabled in a browser. Think of it as a relative of the <noscript>
element. So instead of doing something like this:
<noscript>
<style>
.foo {
color: red;
}
</style>
</noscript>
You could do this:
@media screen and not (script) {
.foo {
color: red;
}
}
Of course, by omitting not
, you could also apply changes when scripting is enabled.
Some non-goals of this proposal are:
- Replacing JavaScript feature detection. You will still be checking, in JavaScript, if certain features are available. In short: I’m not looking to propose implementing media query features for all possible JavaScript APIs. If you want that, you should use Modernizr.
- Enabling JavaScript in CSS. I have no desire to have JavaScript in CSS in any way, shape, or form.
- Be JavaScript-centric in detection. Actually, the intent is to indicate if scripting is enabled, not just JavaScript. It would probably be easy to extend the syntax, such as
(script:"text/javascript")
, but I’m not sure that’s necessary at this point.
And as I always like to remind people: no one would force you to use this feature if it’s implemented. If you don’t like it, you can always leave it to those who do.
Conclusion
I think CSS media queries are one of the best things to happen to the web, and I look forward to using them in new and interesting ways. Adding feature detection for scripting seems like a logic step towards standardizing a fairly common practice. The good news is that Florian Rivoal, one of the editors of the CSS Media Queries specification has agreed5 to write it up as a proposal for inclusion in CSS Level 4 Media Queries. I hope the proposal is able to move forward quickly.
References
- CSS media queries in JavaScript, Part 1 by me
- Proposal: Detecting JavaScript with media queries by me
- When web standards fail us by me
- CSS Level 3 Media Queries
- Re: Proposal: Detecting JavaScript with media queries by Florian Rivoal
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.