Sniff my browser: The Modernizr inadequacy

17th May, 2011 @ 12:03pm UTC

Accessibility, Browsers, CSS, Development, HTML, JavaScript, Thoughts, Tools, Web, Web Standards / 44 Comments

I’m currently involved in a project to write a fairly extensive set of best practices for front-end development. Alongside myself, this project includes input from a fair cross-section of my peers in the front-end development community. These best practices will be implemented alongside a coding standard as standards for development within the organisation I work for, and hopefully many other organisations when they are published.

Of all the standards that a front-end team might want to implement, those that concern the identification and graceful degradation of cross-browser feature sets can be the hardest to define.

With that in mind, I’ve been poking around the front-end community looking for possible solutions. By far the most common approach—and one that gains an astounding level of attention in the community—is to implement Modernizr, a JavaScript feature sniffer created by Faruk Ate?, Paul Irish and Alex Sexton.

Unfortunately, despite my respect for the developers involved, I just can’t advocate Modernizr as a solution. Let me explain why; but first, let’s revisit some concepts that are going to be quite relevant…

The web standards trifle

The separation of structure, presentation, and dynamic behaviour is imperative to web standards. To that end, Andy “Malarkey” Clarke wrote a fantastic post detailing a method he liked to use to explain this fact to clients. He entitled it “the web standards trifle”.

In Andy’s metaphor, the separation of concerns can be imagined as follows:

  1. Sponge

    This layer is your content, marked-up with well structured and valid semantic HTML. This HTML provides more information about each piece of content and allows any device reading the code to output as appropriate.

  2. Fruity jelly

    This is your presentational layer. This separates all your presentational code into CSS, potentially allowing a user to override it with their own, or for you to serve something different based on context, e.g. a print or mobile stylesheet.

  3. Custard

    This is the layer that accommodates any on-page behaviours. In the world of web standards we use this layer to progressively enhance our HTML and CSS layers with more interactive magic. I’ll come back to this later.

The true virtue of this divide is that the presentational (jelly) and behavioural (custard) layers can potentially be removed or overridden without affecting each other, or the content and markup beneath. This is hugely important if we want our websites to maintain client agnosticism and improve accessibility.

Progressive enhancement

Following the publication of this article there have been several suggestions that I explain the difference between graceful degradation and progressive enhancement. Suffice to say, this is something I have covered previously in another article.

Browser vs. Feature Sniffing

Browser “sniffing” is the act of attempting to discern a user’s browser by some means. This “awareness” can then be used in conditional code to control output or interaction for a specific browser. This technique was used a great deal in days of yore, when browsers had very different rendering engines and didn’t all conform to web standards. However, it was only ever really required in JavaScript.

The old school way:

if (document.all) {
    // IE4
    height = document.body.offsetHeight;
} else if (document.layers) {
    // NN4
    height = window.innerHeight;
} else {
    // other
    height = 0;
}

Not a good solution

There are problems with the method used above; for one thing, it is not the most direct method of identifying a browser. However, putting that aside for the moment, there are issues even with the theory of browser sniffing:

It’s quite obvious that browser sniffing does not scale. As new browsers are released, the sniffing code will need updating.

To make matters worse, many manufacturers developed their browsers to identify themselves incorrectly to get around legacy browser sniffing code. This ultimately meant that sometimes browsers were misidentified.

Ultimately browser sniffing is not a good solution. If you adopt it, you will usually end up maintaining separate streams of development whenever you need to add or update features. There are ways to mitigate that pain, but what if there was a better solution?

Feature sniffing

A more scalable approach is to use object detection in JavaScript to discover if a feature is available before you use it. An example of this might be:

if (document.querySelector) {
    element = document.querySelector(selectors);
}

The obvious advantage here is that it is browser agnostic; there are no assumptions as to which browser is involved at all. Using this technique, we overcome the scalability and maintenance headaches incurred through browser sniffing, and we can develop for graceful degradation from the outset.

CSS is a DSL that lacks features

Now, that’s all very well and good when we’re talking about JavaScript, but what happens when we need to affect the presentation layer?

CSS is a very simple domain specific language (DSL) that functions as a series of rules that override each other in a variety of ways (the cascade). There is no mechanism to detect a specific feature or a user-agent; only media types and potentially the odd CSS hack where a user-agent has imperfectly implemented an interpreter. There are also no conditionals; you just have to use the cascade to provide alternatives based on specificity or even just source order.

With these limitations, it is impossible to implement either browser or feature sniffing in CSS. This means we need to find an alternative method to affect the cascade based on the user’s feature set.

The Modernizr method

Step in Modernizr. In the words of the documentation:

Modernizr aims to bring an end to the UA sniffing practice. Using feature detection is a much more reliable mechanic to establish what you can and cannot do in the current browser, and Modernizr makes it convenient for you in a variety of ways:

  1. It tests for over 20 next-generation features, all in a matter of milliseconds.

  2. It creates a JavaScript object (named Modernizr) that contains the results of these tests as boolean properties.

  3. It adds classes to the html element that explain precisely what features are and are not natively supported.

Following along so far? For the most part, that all seems fairly good. What’s more, Modernizr is definitely being pushed as the solution of choice amongst the front-end community:

So with all that in mind, let’s go back to why I will not be recommending Modernizr as a best practice:

Sniffing CSS features with JavaScript

The real issue is that Modernizr uses JavaScript to do the feature sniffing. This method is absolutely fine if we were only looking to test for the features in JavaScript. However, Modernizr is marketed on its ability to detect CSS3 and HTML5 features so that you can write gracefully degrading CSS:

Modernizr is a small and simple JavaScript library that helps you take advantage of emerging web technologies (CSS3, HTML 5) while still maintaining a fine level of control over older browsers that may not yet support these new technologies.

If Modernizr had sold itself as a JavaScript feature sniffing solution that also detected CSS features perhaps I could be more forgiving. In that context, it would be the developers’ responsibility to use Modernizr correctly. However, since the Modernizr site and documentation are selling it specifically as a CSS feature sniffing solution, for primary use within CSS, the error is clearly with the Modernizr team themselves.

It’s all down to the final step outlined in the documentation I quoted earlier:

It adds classes to the html element that explain precisely what features are and are not natively supported.

Modernizr uses JavaScript to add those classes to the html element; one for each of the features detected in the current browser. If we examine the generated source we see the following:

<html lang="en" dir="ltr" id="modernizr-com" class=" js flexbox canvas
canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb
hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize
borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns
cssgradients cssreflections csstransforms csstransforms3d csstransitions
fontface video audio localstorage sessionstorage webworkers applicationcache
svg inlinesvg smil svgclippaths">

When I first saw that, I was horrified. Not only is it ridiculously cluttered, it also feels decidedly unsemantic and looks like a terminal case of classitis. However, let’s try to be pragmatic here; it’s a means to an end, potentially a minor side-effect to a process that will win us some power in the bigger picture. In fact, it’s one step on from Paul Irish’s proposed work around to the FOUC (flash of unstyled content) which I’ve advocated as a reasonable fallback to marking progressively enhanced objects with an “enhanced” class.

Making use of the classes

The Modernizr method allows you to assign styles based on these new classes on the document’s root element like so (example lifted from the Modernizr docs):

button.glossy {
   background: #ccc url(gloss.png) 50% 50% repeat-x;
}
.cssgradients button.glossy {
   background: #ccc -webkit-gradient(linear, left top, left bottom,
         from(rgba(255,255,255, .4)),
         color-stop(0.5, rgba(255,255,255, .7)),
         color-stop(0.5, rgba(0,0,0, .2)),
         to(rgba(0,0,0, .1)));
}
.cssgradients button.glossy:hover {
   background-color: #fff;
}

Here we can see that button.glossy is first defined with a standard png as its background. The Modernizr-added .cssgradients class is then used to increase specificity and assign a WebKit gradient instead.

What happens if we approach the problem without the .cssgradients class:

CSS allows us to define a property twice in the same rule. It also contains built-in error handling that will ignore a property it doesn’t understand; so browsers that do not understand -webkit-gradient(), for example, will simply ignore a property that uses it. This allows us to progressively enhance our CSS like so:

button.glossy {
   background: #ccc url(gloss.png) 50% 50% repeat-x;
   background: #ccc -webkit-gradient(linear, left top, left bottom,
         from(rgba(255,255,255, .4)),
         color-stop(0.5, rgba(255,255,255, .7)),
         color-stop(0.5, rgba(0,0,0, .2)),
         to(rgba(0,0,0, .1)));
}
button.glossy:hover {
   background-color: #fff;
}

However, because we can no longer target the .cssgradients class specifically, we cannot target the button:hover styles only when CSS gradients are detected. Clearly this is an issue we’ll have to find some way around and is exactly what Modernizr is attempting to solve.

This all seems as if Modernizr is giving us a great deal of power, however, it comes with a significant cost.

Dependency on JavaScript is bad

Fellow web developer and good friend Mike Davies wrote a really great article containing a good summary of obstacles potentially preventing JavaScript from executing back in October 2010. This followed a somewhat presumptuous post by Nicholas Zakas on the YDN regarding the number of users with JavaScript disabled.

In short, there are a large number of obstacles that can affect the execution—or even rewrite the source of—JavaScript included in your pages. Hence, dependancy on JavaScript is bad because it introduces many significant points of failure.

As an example of why dependency on JavaScript can be catastrophic, I recommend you read another of Mike’s posts on Gawker’s JavaScript dependent URIs and how it broke their sites quite considerably. It’s worth noting that the Gawker sites have since seen the error of their ways and are attempting to fix the damage.

Styling dependant on JavaScript

By adding styles that are specific to classes that have been inserted with JavaScript, we are making those styles dependant on JavaScript. This means those styles will fail to apply if JavaScript itself has been disabled or, more commonly, the JavaScript file applying the classes has failed to load or execute successfully due to one of the reasons above. In essence, we may just as well add those styles with JavaScript directly because we’ve already broken the web standards separation of concerns.

Do we really want to remove the majority of CSS items covered by Modernizr if the Modernizr JavaScript include fails for some reason?

It would only be the feature-sniff-dependant CSS rules that would fail, since those classes would now be missing. Potentially this only means the loss of a few nice in-browser rendering optimisations. However, it also means there is a significant loss in the overall structure of specificity within your stylesheets, which could easily cascade unintended effects through to other elements. This could easily result in some content being styled to be unreadable, or worse, incorrectly hidden. This would be very bad indeed.

Alternative solutions

Modernizr is clearly unfit for purpose. If it were simply a JavaScript feature sniffing library for use only in JavaScript, it would be a suitable solution although only really useful for JavaScript progressive enhancement.

With that in mind, what other options are available that allow us to target our CSS?

Server-side browser sniffing

We could browser sniff on the server and add a class to the html element as we generate the HTML that is delivered in the HTTP response. This could result in something like the following:

<html lang="en" dir="ltr" class="firefox">

This means we can target CSS with the .firefox class in much the same way that we used the feature classes that Modernizr provided. There is no way for us to perform feature sniffing on the server; the best we could offer is a feature lookup based on the user-agent string that we’ve used to sniff the browser, but that would ultimately still be browser sniffing.

In fact, the best browser sniffing solution would allow us a little more flexibility on browser versions:

<html lang="en" dir="ltr" class="moz ff ff3-6">

Note I’ve added several classes this time; one for the rendering engine, one for the browser, and one that contains the major and minor versions. This would allow us more specificity.

Update: Matthew Pennell has written an interesting post on server-side browser sniffing with .htaccess and environment variables. Definitely worth a read.

Cache issues

However, server-side browser sniffing means that you’ll run into issues if your pages are publicly cacheable. This server-side solution results in a different HTTP response (the HTML) for each differing browser.

If you utilise any intermediary caching (Squid, Varnish, or a custom origin CDN) for static pages, and you use server-side browser detection, you need to make sure those caches don’t inadvertently send the wrong content to the wrong browser. To do this you’ll need to Vary: User-Agent header in the HTTP response. This instructs any intermediary caches to store multiple copies of the page (one for each User-Agent string that it sees) and to inspect the incoming User-Agent string when looking for cached responses to the current request.

IE targeting with conditional comments

If we’re entirely honest with ourselves as web developers, we can probably admit that the majority of woes we experience in CSS are as a direct result of features that any given version of Internet Explorer has not implemented. In fact, I regularly interview developers who advocate maintaining a separate stylesheet for IE that is included through the use of IE’s conditional comments. Having attempted to use this method in the past, I can confidently say that it is a maintenance nightmare and quickly becomes pretty unmanageable.

A better technique would be to adopt conditional comments to add IE specific classes in much the same way we have with Modernizr or server-side browser sniffing. This method was first proposed by none other than Paul Irish back in 2008 in his article “Conditional stylesheets vs. CSS hacks? Answer: neither“. With that method, our html element would look like this:

<!--[if IE ]>
<html lang="en" dir="ltr" class="ie">
<![endif]-->
<!--[if !IE]>-->
<html lang="en" dir="ltr">
<!--<![endif]-->

This looks a bit odd, and often (for the true markup perfectionist) takes a bit of getting used to. However, it does give us what we need without requiring JavaScript or multiple cache versions.

We can even make it more specific if we so desire:

<!--[if lt IE 7 ]>
<html lang="en" dir="ltr" class="ie ie6">
<![endif]-->
<!--[if IE 7 ]>
<html lang="en" dir="ltr" class="ie ie7">
<![endif]-->
<!--[if IE 8 ]>
<html lang="en" dir="ltr" class="ie ie8">
<![endif]-->
<!--[if IE 9 ]>
<html lang="en" dir="ltr" class="ie ie9">
<![endif]-->
<!--[if gt IE 9]>
<html lang="en" dir="ltr" class="ie">
<![endif]-->
<!--[if !IE]><!-->
<html lang="en" dir="ltr">
<!--<![endif]-->

Quite clearly this gets ever uglier, but the solution is entirely encompassed in the structural layer; we will always have the correct class, even if CSS or JavaScript are unavailable for some reason. We also have the same markup regardless of user-agent string, which means caching is not a problem.

The only flaw with this solution is that we can only target versions of Internet Explorer. No other browser implements conditional comments.

Use CSS properly and make use of the cascade

As previously stated, CSS is designed to cascade. This means the built-in error handling will ignore properties the interpreter does not understand, and we can override rules based on specificity and source order. In most cases, these key features are more than adequate to develop gracefully degrading stylesheets.

Most capable front end developers are already doing this and coping just fine. Add this to the previous IE targeting approach and you’ll find that you do not need to over-engineer a solution.

In summary

So, in summary then, I absolutely cannot recommend implementing Modernizr as a best practice for front end development. It attempts to solve a problem from the wrong direction, and introduces a new potential point of failure. What’s more it breaks the fundamental ethic of web standards; the separation of concerns.

I continue to recommend well crafted, gracefully degrading CSS, backed up by conditional commented classes on the html element for targeting IE.

Modernizr may still be a worthy solution for JavaScript-only feature sniffing, if only it allowed the developer to disable the injection of classes on the html element.

Like this post?

Tweet it or Del.icio.us it!

Pinboard

Advertising

Comments (44)

Skip to the comment form…

  1. Gravatar Image Chris Casciano May 17, 2011 @ 12:59 pm

    I don’t totally disagree with you here, but you’ve said a lot and it all sounds so matter of fact. Modernizr may not be right for you, but it is a great tool among many, an will be quite useful going forward as we deal with more than just MSIE deficiencies. Just 3 quick thoughts:

    (1) Are you also advocating against HTML5 elements due to their need for JS shims in some browsers?

    (2) What ‘switches’ or targeted CSS are you worried about not failing gracefully without modernizr that you would still use without? Consider it for Progressive Enrichment more than Graceful Degradation – border-image in one case yet standard border in others, multiple backgrounds, type that is legible without text-shadow, etc. if JS is off, or if you’re in FF3.0 you’d get the same type of appearance, in both cases appearing fine to the user.

    (3) Modernizr provides objects for JS inspection as well – no CSS Transitions? use a JS based one instead, etc. Again, this covers more than you might with IE conditional comments, and lets you get your foot in the door with some things now (or a year or two from now gives you a great catch basin for those who haven’t upgraded recently)

  2. Gravatar Image Mathias Bynens May 17, 2011 @ 1:16 pm

    You may want to link to the original article describing the conditional IE-specific classnames technique: http://paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/

  3. Gravatar Image seutje May 17, 2011 @ 1:23 pm

    “it also feels decidedly unsemantic” made me chuckle a bit, these are dynamically added classes, nobody really gives a shit…
    suggesting “Server-side browser sniffing” as a solution made me chuckle a little bit more
    and the Gawker javascript example is so completely unrelated to this matter that it just makes me roll on the floor laughing.

    Modernizr is only meant to allow u to enhance progressively, disable javascript and this enhancement goes away, which should leave a properly usable site. If not, you did it wrong

  4. Gravatar Image Nicolas Gallagher May 17, 2011 @ 1:39 pm

    Heads up: your example of conditional HTML tags is broken because the first conditional will insert an opening HTML tag for all versions of IE, and subsequently ignore any additional ones I believe.

  5. Gravatar Image Tim May 17, 2011 @ 1:51 pm

    @Nicolas: Good spot. Thanks for that. Fixed.

  6. Gravatar Image Adam May 17, 2011 @ 2:29 pm

    The rules for Modernizr should be the same as the rules for all JS: make sure the site looks and acts acceptably without Modernizr, and then layer on top any extra features you want.

    Modernizr is fundamentally about decoupling.

    - Using browser-detection couples UA names with features, when those mappings are in fact always changing. So we use feature detection, removing this coupling and future-proofing our sites. Detecting browsers on the server just sends us back the wrong direction.

    - Using browser hacks couples UA css parsers with the styles we want them to apply. So we instead detect for CSS features and then use body classes to add rules to the cascade only when certain features are present, decoupling the styles we want to apply from bugs in the parser reading them.

    - By applying classnames to the body, we decouple the method of detecting features from the clients who want to use detection. We write css or js against the classnames, and if a new scripting language or version of html lets us detect features in a new way, we can just use that new feature to add classnames to the body, ditch Modernizr, and our js or css will still work perfectly.

  7. Gravatar Image Bob Bonifield May 17, 2011 @ 2:35 pm

    If everything falls apart because JavaScript is disabled, the front-end eng did something terribly wrong during the development process. You blame the developer if they don’t test in IE, and you should blame them again if they don’t test without JavaScript.

    Also +1 @Mathias’s comment regarding the original article on conditional IE-specific classnames. Reference your source.

  8. Gravatar Image a May 17, 2011 @ 2:46 pm

    ff3.6 isn’t a valid class name

  9. Gravatar Image James John Malcolm May 17, 2011 @ 3:11 pm

    Couldn’t agree more Tim, you’ve hit the nail on the head.

    @seutje The Gawker example simply shows a case where relying on JavaScript had disastrous consequences for the site in question.

  10. Gravatar Image Mathias Bynens May 17, 2011 @ 3:11 pm

    ff3.6 isn’t a valid class name

    Yes, it is.

  11. Gravatar Image Tim May 17, 2011 @ 3:20 pm

    @Bob, Mathias: Reference added. Thanks for that.

    “The rules for Modernizr should be the same as the rules for all JS: make sure the site looks and acts acceptably without Modernizr, and then layer on top any extra features you want.”

    “If everything falls apart because JavaScript is disabled, the front-end eng did something terribly wrong during the development process”.

    I agree completely with this. I’m pretty sure my article doesn’t disagree with that. If it reads that way then I apologise. I’m all for progressive enhancement, and I’m definitely in favour of supporting a non-JS experience. My point was that there’s no need for us to be dependant on JavaScript just to write CSS that supports both CSS3 and non-CSS3 capable browsers. We can do that in CSS without ever needing to rely on the extra classes added by JavaScript.

    If we write CSS that is reliant on those classes, we’re actually missing out on CSS3 features in our CSS3 capable browser if JavaScript does not execute for some reason. That’s really not graceful degradation.

    “Modernizr is fundamentally about decoupling.”

    I disagree. Modernizr couples CSS and JavaScript quite tightly, as described above.

  12. Gravatar Image Matthew MacLeod May 17, 2011 @ 3:35 pm

    I appreciate your point (especially with regard to introducing another point of failure), but like a couple of the guys above I can’t help but feel that if using Modernizr breaks your site on failure, then you’ve used it wrong. I’m struggling to think of a situation where it *would* cause a problem…

    Server-side browser sniffing is just a weak solution on a lot of levels – one of the things we should try to avoid as web developers is an over-insistence on ideal, standard approaches when practically speaking there is an easier and more sensible solution.

    On the whole, to say “Modernizr is clearly unfit for purpose.” when it actually performs very well in almost all scenarios is a bit misleading.

  13. Gravatar Image seutje May 17, 2011 @ 3:35 pm

    @James John Malcolm
    feels like using Nagasaki as an example of why nuclear power plants are unsafe

    they are only very-very-veeeery vaguely related

  14. Gravatar Image Tim May 17, 2011 @ 3:48 pm

    Just to underline a point here, folks: My “alternative solutions” aren’t necessarily my suggested solutions.

    As you’ve all noted, I present server-side browser sniffing as a potential solution and then outline why it’s not really acceptable.

  15. Gravatar Image Paul Irish May 17, 2011 @ 4:06 pm

    Hio!

    Do we really want to remove the majority of CSS items covered by Modernizr if the Modernizr JavaScript include fails for some reason?

    Def not, however, if this happens to you, then you’re probably doing it wrong. Setting up your Modernizr classes like you showed in your css example is a flawed approach. Like you said, CSS comes with built in error handling so a lot of things like background-color, background-image, etc all will handle the feature-less fallback by themselves.

    Modernizr classes are best used in the no- sense, declaring what happens when there isn’t native support. Either kicking off a polyfill or faking support through background images or other clever CSS use.

    Defining the appropriate use of the modernizr classes is a subtlely I’ve had a hard time covering in the documentation. Luckily a new site is around the corner where we spend more time on basics, rather than special cases. So this will all be much more clear.

  16. Gravatar Image Mike Davies May 17, 2011 @ 4:10 pm

    Matthew MacLeod wrote: “but like a couple of the guys above I can’t help but feel that if using Modernizr breaks your site on failure, then you’ve used it wrong. I’m struggling to think of a situation where it *would* cause a problem…”

    Have a look at the first code example on the homepage of modernizr:

    .multiplebgs div p { ...
      /* properties for browsers that
         support multiple backgrounds */
    }
    .no-multiplebgs div p {
      /* optional fallback properties
         for browsers that don't */
    }

    There’s a four way trigger going on here:

    1.) JS working + supports multiple backgrounds
    2.) JS working + no support for multiple backgrounds

    What happens when JavaScript isn’t running? Neither of these stylerules apply because the JavaScript doesn’t get to add in either of the Modernizr applied classnames. That creates the third and fourth states:

    3.) JS not working + supports multiple backgrounds
    4.) JS not working + no support for multiple backgrounds

    So if the Modernizr guys can’t get their heads around how to use Modernizr without breaking on failure, heaven help those that just use Modernizr.

  17. Gravatar Image Steve Webster May 17, 2011 @ 5:23 pm

    Copying my reply to Paul Irish on HN here:

    Modernizr classes are best used in the no- sense, declaring what happens when there isn’t native support. Either kicking off a polyfill or faking support through background images or other clever CSS use.

    Switching from progressive enhancement (applying styles if you detect a feature is supported) to graceful degradation (applying styles if you detect that a feature isn’t supported) doesn’t solve the underlying problem. In fact, it makes the situation worse. JS failure with the progressive enhancement approach means that everyone gets the fallback experience; failure with the graceful degradation approach means that you’re potentially asking a browser to apply CSS that it doesn’t understand and not offering it a fallback.

    No matter which way you cut it, having CSS predicated on classes set by JavaScript creates a dependency where one should not exist. I realise that’s the whole point of Modernizr, but in my opinion it isn’t the right way to solve this problem. Others may not agree, and that’s fine, but it’s critically important that developers being encouraged to use Modernizr (or its underlying techniques) are made aware of the tradeoff they are making and the potential impact that may have on their users.

  18. Gravatar Image Ross May 17, 2011 @ 6:25 pm

    Re: “It’s quite obvious that browser sniffing does not scale. As new browsers are released, the sniffing code will need updating.”

    I feel like this is a bit of a non-issue. The reason people do browser sniffing 99% of the time is because they need to fix something in IE. And as new browser versions come out, old versions should stop being supported by the sniffing code.

  19. Gravatar Image Marcel Shields May 17, 2011 @ 8:09 pm

    @Mike Davies,
    I agree that the example code would fail in the way you identified without a more specific, non-JS dependent selector class or id. I believe that is only a flaw in the example and not in using Modernizr itself.
    So my thought is like:

    div.reallycoolbox p {/* Base site-dependent styles that must be applied even if JS fails */}
    .multiplebgs div.reallycoolbox p {/* Styles for supporting browsers with JS working */}
    .no-multiplebgs div.reallycoolbox p {/* Styles for non-supporting browsers with JS working */}

    Wouldn’t that fix the problem?

  20. Gravatar Image thugsb May 17, 2011 @ 8:13 pm

    @Paul I have to disagree that Modernizr is best used with the no-classes. Sure, with no-js that’s fine, but not with the rest. Progressive enhancement, not clunky degradation.

    I have to agree with Tim, that Modernizr goes across aspectual dimensions. However, it is a fairly helpful tool.

    Most of us are developing websites for clients that assume JavaScript is turned on, and are relying on servers (or CDNs) that are reliable enough to make sure the scripts get served. So most of the time, we are free to use the flexibility that Modernizr gives us.

    Those who browse without JavaScript are used to sites breaking slightly, just as those using IE6 expect it. As developers, it is our responsibility to make sure the content is served faithfully to the widest possible audience, as attractively as possible. However, with an array of over a hundred browsers to serve to (let alone browser versions), the web developer needs tools to help. Modernizr is moderately useful for that.

    I say moderately, because it should indeed be used with caution. I’ve not yet found many uses for it, although there are certainly some. `var toggleOrHover = Modernizr.touch ? ‘toggle’ : ‘hover’;` allows you to bind events to elements depending on the presence of a touch screen with `$(elem)[toggleOrHover](function() {do stuff});`. Admittedly, it would be better to test whether there was a mouse-device in use, but I don’t really care that there’s a few touch-screen devices that also have mice. And of course, my example is in JS. I’ve not yet found a rock solid use for Modernizr classes (besides .no-js, which isn’t Modernizr).

    It’s probably also worth noting that Paul Irish doesn’t use .no-classes on his personal site, the Modernizr sites’ use of it’s own classes are minimal (only 2 appearances of .no- and mainly negative use of it’s other classes such as .borderradius), and even the HTML5 Boilerplate site only uses Modernizr classes rarely.

    Further, with tools like pie.htc (css3pie.com), classes like .no-gradients become inaccurate, requiring CSS to be re-written.

    Having said all that, I’m still going to use Modernizr. I think it’s a pretty cool bit of kit, and I’m determined to find uses for it. It’s only through trying these things (and having discussions like this) that the web advances…

  21. Gravatar Image Jeff Craig May 17, 2011 @ 8:19 pm

    Vary-By: User-Agent is effectively worthless as a cache-control mechanism. Any number of plugins, extensions, or other things done in the Browser will modify the User-Agent header.

    For instance, on Windows, Microsoft.NET installs a browser extension into Firefox to support ‘ClickOne’ deployment of WPF applications from the web, as part of this, the browser User-Agent will include, by default, every single version of .NET installed on the client machine, optionally only the newest version.

  22. Gravatar Image Mike Davies May 17, 2011 @ 9:44 pm

    @MarcelShields that is an improvement, reducing the number of states to 3. I’m still not grokking why there’s a need to draw a style distinction between “support multiple backgrounds” and “support multiple backgrounds with javascript enabled”.

    @thugsb wow, great comment, and +1 for your pragmatic approach.

  23. Gravatar Image Robert Visser May 18, 2011 @ 12:15 am

    Some great threads in the comments.

    Paul Irish, @paul_irish , brought up some points specific to using classes. There are two great posts for further info: one by Faruk Ate? , @KuraFire , Taking Advantage of HTML5 and CSS3 with Modernizr http://goo.gl/70U8G and the other by Inayaili de León, @yaili , How to use Modernizr http://goo.gl/KL1De .

  24. Gravatar Image Faruk Ates May 18, 2011 @ 12:19 am

    I’ll recap my responses from Twitter here, to keep the discussion straightforward:

    1: discouraging the use of a product (that *the community at large* has voted as the best open-source tool of 2010, even) because it has outdated marketing is unhelpful. Yes, our examples on the site are poor examples; they are from the first days of Modernizr, when I still had to explain to people what they could do with it at all. Fortunately, a new site is around the corner with much better documentation and examples.

    2: I take it that your defiance against any reliance on JavaScript whatsoever also means you’ll not be building any sites using clean markup with HTML5 elements, then? Because you’ll have to rely on JavaScript to make that kind of elegance work in IE for many years to come. Moreover, increasing amounts of CSS3 go hand-in-hand with JavaScript for a useful implementation. We can only do so much with Transitions and Animations in just the .css files alone.

    3: Modernizr really *is* fundamentally about decoupling. I just don’t believe in the kind of hyper-aggressive defiance against any kind of JavaScript-dependency at all. It’s fine if you want to do that: you can go a long way with it, sure. But you won’t be doing anything awe-inspiring with HTML5 without entering into JavaScript dependencies, and as said above, even awesome CSS3 stuff is starting to rely on JavaScript in a supporting role. And for the people who want to do stuff like that, Modernizr can be of *tremendous* help in managing the complexities and overcoming the challenges of also having to support browsers that don’t yet support everything.

    In essence, if you want the entire design of your site to work without JS, all the better. Some of us are fine with providing a basic-looking site that is still completely accessible and functional when JavaScript is disabled (or failed or whatever), and enhance not just functionality but also design by use of JS. If that’s an affront to you, well, that’s your right, but that doesn’t make the tool not valuable for those who do want to do that.

    And personally, I think you’re clinging to an era that’s behind us, at the cost of moving the world faster into the era ahead of us. Again, that’s your right, but I’ll respectfully disagree that that’s a good thing.

  25. Gravatar Image Faruk Ates May 18, 2011 @ 2:24 am

    Addendum to my (possibly still unmoderated) comment above:

    In October 2010 there were >3.6X as many IE6 users than users with JavaScript disabled[1][2]. I stopped treating IE6 as a first-class or even second-class browser long before then, and have yet to see a compelling reason why I should treat no-JavaScript users differently.

    Now, I’m not saying “screw them” the same way I say that to IE6 users. Accessibility is always critical to me. But in my opinion, if you are okay with serving IE6 users the Universal IE6 stylesheet, you should be okay with doing the same for no-JS users. Security-conscious people with modern browsers that disable JS are an edge case I have no interest in slowing down progress of the entire Web for.

    [1] http://developer.yahoo.com/blogs/ydn/posts/2010/10/how-many-users-have-javascript-disabled/
    [2] http://gs.statcounter.com/#browser_version-ww-monthly-201004-201104

  26. Gravatar Image Steve Webster May 18, 2011 @ 10:36 am

    @faruk:

    1. I believe Tim was discouraging use of the product because he disagrees with the principles on which it is built, not because of its outdated marketing. If Paul Irish’s comment that the new documentation will advocate using the no-{feature} classes to provide a fallback experience are true, and you think that will help address these issues, I’m not sure you fully understand the scope of the problem.

    2. For me, JS shims for HTML5 element styling falls into exactly the same bracket. The HTML5 markup changes that fail gracefully (e.g. the new input types) are fine, but I’m personally advocating using new HTML5 elements for semantic purposes only until they are universally supported.

    3. So Modernizr is decoupling, but with dependencies? It’s really disingenuous to talk about HTML5 and JavaScript dependency since fully half of HTML5 *is* the new JavaScript APIs. Moreover, if awesome CSS3 stuff is relying on javaScript then it’s not awesome CSS3 stuff, it it? It’s true that modern web development involved a blend of HTML, CSS and JavaScript, but that doesn’t mean that making one depend on the other is a good idea.

    To summarise, this article outlines the negative aspects of relying on Modernizr-like feature sniffing to provide styling hooks. In the main, outside of this article Modernizr (and its underlying techniques) have been advocated without the necessary caveats that developers should be made aware of. I’d suggest listing Modernizr’s tradeoffs right on the homepage and letting developers make up their minds about whether they’re happy with those.

    Universally advocating a tool that you know has downsides and not making users aware of those downsides is irresponsible, no matter how many people have voted for it in an online poll.

  27. Gravatar Image Tim May 18, 2011 @ 11:34 am

    Firstly, thanks everyone for commenting. It’s good to see such a healthy discussion!

    @Faruk: 1. If your marketing is out of date, that’s your problem. Don’t tell me I’m being “unhelpful” just because you’ve been tardy in updating your documentation. Since this is the source of truth for implementation details, it’s important that you design your examples to reflect the way you expect the library to be used.

    That being said, I think my final point was clear enough:

    Modernizr may still be a worthy solution for JavaScript-only feature sniffing, if only it allowed the developer to disable the injection of classes on the html element.

    2. You’re correct; I will not be recommending a best practice that requires JavaScript to support an HTML element for exactly the same reason as outlined above. Whilst I’d love to start using the wonderful new HTML5 elements on larger corporate sites, I simply cannot until they are available in the oldest browser we support as part of our Browser Support Policy. This is really no different to the fact that we’ve only just started to use the child selector in CSS because we’ve dropped support for IE6.

    I have no issue with transitions and animations being invoked in JavaScript because this is an easily degraded progressive enhancement; see my jQuery widgets as an example. What’s more, CSS3 features and CSS2 features can sit side by side in a stylesheet file without ever having to rely on JavaScript.

    3. I’m afraid I agree entirely with Steve on this point; we all use a blend of HTML, CSS, and JavaScript everyday, but we don’t have to make them dependent on one another. In fact, at the moment, this is one of the fundamental pains of my current job due to poor decisions made by previous development teams, and is something that we are fixing iteration by iteration.

    4. It bothers me that you’re reposting Nicholas Zakas’s YDN link, which I already referred to (followed by Mike Davies’s well crafted and intelligent response) in the main article under the large heading “Dependency on JavaScript is bad”. I can only assume you didn’t get that far down the article before you started responding on Twitter.

    The numbers of users with JavaScript disabled are, indeed, low, but I’m more concerned with the time taken for JavaScript to load into a page as an asset, and whether that asset fails or not. Those users shouldn’t be punished or prevented from seeing content or, indeed, a CSS gradient that could work perfectly acceptably without JavaScript.

    As a final note, I’ll say that I’m not clinging to “an era that is behind us”, I just wholeheartedly believe in making as much content and as many website features available to the widest possible number of people, regardless of the hardware and software they choose to use to view it.

  28. Gravatar Image Jeremy Keith May 18, 2011 @ 12:38 pm

    This is orthogonal to the discussion at hand, but I just wanted to interject:

    Some people keep referring to new HTML5 elements (e.g. section, article, nav, etc.) as being JavaScript-dependant because you need to use JavaScript in order to use them in IE less than 9.

    This is untrue.

    You need JavaScript if you want to *style* them in IE less than 9.

    That’s a big difference. You should be choosing elements based on their semantics, not as styling hooks. It’s perfectly possible to start using the new HTML5 structural elements while continuing to use, for example, divs with classes which can then be safely targeted in your CSS.

    Steve Webster, you wrote: “I’m personally advocating using new HTML5 elements for semantic purposes only until they are universally supported,” but I believe what you meant to say was “I’m personally advocating using new HTML5 elements for *styling* purposes only until they are universally supported.”

  29. Gravatar Image Steve Webster May 18, 2011 @ 4:04 pm

    Jeremy Keith: What I said, which may not have been clear due to the awkward way the sentence was constructed, is that it’s okay to use the HTML5 elements for semantic purposes, but we can’t use them as styling hooks until they’re universally supported.

  30. Gravatar Image Jeremy Keith May 18, 2011 @ 5:45 pm

    Steve Webster: quite right. I misread what you wrote (because I am an idiot). My apologies.

  31. Gravatar Image Travis May 18, 2011 @ 5:52 pm

    I’m curious about the processing overhead- If I’m running a high-traffic site, won’t I be saving myself some significant overhead by using the client machine to process the detection (via javascript) as opposed to using Apache or IIS?

  32. Gravatar Image IvanDM May 18, 2011 @ 6:05 pm

    I would have bet that such “breaking” article would have summoned la crem de la crem of the web dev world ;)

    Personally I agree with comments that associate “assume JS is there” with “progress”. This is retrocompatibility, and while I believe it is a good thing to have, it brings costs with it. And if you want to progress, at certain point, you need to “let go of it”, if the price is more than the gain.

  33. Gravatar Image Paul Irish May 18, 2011 @ 8:59 pm

    Jeremy, in addition to not being able to style those elements, they cannot have children elements. The elements are collapsed.

    So your intended DOM is completely different from how you designed it in markup. Which means all your DOM traversal script dies because it’s got very different DOMs in IE.

    So it’s a lot more than inability to style.

  34. Gravatar Image Russell Bishop May 19, 2011 @ 10:59 am

    Referring to Mike Davies, I think it’s important that we remember here that you would write your CSS like this;

    p { /* normal css */ }
    .coolbrowserfeature p { /* enhanced css */ }

    You would not write;

    .nocoolbrowserfeature p {  }
    .coolbrowserfeature p {  }
  35. Gravatar Image Mike Davies May 19, 2011 @ 11:20 am

    Faruk Ates notes: “discouraging the use of a product (that *the community at large* has voted as the best open-source tool of 2010, even) because it has outdated marketing is unhelpful”

    There’s a cognitive dissonance between a “best of 2010″ and “outdated marketing”. The points (and fundamental concepts) raised above are not new to web developers, so I find it difficult to believe that the prime code example of Modernizr use can be outdated at this point. We haven’t had a massive shift since that example was written and today. It was a bad example at the start, and it’s still a bad example now.

    Faruk Ates continues: “3: Modernizr really *is* fundamentally about decoupling”

    Decouple:
    1. Separate, disengage, or dissociate (something) from something else.
    2. Make the interaction between (electrical components) so weak that there is little transfer of energy between them, esp. to remove unwanted AC distortion or oscillations in circuits with a common power supply.

    What Modernizr does between JavaScript and CSS isn’t decoupling, it is the opposite.

    Both Modernizr CSS approaches (half-empty and half-full) suggested by Faruk Ates and Paul Irish are flawed, neither of them clearly outline the drawbacks. That doesn’t inspire confidence, because it suggests to me that neither person understands the implications and repercussions of this approach (or perhaps worse, don’t care about the pitfalls and problems).

    Both approaches ignore CSS’ strength – it’s graceful fallback when properties are not supported. It’s worked from day one (in the previous century), and still works today. Browsers ignore CSS properties they don’t understand.

    Faruk Ate? suggests: “But you won’t be doing anything awe-inspiring with HTML5 without entering into JavaScript dependencies, and as said above, even awesome CSS3 stuff is starting to rely on JavaScript in a supporting role. ”

    That sounds like marketing speak for Flash splash pages, _that’s_ clinging to an era that (I dearly hope) is behind us.

  36. Gravatar Image Matthew Pennell May 21, 2011 @ 9:40 am

    Regarding server-side browser detection, I wrote a little about that technique last week: Browser sniffing with .htaccess.

    I don’t see it as a replacement for the kind of thing Modernizr is intended; it’s more a handy shortcut for those occasions when you notice a weird layout bug in an old version of a particular browser and don’t have a convenient CSS parsing bug with which to hack a solution. The caching caveat is a good one, though.

  37. Gravatar Image Tim May 21, 2011 @ 3:12 pm

    @Matthew: Nice article; I’ve added it as a reference within the text of the article.

  38. Gravatar Image Nicolas Gallagher May 26, 2011 @ 10:54 am

    @Matthew @Tim: Kroc Camen also wrote about that a while ago: Targeting Browsers With CSS Using mod_rewrite

  39. Gravatar Image Anders June 3, 2011 @ 10:33 am

    I agree with Paul when he says that Modernizr is best used with the no-classes – I don’t see why we would want to punish the browsers with CSS3 support when JS is disabled. That’s sort of anti-progressive enhancement to me.

  40. Gravatar Image zardoz June 23, 2011 @ 10:27 am

    This is a a good article and had some very valid points, I will re-read it. However. It’s very CSS centric and Modernizr isn’t just about supporting CSS features. Many here have said that relying on JS is ‘Bad idea’. Hmmm. There is a problem there though isn’t there.

    What about HTML5 features that actually rely on Javascript? Like for example ApplicationCahe, or globalStorage, Web Workers??

    Javascript is an essential part of the web now and definitely essential to a great swathe of HTML5 features.

    I would not be surprised to see versions of future browsers were you can totally disable JS. So yes relying totally on something can be flawed, but trying to produce JS free equivalents is sometimes impossible and in my opinion working against progress.

    My 5 cents

  41. Gravatar Image zardoz June 23, 2011 @ 10:28 am

    should have read “I would not be surprised to see versions of future browsers were you can’t totally disable JS”

  42. Gravatar Image preusstang August 1, 2011 @ 8:48 pm

    wow. you just blew my mind

  43. Gravatar Image Eugenio Pacelii November 25, 2011 @ 12:49 pm

    What a load of rubbish. This article is simply hair splitting at best.

  44. Gravatar Image Grigory November 25, 2011 @ 12:49 pm

    1) THERE IS NO SUCH A THING AS “CLASSITIS”!
    2) You can use Modernizr from JS only. Nobody forces you into using CSS classes. You don’t need to disable CSS classes to use JS variables.
    3) You didn’t mention custom builds. That long html tag example is wrong because the full version is only for development.

Leave a comment





Categories

Syndication

Technorati

© 2012 Tim Huegdon, All Rights Reserved / Website design and development by Nefarious Designs

Powered by Wordpress / Log in

This website was made entirely from sticky-back plastic and glue.