29 August 2011
Old browsers stubbornly refuse to go away, making it difficult to incorporate the latest CSS3 or HTML5 features into your websites. That's where Modernizr, an open-source JavaScript library, can help by detecting which features a browser supports. Modernizr doesn't attempt to add the missing features, but it allows you to adapt your page design by creating alternative style rules for older browsers. It also enables you to load custom scripts to emulate missing functionality.
Using Modernizr is straightforward, but it's not a magic wand. Your success in working with it depends greatly on your CSS and JavaScript skills. In this tutorial, you'll learn how to serve alternative styles to browsers that don't support multiple columns or drop shadows. You'll also learn how to get older browsers to validate forms that use the new HTML5 required attribute, as well as how to load scripts conditionally depending on a browser's capabilities.
Modernizr is a JavaScript library that detects which features a browser supports. It currently checks 18 CSS3 features and more than 40 HTML5-related ones by examining how the browser responds to a series of tests. This is much more reliable than the outdated practice of checking the browser's name (browser sniffing). The full set of tests takes only microseconds to perform. What's more, the Modernizr website maximizes efficiency by automating the creation of a customized script to test only those elements you're interested in.
When used to detect support for CSS3, Modernizr requires no knowledge of JavaScript. You simply attach the file to your web page, and it dynamically adds a set of classes to the <html> element depending on the browser's capabilities. The class names are standardized and self-explanatory. For example, the boxshadow class is added if the browser supports the box-shadow property; otherwise no-boxshadow is added instead. All you need to do is to create a style sheet that uses these classes to serve appropriate styles to the browser.
Modernizr makes it easy to implement JavaScript solutions known as polyfills that emulate features related to HTML5 and associated technologies, such as geolocation. However, you do need at least a basic understanding of JavaScript to use them. By the way, the term polyfill comes from Polyfilla, the British brand name of a paste for mending cracks (known as spackling paste in the USA). The idea is that a polyfill plugs a hole in the browser's capability. Sometimes, it performs the task seamlessly. But it's basically a repair job, so cannot be relied upon to produce exactly the same results.
In common with other JavaScript libraries, Modernizr is available in development and production versions. With most libraries, the only difference is that whitespace and comments have been removed from the production version to reduce the size of the download. Modernizr takes a different approach. The development version is what might be termed the "kitchen-sink" version—it contains almost everything. The production version contains only those elements that you choose, resulting in a considerably smaller download. In many cases, the production version can be as small as one-twentieth the size of the development version.
When experimenting with Modernizr, I recommend that you download the development version. Once you know how it works and what it's capable of, you can download a custom production version to deploy on your website.
The sample files for this tutorial contain version 2.0.6 of the development version of Modernizr, but I recommend that you replace it with the most up-to-date version from the Modernizr site.
Note: If you click the Download link in the main navigation menu by mistake, you'll be presented with a large number of checkboxes asking you to select the tools you want. This is for a customized production version. Click the link for the Development version at the top of the panel, or click the browser's Back button to return to the main page and select the Development button as shown in Figure 1.
As noted earlier, Modernizr doesn't attempt to add new features to older browsers, but it allows you to compensate for missing features in your styles. To demonstrate how this works, the sample files contain a page called css_support_begin.html. If you load the page into a modern browser, it should look like Figure 2.
The styles in the page use the CSS3 column-count and box-shadow properties to display the text in multiple columns and add a drop shadow to the image. Older browsers don't support either of these properties, so the same page looks like Figure 3 in Internet Explorer (IE) 7.
In IE 9, the same page displays the drop shadow on the image, but the text is laid out in the same way as Figure 3.
How far you go in trying to compensate for the missing features depends on the requirements of your design brief. Trying to get the page to look exactly the same in all browsers would involve a lot of work, but you can make some simple improvements, such as wrapping the text around the image, aligning the image with the left margin of the text, and adding a subtle border to the image's bottom and right edges to give it a more three-dimensional look.
Modernizr uses JavaScript to detect which features a browser supports, but rather than using JavaScript to load different style sheets dynamically, it uses the remarkably simple technique of adding classes to the page's <html> tag. It's then up to you as the designer to use the CSS cascade to serve the appropriate styles to target elements. For example, if the box-shadow property is supported, Modernizr adds the boxshadow class. If it's not supported, it adds the no-boxshadow class instead.
Since browsers ignore CSS properties that they don't recognize, you can safely use the box-shadow property in your basic style rules, but add a separate descendant selector for older browsers like this:
.no-boxshadow img {
/* styles for browsers that don't support box-shadow */
}
Only browsers that don't support box-shadow will have the no-boxshadow class, so no other browsers will apply this style rule.
Let's add Modernizr to the sample page and inspect the classes it adds to the <html> tag.
<!DOCTYPE HTML>
<html>
<html> tag like this:<!DOCTYPE HTML>
<html class="no-js">
Modernizr depends on JavaScript being enabled in the browser. When it is, this class is dynamically removed. However, in the rare cases when JavaScript is disabled, it remains in the HTML markup, allowing you to create special style rules for such visitors if necessary.
<style> block. The Modernizr library needs to be added to the <head> of the page after the styles have been loaded. Add a new line between the closing </style> and </head> tags and attach moderizr.js using a <script> tag. The simplest way is to type the code yourself, but you can also use the Script button in the Insert panel or select Insert > HTML > Script Objects > Script. The last three lines of the <head> should look like this:</style>
<script src="js/modernizr.js"></script>
</head>
Note: If you use the Insert panel or Insert menu, Dreamweaver adds type="text/javascript" to the opening <script> tag. This is no longer required in HTML5, but it does no harm to leave it in.
<html> tag is now populated with more than 40 class names indicating the capabilities of Dreamweaver's built-in version of the WebKit browser engine (see Figure 4).
Note: If your version of Dreamweaver doesn't have Live Code (or if you're using a different HTML editor), you can inspect the generated code using the developer tools in most modern browsers or Firebug in Firefox.
As Figure 4 shows, the no-js class has been replaced by js , indicating that JavaScript is enabled.
Table 1 lists the class names used by Modernizr to indicate support for CSS3. If the feature is not supported, the class name is prefixed by no- .
Table 1. CSS3 features detected by Modernizr
CSS Feature |
Modernizr class (property) |
@font-face |
fontface |
::before and ::after pseudo-elements |
generatedcontent |
background-size |
backgroundsize |
border-image |
borderimage |
border-radius |
borderradius |
box-shadow |
boxshadow |
CSS animations |
cssanimations |
CSS 2D transformations |
csstransforms |
CSS 3D transformations |
csstransforms3d |
CSS transitions |
csstransitions |
flexible box layout |
flexbox |
gradients |
cssgradients |
hsla() |
hsla |
multi-column layout |
csscolumns |
multiple backgrounds |
multiplebgs |
opacity |
opacity |
reflection |
cssreflections |
rgba() |
rgba |
text-shadow |
textshadow |
Where a specific CSS property is tested, the class name is the same as the property, but with any hyphen or parentheses removed. Other classes are named after the CSS3 module they refer to.
Looking at Table 1, you can see that Modernizr uses boxshadow and csscolumns to indicate support for the box-shadow property and multicolumn layout, respectively. So, you can create special style rules using the no-boxshadow and no-csscolumns classes for browsers that don't support these features.
To keep the instructions simple, I'll show only the CSS declarations. You can either type them directly into Code view or use the New CSS Rule dialog box.
.no-boxshadow img .#8A8A8A ). The resulting style rule looks like this:.no-boxshadow img {
border-right: #8A8A8A 2px solid;
border-bottom: #8A8A8A 2px solid;
}
This isn't as attractive as a translucent drop shadow, but it nevertheless helps the image stand out slightly from the background.
.no-csscolumns img ..no-csscolumns img {
margin: 3px 8px 3px 0;
float: left;
}
.columns img rule. Both rules have the same specificity, so the 10-pixel left margin in .columns img would override the rule you have just created if they're in the opposite order. You could rename .no-csscolumns img to .no-csscolumns .columns img to give it greater specificity, but it's best to keep selectors as simple as possible. (By the way, if you're not sure what specificity is, check out Adrian Senior's article, Understanding Specificity. It's an oldie, but goldie.)
In this simple example, I have used only the classes prefixed with no- to create special styles for older browsers. However, there's absolutely no reason why you shouldn't use both classes (with and without prefixes) to serve different styles to browsers according to their capability. For example:
.csscolumns {
/* rules for browsers that support multi-column layout */
}
.no-csscolumns {
/* rules for browsers that don't support multi-column layout */
}
Sometimes this approach is justified; for example, if you want to create a completely different layout for each level of support. But if it's simply a question of offering alternative styles to older browsers, don't forget that browsers ignore properties that they don't recognize. If you use Modernizr classes for all styles, your page will be totally unstyled in browsers that have JavaScript disabled.
The names of the classes that Modernizr adds to the opening <html> tag serve a dual purpose. They're also the names of JavaScript properties that the Modernizr object creates when the page loads. Table 1 listed the names of the classes and properties related to CSS. Table 2 lists the remaining classes and properties related to HTML5 and associated technologies, such as geolocation.
Table 2. HTML5-related features detected by Modernizr
| HTML5-related features |
Modernizr property (class) |
| Application cache |
applicationcache |
| Audio |
audio.type (ogg, mp3, wav, m4a) |
| Canvas |
canvas |
| Canvas text |
canvastext |
| Drag and drop |
draganddrop |
| Form input attributes |
input.attributeName |
| Form input elements |
inputtypes.elementName |
| Geolocation |
geolocation |
| hashchange event |
hashchange |
| History management |
history |
| IndexedDB |
indexeddb |
| Inline SVG |
inlinesvg |
| Local storage |
localstorage |
| Messaging |
postmessage |
| Session storage |
sessionstorage |
| SMIL |
smil |
| SVG |
svg |
| SVG clip paths |
svgclippaths |
| Touch events |
touch |
| Video |
video.type (ogg, webm, h264) |
| WebGL |
webgl |
| Web sockets |
websockets |
| Web SQL database |
websqldatabase |
| Web workers |
webworkers |
In most cases, all the properties listed in Tables 1 and 2 return true or false . So, you can test for local storage using JavaScript like this:
if (Modernizr.localstorage) {
// script to run if local storage is supported
} else {
// script to run if local storage is not supported
}
However, in the case of audio and video , the value returned is a string indicating the browser's level of confidence that it can play the specified type. According to the HTML5 specification, an empty string means the type isn't supported. If the type is supported, the value is "maybe" or "probably." For example:
if (Modernizr.video.h264 == "") {
// h264 is not supported
}
HTML5 adds several new form attributes, such as autofocus, which automatically puts the focus in a specified field when the page first loads. Another useful attribute is required, which prevents HTML5-compliant browsers from submitting the form if a required field is left blank (see Figure 6).
This is great, but it leaves you with the problem of what to do about older browsers. One solution is to ignore them, and leave the final check to server-side validation. A more user-friendly way to handle the situation is to create a small script to check required fields if the browser doesn't recognize the required attribute. The following instructions show how to do this with the help of Modernizr.
<script> block just before the closing </head> tag like this:</style>
<script src="js/modernizr.js"></script>
</head>
<script> block immediately after the tag that links the Modernizr library to the page, and create an event handler to execute code as soon as the page finishes loading:<script src="js/modernizr.js"></script>
<script>
window.onload = function() {
// code to execute when page loads
};
</script>
</head
autofocus and required attributes in browsers that don't recognize them. Dealing with autofocus is easy:window.onload = function() {
// get the form and its input elements
var form = document.forms[0],
inputs = form.elements;
// if no autofocus, put the focus in the first field
if (!Modernizr.input.autofocus) {
inputs[0].focus();
}
// if required not supported, emulate it
}
The condition tests Modernizr.input.autofocus , which returns false if autofocus is not supported. However, the logical NOT operator (an exclamation mark) reverses the meaning, so if autofocus is not supported, the condition evaluates to true , and inputs[0].focus() puts the focus in the first input field.
required is not supported. The complete code for the event handler looks like this:window.onload = function() {
// get the form and its input elements
var form = document.forms[0],
inputs = form.elements;
// if no autofocus, put the focus in the first field
if (!Modernizr.input.autofocus) {
inputs[0].focus();
}
// if required not supported, emulate it
if (!Modernizr.input.required) {
form.onsubmit = function() {
var required = [], att, val;
// loop through input elements looking for required
for (var i = 0; i < inputs.length; i++) {
att = inputs[i].getAttribute('required');
// if required, get the value and trim whitespace
if (att != null) {
val = inputs[i].value;
// if the value is empty, add to required array
if (val.replace(/^\s+|\s+$/g, '') == '') {
required.push(inputs[i].name);
}
}
}
// show alert if required array contains any elements
if (required.length > 0) {
alert('The following fields are required: ' +
required.join(', '));
// prevent the form from being submitted
return false;
}
};
}
}
The new code creates a function that loops through all the input elements when the form is submitted, looking for fields with the required attribute. When it finds one, it strips leading and trailing whitespace from the value, and if the result is an empty string, it adds it to the required array. If the array contains any elements after all the fields have been checked, the browser displays an alert with the names of the missing fields, and prevents the form from being submitted.
Note: Safari 5.1 falsely reports that it supports the required attribute, so it submits the form without validating the required fields. This is a bug in Safari, not in Modernizr.
When you're ready to deploy your site, it's recommended to create a customized production version of Modernizr, containing only those elements that you actually need. This can reduce the size of the Modernizr library from 44 KB to as little as 2 KB, depending on which features you choose. Figure 8 shows the current range of options.
The options are conveniently grouped in categories: CSS3, HTML5, Misc(ellaneous), and Extra. Clicking the Toggle button alongside the titles of the first three alternately selects and deselects all checkboxes in the category.
By default, the following three items are selected in the Extra category:
<header> , <footer> , <nav> , <section> , <article> , and so on.<html> tag. You must select this option if you want to detect support for CSS3 features.If you select any options in the CSS3 category, the following options in the Extra category are also selected:
Modernizr.testProp()Modernizr.testAllProps()Modernizr._domPrefixes()Do not deselect these options. Doing so automatically deselects any options you have chosen in the CSS3 category.
MQ Polyfill(respond.js) in the Extra category adds a script that enables limited support for media queries in IE 6–8. When you select this option, it automatically selects Media Queries and Modernizr.testStyles(). To learn more about the media queries polyfill (respond.js), visit https://github.com/scottjehl/Respond.
The remaining options in the Extra category are of interest only to advanced users. For details of what they're for and how to use them, see the Extensibility section of the Modernizr documentation.
The following instructions describe how to create a custom production version of Modernizr for the sample files. This custom version is needed for a later exercise, which shows how to use Modernizr.load() to load external JavaScript files.
<html> tag now has only three classes, as shown in Figure 9.
When creating a custom production version of Modernizr, the option to include Modernizr.load() is selected by default. Modernizr.load() is an alias for yepnope(), a standalone script loader that was developed with Modernizr in mind. To show a simple example of how to use it, I have moved the script from required.html to check_required.js and made three minor alterations to remove the Modernizr tests and to assign it to a variable called init. The revised script looks like this:
var init = function() {
// get the form and its input elements
var form = document.forms[0],
inputs = form.elements;
// put the focus in the first input field
inputs[0].focus();
// check required fields when the form is submitted
form.onsubmit = function() {
var required = [], att, val;
// loop through input elements looking for required
for (var i = 0; i < inputs.length; i++) {
att = inputs[i].getAttribute('required');
// if required, get the value and trim whitespace
if (att != null) {
val = inputs[i].value;
// if the value is empty, add to required array
if (val.replace(/^\s+|\s+$/g, '') == '') {
required.push(inputs[i].name);
}
}
}
// show alert if required array contains any elements
if (required.length > 0) {
alert('The following fields are required: ' + required.join(', '));
// prevent the form from being submitted
return false;
}
};
};
A big advantage of Modernizr.load() is that it conditionally loads scripts depending on the results of testing the browser's capabilities—that's why the original is called yepnope(). It loads external scripts asynchronously—in other words, after the Document Object Model (DOM) has loaded in the browser—so it can help speed up the performance of your site.
The basic syntax for Modernizr.load() is to pass it an object with the following properties:
test: The Modernizr property you want to detect.yep: The location of the script you want to load if the test succeeds. Use an array for multiple scripts.nope: The location of the script you want to load if the test fails. Use an array for multiple scripts.complete: A function to be run as soon as the external script has been loaded (optional).Both yep and nope are optional, as long as you supply one of them.
To load and execute the script in check_required.js, add the following <script> block after modernizr.adc.js has been attached to the page (the code is in required_load.html):
<script>
Modernizr.load({
test: Modernizr.input.required,
nope: 'js/check_required.js',
complete: function() {
init();
}
});
</script>
This works exactly the same as before, but reduces the download burden on browsers that already support the required attribute.
To test for multiple conditions, you can pass Modernizr.load() an array of objects. For more details, see the Modernizr.load() tutorial in the Modernizr documentation.
Modernizr is a powerful and useful tool, but that doesn't necessarily mean that you should use it. It's not always necessary to use Modernizr to provide alternative styles to browsers. If your main concern is Internet Explorer, consider using IE conditional comments. You can also use the CSS cascade to override some styles. For example, use a hexadecimal color first and then override it with rgba() or hsla(). Older browsers will use the first value and ignore the second.
Modernizr really comes into its own when combined with polyfills and other JavaScript. But remember that it's often very simple to create your own test for supported features. For example, the following is all you need to test whether a browser supports the required attribute (the code is in required_nomodernizr.html):
var elem = document.createElement('input');
if (typeof elem.required != 'boolean') {
// required is not supported
}
This tutorial has covered all the main features of Modernizr. To learn more about its features, study the official documentation at http://www.modernizr.com/docs/. You might also find the following resources useful:
yepnope(), which is incorporated in Modernizr as Modernizr.load().This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.
Tutorials and samples |
Dreamweaver user forum |
More |
| 04/23/2012 | Resolution/Compatibility/liquid layout |
|---|---|
| 04/20/2012 | using local/testing server with cs5 inserting images look fine in the split screen but do not show |
| 04/18/2012 | Ap Div help |
| 04/23/2012 | Updating |
Dreamweaver Cookbook |
More |