Progressive enhancement and obsolescence control with Modernizr - Expanding the design with code - The Responsive Web (2015)

The Responsive Web (2015)

Part 3. Expanding the design with code

Chapter 8. Progressive enhancement and obsolescence control with Modernizr

This chapter covers

· Introducing responsive experiences

· Introducing progressive enhancement

· Diving deeper with Modernizr

· Using Modernizr to progressively enhance an element

So far we’ve talked about developing a website by starting with prototypes, then moving on to style tiles and content, and finally building the site. The final part of building a responsive site is to use a technique called progressive enhancement, enhancing a simple site into one that’s more technologically advanced.

The introduction of touch interfaces and small screen devices has been interesting, and they can be fun to design and develop for, but that’s merely the tip of the responsive iceberg. Although many users have access to the most modern mobile phones and tablets, building a responsive website also means supporting older, less capable hardware and making content accessible to sight-impaired users.

To achieve this, you first need a workflow that enables you to tend to the needs of all your users. We’ve talked about designing and developing for mobile first and building up from there, but let’s take that further. What if instead of throwing HTML, JavaScript, and CSS at a browser until you get what you want, you build from a basic foundational site and work your way up? Let’s see what happens.

8.1. Technical obsolescence

Over time, every website becomes obsolete, and this is especially true in responsive web design. Several techniques have been introduced to deal with this problem, and we’ll cover two of them in this chapter: progressive enhancement and graceful degradation.

We’ll discuss some of the major points in these two methodologies in order to understand some of the best practices for resolving issues around obsolescence and cross-browser compatibility. Once we’ve established these two methodologies, we’ll discuss how to use Modernizr to achieve a cross-browser-compatible website.

8.1.1. Progressive enhancement

Progressive enhancement is a technique for enhancing a simple site into something that’s more technologically advanced, as diagrammed in figure 8.1. This process is a counterpoint to mobile-first design. Mobile-first design deals directly with form, whereas progressive enhancement deals with function. In a progressive enhancement methodology, you start small and gradually make your site more complex by, for example, adding animations or HTML5 and CSS3 features.

Figure 8.1. This is a simple diagram of the progressive enhancement workflow. You begin with a simple, accessible site and enhance it into a more complex website with modern design features.

When dealing with the function of a site, you first need a model for figuring out how to enhance the site. So far we’ve discussed using media queries for adjusting the site’s layout, but let’s see how we can take this mobile-first concept a step further using progressive enhancement to create a responsive experience.

Sensors, systems, and actuators

As Mark Boulton described in a blog post titled “A Responsive Experience” (www.markboulton.co.uk/journal/a-responsive-experience), responsive experiences are achieved by using three conceptual components together—sensors, systems, and actuators:

· Sensors are components that sense the environment. In the context of responsive web design, the sensor is the browser, which provides valuable information about the user and their current capabilities.

· Systems are the responses to the information provided by the sensor. In previous chapters we’ve discussed media queries, which are a type of system. We could also use JavaScript to build systems that handle events and provide information such as the user’s time or geographic location.

· Actuators are the responses to the systems’ instructions. This could be CSS applied within a media query or a JavaScript plugin that applies page improvements based on the user’s capabilities. In previous chapters, our actuators have been the enhancements or adjustments we’ve made for larger viewports.

So far we’ve used the browser as a sensor and based our systems on one piece of feedback (viewport width), adjusting accordingly, but there’s more to building responsive websites than just responding to width. Width is just the first and simplest way to understand the differences between mobile, tablet, and desktop site versions.

In addition to using media queries to sense the viewport dimensions of a site, there’s also a base-level sensor you can use, and that’s the lack of JavaScript. The overwhelming majority of web traffic uses JavaScript to render web pages, but with that being said, checking whether or not JavaScript is enabled should be the first sensor you use when progressively enhancing a site. Every site you build should be able to be navigated, to some degree, without JavaScript enabled.

Enhancing for browser versions

Historically, in front-end development, developers would adjust a site to fit the constraints of the layout engine being used by a particular browser. There were only three browsers in 2003: Netscape, Internet Explorer, and Opera. By 2005, Firefox, Safari, and the first mobile browser, Opera Mini, were released; Chrome was released in 2008.

Currently there are five major browsers, each with its own mobile version. Across that array of browsers, there are also older versions that users haven’t upgraded. In the same way that creating multiple layouts for multiple screen sizes eventually becomes a zero sum game, so does building multiple front ends for multiple browsers and browser versions.

We’ve talked a lot about how to build a site for new, cutting-edge mobile browsers. We’re using responsive web design to accommodate these browsers, but it’s important not to do so at the expense of older browsers.

Progressive enhancement is one strategy for coping with browsers that don’t support up-to-date features. As we’ve discussed in this book, there’s always a temptation to build for the most up-to-date features available, but in a responsive web, design is contextual. The design must be appropriate for the frame that it’s being viewed through. Responsive web design has become popular because it resolves the most obvious changing context—the available screen real estate—but the context of a browser runs much deeper than its viewport size.

In the previous chapter we discussed using SVG images in a site’s design. SVG is a great solution for high-resolution displays, but what about support in older browsers? It’s not supported in IE8 or lower, so you’d have to build in a fallback if you supported that browser. You could identify the browser and serve alternative styles to that browser, but then you’d have to serve those same alternative styles for every browser that doesn’t support SVG. Therefore, according to progressive enhancement, you should start the build process with a graphic that’s supported by the lowest common denominator, like a PNG. This approach will delay the addition of more modern features for modern browsers in favor of basic functions that are supported by older browsers and devices.

Designer insight: progressive enhancement in design

Progressive enhancement is implemented in development, but it’s important to consider ways to support these features during the design process. When progressive enhancement is possible during the design process, it might require a module on a site to be completely replaced with another module that accomplishes the same task. Be ready to provide design starting with a simple layout and progressing into rich and beautiful interfaces.

Feature detection via user agents

Traditionally, feature detection has been accomplished by detecting the browser’s user agent. This is done through JavaScript, using the navigator object. The navigator object dates back to the Netscape days and used to be a developer’s best tool in providing cross-browser compatibility. In the context of sensors and detecting user information in order to resolve a cross-browser issue, user agents were at one time the most meaningful and widely used sensor.

If you have Chrome, Firefox, or Safari available, try opening your browser’s web inspector by right-clicking on a page and selecting Inspect Element. After you’ve opened the web inspector, click on Console, and after the caret, type navigator.userAgent and press Enter. This will return your current browser’s user-agent, which is a string of text used to identify the browser in use. For example, I’m using Google Chrome, which returns the following:

"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.35 (KHTML,

like Gecko) Chrome/27.0.1443.2 Safari/537.35"

In a lot of ways, the navigator object is one of the best sensors we have available to inform our system about what the user is capable of, but it’s not very future-friendly. It bases your site’s actuators on assumptions about what the browser does and doesn’t support. It’s also unreliable because it can be configured by the user in order to access sites that the browser might not be able to support.

Developer insight: the navigator object

Although navigator can’t reliably be used to make assumptions about the user’s feature support, it can be an incredibly handy sensor. In addition to detecting the user agent, it can be used to detect geolocation, whether cookies are enabled, and even where the user is in the world. If your console is still open, try inputting this:

navigator.geolocation.getCurrentPosition(function(position) {

console.log(position.coords.latitude, position.coords.longitude);

});

The browser should prompt for permission to use your location. If you allow it, it should return two values indicating latitude and longitude. Copy the values into a Google search, and you can see in Google Maps the location your user agent is broadcasting. This can be used as an additional sensor, which you can use to create a richer responsive experience.

For example, on my personal blog I might want to detect whether a visitor is from New York, and if so say something like, “Hey, you’re reading my blog, you must be a pretty cool person. I see you’re near me, could I take you out for a beer and chat about how to make my site better serve you?” I could potentially use the navigator’s geolocation feature to send an alert to such a user, encouraging them to contact me directly.

Detecting user agents is the traditional method of applying progressive enhancement. Developers would know that a certain feature was unavailable to a particular browser and build to that limited specification. An enhancement could be added for a specific browser using its user agent. This was a manageable workflow historically, but now it’s unrealistic. There are too many browsers to keep track of, and new operating systems and browser versions are being added daily. Fortunately, there are other methods of resolving cross-browser limitations.

Limitations of progressive enhancement

In progressive enhancement, you might find yourself having to initially support a minimum system that represents a small percentage of your user base. Say, for instance, that you have a minimum supported browser of IE8—that browser might only represent 5% of your site’s traffic, so initial development cycles are spent building support for a product that represents a small subset of actual site traffic.

Meanwhile, if you also decide to work in a mobile-first capacity, you could end up building a site for a mobile device with the features supported in IE8, all to accommodate the limitations of 5% of your site’s traffic.

There’s another way of dealing with technical obsolescence, through a process known as graceful degradation. This takes the opposite approach to progressive enhancement and involves building a site, and building in a failsafe for each potential failure.

8.1.2. Graceful degradation

With graceful degradation, the development of a site includes fallbacks for site failures. This means you might build a site that uses HTML5 video, and if the HTML5 video fails, you use a Flash plug-in to add video support to the browser and play the video.

Unlike progressive enhancement, graceful degradation starts at the most advanced point and falls back to alternatives if browser support fails. This can be an exhausting part of developing a web site. In the quality-control phase of a project, a lot of cross-browser-related bugs find their way to the surface, and developers are forced to react quickly to implement a fallback to fix them.

Providing fallbacks for every module in a page isn’t likely to be necessary, or even possible. Fortunately, HTML is backwards-compatible, meaning that HTML5 can work with older browsers using something called a polyfill. As Google developer evangelist Paul Irish explains it, a polyfill is a piece of code “that mimics a future API, providing fallback functionality to older browsers” (http://www.paulirish.com/i/7570.png).

HTML5Shiv is an example of a polyfill. It’s a piece of code (JavaScript) that mimics a new API (tags introduced in the HTML5 specification, like <header> or <section>), in order to provide functionality to browsers that don’t support the HTML5 specification.

Even with a polyfill in place, some things simply will not work in older browsers. A polyfill is not a major bullet that’s going to force browsers to work; it’s a piece of code that adds a degree of support for newer features to older browsers.

So when should you use a polyfill? They can be expensive in terms of bandwidth, and loading a lot of polyfills for the few browsers that need them is pretty excessive. You wouldn’t want to unnecessarily serve a fallback asset to all mobile browsers simply to give support to some older browsers.

Designer insight: cross-browser perfection

Does every site need to look identical in every browser? I don’t think so. If you compare an application on iPhone, Android, Windows, and OS X, does it have to look the same? Of course not; they’re completely different platforms, and some common interaction patterns are not going to work as easily across operating systems.

In the youth of the web, developers were expected to make things look uniform in cross-browser environments, but it has become more difficult to maintain uniformity as the internet has diversified. If you want to use WebGL on a project, you can kiss your uniformity goodbye completely. Embracing the fluidity of the web is the whole point of the responsive movement.

If graceful degradation forces you to load too many assets, and progressive enhancement limits your ability to take advantage of new technologies, is there a solution somewhere in the middle? Wouldn’t it be easier if you could write one style that would be used against every browser that didn’t support SVG? That way you wouldn’t have to keep up with every browser’s feature set or be surprised when a user reports a bug about an older version of a browser you didn’t think anyone used anymore. You could just set the fallback once and forget about it. This is where Modernizr comes in handy.

What if, instead of supporting browsers, we supported features? Then we could create fallbacks for particular features, and browsers that don’t support that feature would universally be served the fallback. This is exactly what Modernizr was created for.

8.2. What is Modernizr?

Modernizr is a JavaScript library used to detect features in the browser. It’s loaded in the head of your page and runs during page load. Adding it to your site is as simple as adding any other JavaScript library, such as jQuery, but once added, Modernizer gives you an incredible amount of control in rendering your page and ensuring that every user is served a quality experience.

When the library is loaded, Modernizr runs a series of checks against the user’s browser to determine what features the browser supports, and it creates a JavaScript object that you can test against. Modernizr doesn’t create support for these features; it simply gives you a way to provide fallback support for modern features.

Modernizr also applies a set of classes to the html tag, giving you the ability to modify the page’s CSS using the generated CSS classes. With these CSS classes, you can use CSS systems to build actuators that will adjust your pages by providing the progressive enhancements available for a page.

Unlike the user agent, Modernizr detects features directly by running a series of JavaScript tests that return Boolean (true or false) values. This dictates the classes that are set on the html tag, and it gives you the ability to use JavaScript to check whether a feature is available. This is done by Modernizr out of the box.

What makes Modernizr unique? Primarily, Modernizr stands alone in that it does something no other library does. HTML5Shiv allows older browsers to recognize and apply style to HTML5 elements, but that’s it—HTML5Shiv simply makes HTML5 objects accessible to CSS and JavaScript. Modernizr also does this, but it has the added bonus of feature detection.

HTML5Shiv, in conjunction with browser sniffing, can provide adequate graceful degradation. But it limits the support for a site to specifically identified supported browsers. Any good quality assurance practice should account for a specified amount of browser support, but Modernizr reduces the risk in specifically required HTML5 features.

HTML5Shiv will validate an HTML5 tag like <video>, but what it doesn’t do is make an HTML5 video play in an older browser. Although the tag itself can be styled and validated, the source video still won’t play in an older browser. Modernizr allows you to not only make this <video>tag valid, but also to offer alternative functionality in the event that the browser doesn’t support the feature. In the case of video, you can use Modernizr to fall back to a Flash video player if HTML5 video isn’t supported.

There are some cases where Modernizr might not be the right fit. In some cases, you might find Modernizr to be overkill. For instance, if you have a simple site, it might be wise to use the smaller HTML5Shiv to add HTML5 tag support, and then provide a browser-specific CSS file for older versions of Internet Explorer.

Modernizr also blocks page rendering because it needs to append test classes to the HTML classes prior to rendering the visible page. Because it blocks page rendering until the page loads, there can be interference with other JavaScript events, specifically when using libraries like Backbone. These interferences are rare, but they’re worth being aware of. In most cases, blocking page rendering will be unnoticeable by the user, but it’s a trade-off with Modernizr that’s worth being aware of.

8.2.1. Installing Modernizr

Installing Modernizr is as simple as linking to the JavaScript library in the head of your page. The only complicated part is creating the version that you need. Modernizr is available for download through its website (http://modernizr.com/) in two versions: the development version and the production version.

As mentioned, Modernizr’s relationship to page rendering is essential to its utility. This is why, unlike most scripts, Modernizr should be loaded in the head tag. It’s common practice to place script tags at the end of the page body, but Modernizr recommends placing it in the head because the HTML5Shiv that’s included must execute before the body, and if you use CSS classes in Modernizr, there’s a chance of there being a flash of unstyled content.

The development version is a full 42 KB uncompressed file. This version is great if you’re well versed in JavaScript and want to make some tweaks to the tests it performs. Because it’s uncompressed, it’s easy to read and augment, but it’s best left to developers with a firm understanding of JavaScript.

If you’re not completely adept at JavaScript, or you’d like to quickly build a customized version of Modernizr, you want the production version of the library. The production version’s building tool on the site gives you the ability to create a version with only the tests you require.

This comes in handy when you know you only need a certain set of tests. For instance, your site might not take advantage of CSS box shadows, but it might need to support CSS gradients. Using the build tool, you can include the tests you need and exclude the ones you don’t, keeping the source code trim and your users’ total load time down.

For our example, I’ll work with the development version. I find that when I’m building a site, it’s best to work with the full version, and then once I know what features I’ll use in the site, I trim the version down.

Installing Modernizr is as simple as linking to the source JavaScript file:

<script src="/js/modernizr.js" type="text/javascript"></script>

After linking, you can add a class of "no-js" to the html tag on the page, like this:

<html class="no-js">

You’re ready to go. Note that if JavaScript is supported and enabled, the no-js class is removed by Modernizr and replaced with the test classes, a screenshot of which can be seen in figure 8.2. This way, you can add CSS for pages with JavaScript disabled.

Figure 8.2. The rendered html tag on a page that has the Modernizr CSS classes applied

In total, Modernizr comes with over 40 built-in tests for HTML5, CSS3, and other features. Table 8.1 offers a short rundown of the key tests, taken directly from the Modernizr documentation.

Table 8.1. Built-in tests in Modernizr

Test type

Feature

Modernizr JS object property/CSS classname

CSS tests

@font-face

fontface

background-size

backgroundsize

border-image

borderimage

border-radius

borderradius

box-shadow

boxshadow

Flexible Box Model

flexbox

hsla()

hsla

Multiple backgrounds

multiplebgs

opacity

opacity

rgba()

rgba

text-shadow

textshadow

CSS columns

csscolumns

Generated content

generatedcontent

CSS gradients

cssgradients

CSS reflections

cssreflections

CSS 2D transforms

csstransforms

CSS 3D transforms

csstransforms3d

CSS transitions

csstransitions

HTML tests

applicationCache

applicationcache

Canvas

canvas

Canvas text

canvastext

Drag and drop

draganddrop

hashchange event

hashchange

History management

history

HTML5 audio

audio

HTML5 video

video

IndexedDB

indexeddb

localStorage

localstorage

sessionStorage

sessionstorage

Web sockets

websockets

Web SQL database

websqldatabase

Web workers

webworkers

As you can see, Modernizr covers a lot of ground. We’ll go over the basics so you know how to implement feature detection for CSS features and how to access the JavaScript object property for a test.

8.2.2. Using Modernizr for cross-browser CSS

With Modernizr installed, you have everything in place to start making some progressive enhancements. We’ll start with a raw sample site:

<!doctype html>

<html class="no-js" lang="en">

<head>

<meta charset="utf-8">

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js"></script>

</head>

<body>

</body>

</html>

In the last chapter we used SVG graphics, so let’s use a small test to detect whether or not a browser is capable of supporting SVG. For the sake of simplicity, we’ll just add two span tags to the page to detect support:

If you test this in a browser that supports SVG, you’ll see the message “Huzzah! You have SVG support.” If you have a browser that doesn’t support SVG, you’ll see the message saying “BOO! You don’t have SVG support.” (You can find this example in the chapter’s source code under the 8.1 directory.)

This example is rudimentary, but it displays the core idea of using Modernizr to fix cross-browser issues. Modernizr adds the classes to the html tag, offering a way to override styles based on Modernizr’s feature detection. If you were implementing this same fix using the old user-agent method, you’d need a stylesheet for each browser that didn’t support SVG, and you’d need to change the CSS for each one (for anyone interested, the only major browsers lacking SVG support are Internet Explorer 8 and under).

By adding the svg/no-svg class to the HTML on the page, your CSS now has a selector that can be used to override existing CSS rules. Because it’s on the parent-most tag, it can be used to override other classes on the page. In this example, both span tags are given display:none, and if there’s no SVG support, the display:inline declaration on the span tag with a class of no overrides the display:hidden, thanks to the no-svg rule on the html tag.

Let’s try a more useful example of the same idea. You might want to have an SVG background image on the page that falls back to a PNG if the browser doesn’t support SVG. By default, you’ll use the PNG image. This way the SVG isn’t served unless it’s needed and becomes a progressive enhancement. (This example is available in the 8.2 directory.)

Now you have an awesome SVG skull that will look crisp for users with high-resolution displays, and will still look good for users with older browsers. Modernizr provides cross-browser capability without you having to remember or maintain a list of which browsers support SVG.

This approach is excellent for supporting features with CSS, but what about testing a user’s capabilities and offering deeper support for progressive enhancements? For that, you need to take advantage of some of Modernizr’s other capabilities.

8.3. JavaScript feature detection with Modernizr

A CSS hook that allows you to alter the design of a page based on which features a browser supports is a pretty handy feature, and it justifies the use of Modernizr in almost every project I work on. Ultimately, though, this leads to a bit of site bloat as you add progressive enhancements. In many cases, site functionality and interaction might also need to be progressively enhanced, and JavaScript is the best way to do that.

As I mentioned earlier, in addition to applying a series of classes to the html tag on the page, Modernizer creates a JavaScript object with Boolean values for each of the tests it runs. To check the values of the JavaScript object, it requires some base level of JavaScript ability, but it’s deeply rewarding and can offer a huge degree of control over what your page loads.

If you have the example page open (directory 8.2 in this chapter’s source code), open your browser’s console and type Modernizr. This will return the full object in your browser with all of the tests run and each of their corresponding true or false values.

You can check these Boolean values easily by using a simple JavaScript if statement that evaluates the properties of the Modernizr JavaScript object with dot notation. In the same example page, try adding the following in the head tag:

<script type="text/javascript">

if(Modernizr.opacity) {

alert('opacity is supported');

}

</script>

Reload the page, and if your browser supports CSS opacity, you’ll get an alert saying “opacity is supported.” This is a common CSS property, so let’s try using a sensor that’s more relevant to our responsive goals—touch.

8.3.1. Detecting touch support

With responsive sites, it’s often not enough to detect the viewport size. You may find that sites will assume that a smaller viewport means you have touch-screen capabilities. This isn’t always the case. Often I’ll find myself browsing in a smaller window (say, to hide my personal browsing from my coworkers’ prying eyes).

If I come across a page that assumes I have a touch screen, some elements on the page might be hidden behind touch-based systems. Or I might be on a desktop computer that has a touch interface as its primary pointer. In this case, I might have trouble tapping small links on a page designed for mouse use. It would be nice to get feedback for these use cases, and Modernizr’s touch property gives you that.

Try replacing the previous opacity script example with the following:

<script type="text/javascript">

if(Modernizr.touch) {

alert('touch is supported');

}

</script>

If you refresh the page on a machine that doesn’t have touch support, nothing happens. Where did the alert go? The if statement returned false, so the alert contained within it wasn’t run because the device does not support touch.

If you write an else statement after the if, you can run a command in the event that the if statement fails:

if(Modernizr.touch) {

alert('touch is supported');

}else{

alert('touch is not supported');

}

This way, your bases are covered.

Obviously, simply alerting the user to whether touch events are available isn’t terribly useful. It’s great for testing, but useless outside of that. What would really be helpful is if we could load one JavaScript plugin or CSS file if the test passes, and another if the test fails. Luckily Modernizr has built in a resource loader called yepnope to support this ability, and it lets you load only the scripts your user needs.

8.3.2. Using Modernizr.load and yepnope

Another of the advantageous features of Modernizr is yepnope, its resource loader. Using Modernizr.load, you can load a set of files depending on whether or not a test passes. This is great, because it allows you to load only the assets you need for the user visiting the website.

Yepnope (http://yepnopejs.com/) was built by the Modernizr team and is incorporated into Modernizr by default, but it has since been released as a standalone plugin, so if you need to conditionally load resources in a standalone project without Modernizr, you can.

The syntax is completely straightforward and written in plain English. Here’s an example of a simple test:

Let’s break this down a little bit. Modernizr.load runs on page load and runs the tests specified. If a test passes, the assets after yep are loaded. If a test fails, the assets after nope are loaded. If you run this example on a computer without touch support, stylesheets/no-touch.css is loaded. If the browser does have touch support, stylesheets/touch.css is loaded.

You can specify multiple files by enclosing the assets in brackets, like this:

Modernizr.load({

test: Modernizr.touch,

yep: ['stylesheets/touch.css', 'touch.js'],

nope: ['stylesheets/no-touch.css', 'no-touch.js']

});

You can also run multiple sets of tests by passing in a JavaScript array with all your tests, like this:

<script type="text/javascript">

Modernizr.load([

{

test: Modernizr.touch,

yep: ['stylesheets/touch.css', 'touch.js'],

nope: ['stylesheets/no-touch.css', 'no-touch.js']

},

{

test: Modernizr.opacity,

yep: ['stylesheets/opacity.css', 'opacity.js'],

nope: ['stylesheets/no-opacity.css', 'no-opacity.js']

},

]);

</script>

This approach has a big downside in that it makes it impossible to concatenate all JavaScript files into a single JavaScript file, or all CSS files into a single CSS file. But the cost of taking this approach is offset to a large degree by the asynchronous nature of yepnope’s resource loading. It’s worth being aware of this downside, though, and using these features strategically.

As I’m sure you’re quickly noticing, you can customize a great deal of a user’s experience with Modernizr. It gives you the ability to fine-tune a website specifically for the user’s needs, but what if you need to do a specific test that isn’t included in the 40 or so tests included out of the box with Modernizr? Luckily, there’s an easy way to add a test to Modernizr with just a little bit of JavaScript.

8.3.3. Creating custom Modernizr tests

With the ability to add a test to Modernizr, you can diversify what the plug-in is capable of and expand on its built-in capabilities. The ability to add a JavaScript object, use a CSS class, and conditionally load assets can all be ported over to custom tests. The custom test becomes fully accessible within Modernizr and operates exactly like the built-in tests.

Custom tests are added using the addTest method as follows:

Modernizr.addTest(string, function);

Modernizr’s addTest function receives two parameters: the first one is a string with the name of the CSS class that you’ll use to identify your test, and the second is the callback function that you’ll use to test the device. The function needs to return a true or false value.

For example, if you wanted to test whether it was before 7 pm for a user, you could start with this:

Modernizr.addTest('night', function(){

return true;

});

In this case, the if statement, if(Modernizr.night), will always be true and the night class will always be on the head tag. You need a function to determine if it actually is after 7 pm.

To do that, you can grab the time from the user’s internal clock with some Java-Script and return the Boolean value based on that:

In this simple example we’ve added something incredibly helpful. This test would allow you to serve varied content based on the time of day.

8.4. Adding Modernizr to our site

Now that you understand what Modernizr is and a little bit of what it does, let’s add it to the blog site we’ve been working on. As mentioned, adding Modernizr is as simple as linking to the source in the head tag and adding the no-js class to the html tag. The source code with Modernizr installed is in the 8.5 directory.

If you look at line 2 in the source code, you’ll find this:

<html class="no-js">

But if you inspect the rendered HTML in the browser, you’ll see that the set of Modernizr classes has been added to the html tag. This means Modernizr is working! Now, you may recall that in the previous chapter we added SVG graphics to the page (on line 66 of index.html in the 8.6 directory). Let’s create a fallback for the SVG graphic using Modernizr.

We’ll start by adding a wrapper div with the class of star-svg around the object tag. This will give us something to target above the SVG itself. Additionally, we can add an img tag linking to a PNG file for older browsers (the output of which is seen in figure 8.3):

Figure 8.3. We now have two images, the SVG and the fallback PNG.

<div class="star-svg">

<object type="image/svg" width="400" height="400" style="float:right" data="images/star.svg">

</object>

<img src="images/star.png">

</div>

We need to add some CSS to hide and show the fallback image. On line 209 of style.css, you’ll see the following:

.svg .star-svg img{display:none;}

.no-svg .star-svg object{display:none;}

That produces the results seen in figure 8.4.

Figure 8.4. With CSS, we’ve hidden the second star.

In theory, this does a good job of providing a fallback for the SVG, but it has some faults. Notably, the SVG is still loaded in older browsers, and the PNG is also loaded in newer browsers.

We could circumvent some of this by using the default fallback SVG technique, in which we’d embed the fallback image within the object tag. This has the added benefit of not requiring Modernizr, and it would support graceful degradation. That would look something like this in practice:

<object type="image/svg+xml" data="images/star.svg">

<img src="images/star.png">

</object>

Although this will work just fine, it still requires the initial SVG to fail and then serves the PNG. What would be ideal is to only serve the file to the browsers that need it. We’re going to do this by using a simple Modernizr test to determine which file to load. In order to do this flexibly, we’re going to change a few things.

First we’ll change the star-svg class to an ID, so we can easily target it with Java-Script. We’ll also use an HTML5 custom data attribute to give us the path to the asset we want to load. This attribute, titled data-path, will be the path to the directory containing both the PNG and SVG images:

<div id="star-svg" data-path="images/star"></div>

Next we’ll add a conditional statement to append the extension to the filename. This conditional will use the modernizr.svg test, and if it passes, it’ll create either an image tag or an SVG object depending on browser support. The final version of this code can be found in the 8.7 directory:

8.5. Summary

In this chapter we discussed obsolescence control, focusing on the methodologies of progressive enhancement and graceful degradation. We discussed how they’re applied and outlined their differences. Hopefully, this gave you an understanding of the basics of using obsolescence control in responsive web design.

We also discussed Modernizr, which functions exceptionally well as a system with which to serve your user the required assets for their browser and create speedy and highly functional websites. Take some time and read up on Modernizr’s documentation at http://modernizr.com. I’ve found it to be an incredibly helpful resource in my personal workflow.

Modernizr is a great tool for controlling obsolescence in websites, but to dig deep into a site’s quirks, you need to learn how to test a site’s performance. In order to really get under the hood of your website, you need some tools that show you what’s going on behind the scenes. In the next chapter we’ll discuss some tools you can use to optimize site performance in a responsive world.

8.6. Discussion points

· What are some of the advantages and disadvantages of progressive enhancement? What about graceful degradation?

· How can you build controls for supporting older browsers into your site designs?

· Can you think of any creative ways to use Modernizr’s addTest method?