First do it. Then do it right. Then do it better.
<canvas> in IE7 & 8 with FlashCanvas (Demo)
border-radius,box-shadow and gradients in IE7

Imagine if we could polyfill things like..
oldIE: Internet Explorer 6, 7 & 8. aka, the three browsers often getting the low-res experience.
New features will never be available in oldIE.
Bleeding-edge features aren't available in all modern browsers at the same time.
Polyfills are a type of shim that retrofit legacy browsers with modern HTML5/CSS3 features
Shims refer to any code that intercepts API calls and provides a layer of abstraction
Polyfills help us use today's modern features in yesterday's browsers
html tag based on browser capabilities<html class="no-cssgradients boxshadow no-cssanimations ...">
.no-cssgradients .shinybutton {
background: url("shinybutton.jpg");
}
.cssgradients .shinybutton {
background-image: linear-gradient(top, #555, #333);
}
if (Modernizr.webgl){
loadAllWebGLScripts(); // webgl assets can easily be > 300k
} else {
var msg = 'WebGL is not available in your browser';
document.getElementById( '#notice' ).innerHTML = msg;
}We'll look at more Modernizr feature detection tests later.
WebAudio API
Modernizr.addTest('webaudio',
!!(window.webkitAudioContext || window.AudioContext));Track API
Modernizr.addTest('trackapi',
typeof document.createElement('video').addTextTrack
=== 'function');
<!DOCTYPE html>
<html>
<head>
<style>section { border:1px solid red; display:block}</style>
<script>document.createElement('section');</script>
</head>
<body>
<section>
<p>Hello FITC!</p>
</section>
...
We can now style a HTML5 element in IE6 and above
<section> instead of <div> in older browsers<section>
<p>I can now be styled in all browsers!</p>
</section>
Remember, polyfills still needed for other features
There are some great script loaders that can help with conditional loading
Example: conditionally load a geolocation polyfill and stylesheet
yepnope({
test: Modernizr.geolocation,
yep: 'regular-styles.css',
nope: ['modified-styles.css', 'geolocation-polyfill.js'],
callback: function (url, result, key) {
if (url === 'modified-styles.css') {
alert("woohoo! it's loaded");
}
}
});
Supports similarly loading up a geolocation polyfill depending on support
Modernizr.load({
test: Modernizr.geolocation,
yep : 'geo.js',
nope: 'geo-polyfill.js'
});
Example: conditionally load a JSON polyfill if it isn't natively supported
$LAB.script(function(){
if (typeof JSON == "undefined") return "json2.js";
})
.wait()
.script("myotherscript.js");
An alternative:
$LAB.script(typeof JSON == "undefined" ? "json2.js" : false).wait()
.script("myotherscript.js");
Example: conditionally load a geolocation polyfill and stylesheet
yepnope({
test: Modernizr.geolocation,
yep: 'regular-styles.css',
nope: ['modified-styles.css', 'geolocation-polyfill.js'],
callback: function (url, result, key) {
if (url === 'modified-styles.css') {
alert('The Styles loaded!');
}
}
});
Why should you give writing polyfills a go?
You can't detect 'HTML5 Support', but you can detect support for individual features
There are some useful tips to keep in mind
window and document are your friendwindow //explore me!
Detecting finalized and unfinalized features. Test if:
window or navigator)
Testing for geolocation support
function isGeolocationSupported(){
return !!navigator.geolocation;
}and with Modernizr it's as simple as..
if(Modernizr.geolocation){
// supported
}else{
// not supported
}
Testing for <canvas> support
function isCanvasSupported(){
return !!document.createElement('canvas').getContext;
}and with Modernizr its..
if(Modernizr.canvas){
// supported
}else{
// not supported
}
Testing for <audio> support
function isAudioSupported(){
return !!document.createElement('audio').canPlayType;
}and with Modernizr its..
if(Modernizr.audio){
// supported
}else{
// not supported
}
Testing for <audio> format support
if(isAudioSupported()){
var audio = document.createElement('audio');
if(audio.canPlayType('audio/mpeg')=='probably'){
//supports MP3 audio
audio.src = 'music.mp3';
}
else if(audio.canPlayType('video/ogg; codecs="theora"')=='probably'){
//supports Ogg/Vorbis audio
audio.src = 'music.ogg';
}
}else{
//load a flash fallback
}
and with Modernizr its..
if(Modernizr.audio){
var audio = new Audio();
//If Ogg is supported, load 'music.ogg'
//Otherwise the MP3 or M4A fallback depending
//on browser support
audio.src = Modernizr.audio.ogg ? 'music.ogg' :
Modernizr.audio.mp3 ? 'music.mp3' :
'music.m4a';
}else{
//use a flash fallback
}
Testing for <input type="color"> support
function isColorPickerSupported(){
var input = document.createElement('input');
input.setAttribute('type','color');
return input.type !== 'text';
}and with Modernizr its..
if(Modernizr.inputtypes.color){
// supported
}else{
// not supported
}
Allow vendors to implement experimental features before they've been finalized
// From css3please.com:
.box_transition {
-webkit-transition: all 0.3s ease-out; /* Saf3.2+, Chrome */
-moz-transition: all 0.3s ease-out; /* FF4+ */
-ms-transition: all 0.3s ease-out; /* IE10? */
-o-transition: all 0.3s ease-out; /* Opera 10.5+ */
transition: all 0.3s ease-out; /*fast-forward compatible*/
}
Edge-features occasionally need to be tested prepending a vendor prefix to the feature name.
function getPrefix(prop){
var prefixes = ['Moz','Khtml','Webkit','O','ms'],
elem = document.createElement('div'),
upper = prop.charAt(0).toUpperCase() + prop.slice(1);
if (prop in elem.style)
return prop;
for (var len = prefixes.length; len--; ){
if ((prefixes[len] + upper) in elem.style)
return (prefixes[len] + upper);
}
return false;
}
console.log(getPrefix('transform'));//WebkitTransformconsole.log(Modernizr.prefixed('transform'));//WebkitTransform
As browser vendors implement new specs and features, the need for specific polyfills will decrease.
What did we learn today?
For more on me:
Big thanks to @paul_irish, @mathias, @peol, @rem and others for their previous work in this area and technical reviews.