The Big CSS Media Query Mistake

Do you ever feel weird when everyone around you is doing something you would ordinarily think is wrong [or not quite ideal at the very least], but somehow no one seems to want to say anything for one reason or another? It’s a very strange feeling to see everyone doing their best impression of a hapless observer. It kind of reminds of me of that old fable, “The Emperor’s New Clothes.”

I’ve kind of always felt that way about CSS media queries. Why is everyone just so accepting of a technology that just doesn’t seem to be getting the job done? Why haven’t we as a community come together and improved it in a real and meaningful way? Why haven’t we come up with something better?

Today, CSS media queries just happens to be the functional cornerstone of responsive web design. But, it was never designed for what everyone’s using it for today, and the proof is in the practice. I still often stumble on websites when using a tablet device that at-first seem well-designed, but just happen to look and feel downright wonky when you put them through their paces.

There’s something fundamentally wrong with this approach to responsive web design that we just have not properly addressed yet, and I’d like to be one of the few voices to call the emperor out for his nakedness on this one. Thankfully though, in this day and age, I’m glad there’s almost zero chance of being burned at the stake for having this alternative viewpoint.

What’s Wrong With CSS Media Queries

CSS media queries were designed for something, but that thing isn’t responsive web design. Based on my experience, here are seven (7) big issues I’ve run into when trying to use them for working with websites:

1. Not intuitive:

“CSS media queries are intuitive”, said no web designer ever. The way you define a media query is pretty straightforward, but it’s not always exactly clear how things will play out on real browsers, on real devices, and in a myriad of scenarios.

@media only screen and (min-width: 320px) and (max-width: 480px) {
    /** CSS rules go here **/
}

The code above applies to the viewport when it is between 320 and 480 pixels. However, it’s not exactly definitive [or intuitive] when you want to do something more specific, like apply a style rule when the device is a tablet in landscape operation. It’s not impossible to [sort of] set a media query up to do this, but it’s definitely not intuitive – or definitive.

2. Limited conditionality:

CSS media queries are dynamic and enable you to define conditional statements in your CSS. For example, if the viewport is between this and that, then do the other. However, you are limited to viewport considerations mostly, and there are many more conditional scenarios that would make sense in modern web design.

Mobile design guidelines for tab bar

Say you’re building a progressive web-app. There are times when it would be useful to style certain UI elements differently based on the OS. For example, it is customary to have the tab-bar at the bottom for iOS devices, while for Android the reverse is the case. So, how exactly would you get this to work with CSS media queries?

You can’t, because CSS media queries are not built with any feature that would let you. Besides this, there happen to be numerous other customizations that you may need to be made via CSS, but media queries isn’t an option when you need varying degrees of simple to advanced conditionality.

3. Not natively extensible:

CSS media queries are functionality that is baked into the browser. This means that it is not natively extensible. In other words, you can’t add extra and enhanced capabilities to CSS media queries natively via the CSS interface.

Even if new CSS media query features are approved by the [long-suffering] web standards process, it still takes time before these features become usable on account of ubiquity. In addition, not every feature that is added may be useful to you, so you are left to figure out some other way to solve your specific challenge if you don’t get what you want.

Of course, there is a way to extend CSS, but you have to know JavaScript really, really well, and it’s not a process that is practical for most web designers.

4. Not suited for retrofit:

Some might find this hard to believe, but before mobile devices showed up, there were actually a lot of websites out there, and none of them were mobile-friendly. As a result, these desktop-era websites needed to be upgraded.

Unfortunately, CSS media queries are not a very good option for this task. Because these websites were built before mobile devices were relevant, a lot of them have design elements that don’t lend themselves to responsive web design e.g. sidebars, table-based layouts, tabbed content, etc. Also, a sizable proportion of these websites are built on a content management system (CMS) like WordPress, Drupal, Magento, etc., and integrating CSS media queries [front-end] effectively from the back-end is extremely difficult to near impossible to coordinate.

I’ve had to retrofit websites powered by Magento Enterprise, WordPress, and one that used a custom CMS based on Coldfusion, and all projects would have been downright impossible using CSS media queries [which is what all my clients tried prior to using our alternative approach].

5. Not code efficient:

Using CSS media queries to make a web page responsive requires code multiplication on a significant scale. Because of the way these directives work [with your breakpoints], you have to define individual style rules in each and every media query block.

section {width: 960px;}

/* Portrait */
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait) {
    section {width: 100%}
}
/* Landscape */
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape) {
    section {width: 100%;}
}

When writing the code above, my original intention was to make the <section> elements on my page fluid [width of 100%] in all mobile devices. However, since I don’t have native device-detection capability, I have to compromise and define a style rule in each and every mobile-oriented CSS media query block to make sure that the new property will apply in all relevant scenarios.

This means that the functional efficiency of the stylesheet cascade, and the good development principles of Do-not-Repeat-Yourself, have to take a back seat.

6. Increases workflow complexity:

CSS media queries handle only a very specific aspect of responsive web design that is almost entirely focused on layout resizing. Ergo, to do anything more than that, you have to rely on JavaScript to make up the difference. This introduces additional learning requirements for code and tools.

In addition, the non-definitive way it [media queries] handles breakpoints means that you have to spend more time [and money] testing your web pages in numerous virtual and/or physical devices to make sure that things work the way you originally intended. And, you need to retest everything again when you make any significant changes to your layout.

By the simple and purposeful action of using CSS media queries, you significantly increase the number of steps required to build a modern web page.

7. Worsens performance:

On account of the way CSS media queries work, you will end up needing a lot more CSS code than otherwise to make your website responsive/mobile-friendly. According to data from HTTPArchive.org, CSS file sizes have increased by 114% over the last five years. The increase in HTML file sizes peaked at about 53% over the same period.

This peculiar situation has performance implications for your website as it is bound to be slower after implementing CSS media queries [in a responsive web design context] than it ever was before, especially for mobile devices using less-than-ideal mobile broadband networks.

And, asides from the issue of increased file sizes, there is no internal mechanism within CSS media queries to actually improve the performance of your web page. For that, you’re going to have to leverage advanced JavaScript techniques to enable these enhancements.

Why are we still using this?

If I asked you what percentage of websites were using CSS media queries, what would your answer be? With all the stress web designers have had to endure over the years, you’d think we’d have probably gotten over the adoption hump by now, but you’d be very wrong.

The percentage of websites using CSS media queries across the entire web is about 0.2%. Contrast that with the percentage of websites using jQuery at 18%. What that means is that you are 90 times more likely to come across a website that is powered by jQuery than you are a responsive website [not including those that happen to be both].

Why would a toolkit based on a core technology [JavaScript] that certain folks seem to think is complicated and superfluous be so far ahead of one that is seemingly less complex [CSS] and meant to address an arguably more important problem [mobile-friendliness]? Obviously, there’s something seriously wrong here that is hindering adoption, and it needs to be addressed.

CSS media queries found it’s way into web browsers to handle a specific challenge, but it was then drafted to carry the whole weight of responsive web design on its shoulders. It’s kind of like practicing for a 3rd-grade recorder recital, only to be magically transported to Royal Albert Hall to render a trombone solo of Handel’s Messiah; No fair!

With all the challenges of modern web design, it’s extremely surprising that we’re still on this media query business. It doesn’t go far enough to deal with some important legacy issues, in addition to some new ones in new fields like progressive web-app design. As such, I think it’s time we came up with an alternative. But, what would that be exactly?

What is the Solution?

The solution to all this is really very simple: JavaScript. Now, before you pick up that pitchfork, give me a chance to explain.

JavaScript is the only component of the HTML5 trinity where extensibility is not a dirty word. You can’t extend HTML markup using more HTML, and you sure as heck can’t extend CSS natively with CSS. However, you can extend JavaScript natively using JavaScript, and you can even do the same for CSS.

Manipulating CSS with JavaScript is extensively discussed in the W3C’s Web Standards Curriculum. The document.stylesheets DOM interface enables us to access the stylesheets applied to a web page, including all the external stylesheets referenced using HTML’s <link> tag. It’s not an easy thing to do, but it’s possible.

So I should expand on the initial answer: it’s not simply JavaScript, it’s JavaScript-assisted CSS. JavaScript is an awesome platform with functionality like you wouldn’t believe, but CSS is where most web designers work. If we could somehow create some kind of functional bridge between these two where a web designer could write a CSS ruleset to leverage JavaScript functionality, that would be somewhat of a game-changer for web design.

Show me some code

For the last two years or so, I’ve been working on a new JavaScript-assisted CSS toolkit called rKit. The whole idea was to build a designer-friendly tool to not just replace CSS media queries for responsive web design, but to address some of the known [and unknown] challenges web designers/developers face when building modern websites and webapps.

There’s a lot to the concept, but here’s a quick code snippet of CSS to explain:

#my-element[rk="if @viewport.width between 320 and 480"]{background-color: #0000ff;}

With rKit, the CSS rules look like modified attribute-value selectors. You can then define an expression within the value section. The syntax of this expression is designed to be simple and intuitive.

Note: rk is a constant attribute identifier.

The code above is functionally equivalent to the CSS media query below:

@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
    #my-element {background-color:#0000ff;}
}

However, there’s a lot more you can do with rKit. Here’s another quick example:

#my-element[rk="if @self.width between 320 and 480"]{background-color: #00ff00;}

By simply changing the entity reference from @viewport to @self, we’ve essentially setup what is commonly referred to as an element query. So what now happens is that when the width of #my-element is between 320 and 480 pixels, the given declaration [background-color: #00ff00] will apply.

You can also use classes instead of pure declarations:

#my-element[rk="if @self.width between 320 and 480 then addClass(c_mobile_320)"]{}
.c_mobile_320 {background-color: #00ff00;}

This is just the tip of the iceberg though. With rKit, you can do some pretty awesome things like event management, mutation observation, quantity queries, routing, data-binding [up to 7-way], and a host of other cool stuff, all using pure CSS code, and without writing a single line of JavaScript.

rKit will be free and open-source when it’s launched. And, it will also sport a special performance pack that you can install in a way that guarantees zero render-blocking, so the web page loads like a rocket on rails.

It’s taken quite a while to put this together, but it’ll be here soon [definitely before Godot], and I’m really interested to see just what web designers [and developers] are able to do with it.

Conclusion

I hope you don’t come away from this post thinking I’m bashing CSS media queries just because. I’m not. That would be like bashing a tomato for ending up in a fruit salad. Like I said earlier, CSS media queries were never designed for responsive web design. It was co-opted on account of expediency, and we all made the misstep of trying to use it to solve all the problems.

Sadly, we as a web community never really got around to correcting that initial mistake by improving it in a significant way, or coming out with a better alternative. But alas, shows must go on, websites must be built, and progress must prevail. It’s time for a change.

rKit is merely one option and one answer. It’s not the first, and it definitely won’t be the last. But, at the very least it is a right step in the right direction. An opportunity to fix some problems of the past, and then iterate to fix those in the now and into the future. It would be interesting to see how it matches up against the status quo.

All tolled, making a mistake is not an end in itself; it should be a learning experience. With any luck, we’ll learn how to use the right tool for the right job next time. I mean, just because you can ride a bicycle on a paved road doesn’t mean you should bring one to the Nürburgring. Bring a Porsche!

Comments

  • James Delaney

    Isn’t that section example a bad one? Assuming a mobile device and specifying 100% wide as the default, then using media queries for the desktop view would surely be better? I do agree with most of your points.

    I don’t necessarily agree that you can make the assumption that because only 0.2% of sites use max-width that only 0.2% of websites are not responsive. Many of the 99.8% may not ever have been intended to be used on a touch-screen, or mobile device – with no desire for it to do so in the future either.

    The BuiltWith Top Million is maybe a better metric: 512,149 of 827,020 or 61.9% of popular website using max-width.

    They are a dog to write and maintain though :)

  • Albo P. Fossa

    One might with some validity question the *real* advantage of using javascript to detect the very same conditions as the media query. And then place the resulting detection results back in the form of CSS. For, as you might detect, the javascript code is larger in size than the original (or added) CSS, which has bandwidth implications. And CSS can be cached on the client side, reducing client side computation for page presentation.

  • Obinwanne Hill

    Hi James. Thanks for your comment.

    I think we have to look at the entire Web; not everyone is going to be in the Top million. Also, with over 50% of traffic being over mobile, I think we are passed the stage of making websites that are not intended for mobile; they just have to be in today’s world. Fast too.

    All tolled, it would be nice to have some viable alternatives to CSS media queries.

    Edit: Sorry, I missed the question on the section example. No, sometimes you might not have 100% as the default; you could be using a 960px, 1140px, or other grid; it’s not always mobile-first.

  • Obinwanne Hill

    Hello Albo. The trick is for the JavaScript to work with CSS via CSS; not for Web designers who usually have no inclination for advanced development to learn copious amounts JavaScript just to get complex tasks done. This way, they can do some advanced things with a few lines of CSS. And regarding performance, rKit actually has a novel two-line install feature that is non-blocking, so no worries there.

  • Another option is to stop thinking that just because there’s screen real estate that you HAVE TO use it. That might not eliminate all of the above but it certainly helps to streamline things. In a way it’s rebranding mobile-first as unified-experience. You’re still designing and developing for all, you’re just not doing that based on the availability of screen real estate.

  • John Phoenix

    Media queries, as “ugly” and “verbose” as they are, does serve their intended purpose (as the article states), I offer two alternatives to ponder

    1. data attributes on the body Eg. data-min-width=”480″ and then styling it via the css cascade

    2. Straight classes (like rk but as a string like name not an array like structure, for easier regex)
    [email protected]

    Both of these options require a javascript resize listener (denounced hopefully) to work across multiple devices/resolutions and planning out your stylesheet beforehand.

    Cross browser dimension retrieval is tricky, specifically with height based queries and cognitive load is also increased on the developer to augment their vocabulary to include this new syntax.

    All of the factors above rolled into one js file adds much more tax to the site.

    Yes media queries “feel wrong” inside a stylesheet, my suggestion would be to move the mq out as an attribute on the link to the required stylesheet, that way the browser is at least partially aware of the variances before it parses the styles. And can download the most correct one first.

    Furthermore Rk mixes presentation and logic even more than media queries do, adding more overhead to the render time. At this rate we might as well ditch the separation of concern and just create massive json files that contain html/css/events/logic and render it using js.

    Your thoughts?

  • Obinwanne Hill

    Hi John. Thanks a lot for the detailed feedback.

    As you’ve mentioned, there are actually quite a few ways to manage breakpoints without CSS media queries. I’ve done so quite effectively using rScript [formely restive.js], which is more inline with your second option, and I’ve never looked back. It actually handles the resize handler [throttled for better performance] and cross-browser dimension requirements very well, and it is no longer dependent on jQuery. We’ll be launching rScript quite soon.

    As to the issue with mixing presentation and logic, the impact is quite light. rKit doesn’t try to turn CSS into a programming language; that would be counter-productive. Instead, the big idea is to enable a functional bridge that allows Web designers reach beyond the curtain and engage with JavaScript. I also think you will be pleasantly surprised with the render time of rKit; it’s really fast.

    Finally, it uses a unique loading mechanism to ensure high performance. It’s optional, but there’s an installation option where the payload is split into 2 files; critical and non-critical. The critical file [less than 20k gzipped] loads asynchronously and then loads the non-critical file [which is deferred via an irregular type attribute on the SCRIPT tag] after the parser is done constructing the DOM. The result is that there will be no render-blocking.

    So a lot of your concerns are quite valid, but they’ve been addressed in rKit by design.

    I’d be interested to know how you handle breakpoints today?

  • Albo P. Fossa

    While I can understand the intent you have described, my point is ultimately independent of the technician who develops the code. It is about the code that is generated, and its efficiency. Cached CSS can be rather more efficient than re-sent javascript which executes on the client side to generate (altered HTML? and) non-cached CSS

  • Albo P. Fossa

    My point, too. From one of the examples presented above, I deduce the same elements as might occur in a CSS media query. Some (of course, not all) careful CSS coding can avoid the need for much media querying. I have found ways in some of my sites to limit my query adjustments to a very few font-size changes. (Of course, if you *want* to consider old IEs—which I ignore—you could use others.)

  • Obinwanne Hill

    Understood. CSS will always be more efficient [to a certain degree], but there are things that only JavaScript can do. In this scenario, there isn’t an option but to use JavaScript. With rKit, you have the option of a bridge to get you to where you need to be without having to climb Mt. JavaScript. And, I’m not sure what you mean by ‘re-sent’ JavaScript, but I can assure you that rKit is performant in a number of ways. More on this when it comes out next month