< Pixel Perfect />
Modernizr & Plugin Detection

Modernizr is a popular javascript library that helps you build the next generation of html5 and css3-powered websites. If your not familiar with it and your a developer, I recommend you visit there website.

Apart from its amazing feature detection abilities I’ve decided to play with its api a little. In a recent project of mine I wanted to seporate my javascript logic into 2 main categories to help keep clean seporation in my MVC app. My application varies in script(plugin) loading on each page. So I decided to use Modernizr’s feature detection abilities to load jquery plugins to decrease the overhead loading time on my pages.

Modernizrs api contains an method called addTest().


    Modernizr.addTest(str, fn)
    Modernizr.addTest(str, bool)
    Modernizr.addTest({str: fn, str2: fn2})
    Modernizr.addTest({str: bool, str2: fn})

I’ll add a class name to any element on the page, I’ll run a test. If Modernizr finds that specific class name, it means that that feature(plugin) exsists and needs to load its dependencies.

First I’ll add the new features to Modernizr:


/* Adding any of the class names to any element on the page 
   will load the dependencies for that plugin. */

Modernizr.addTest('pluginSlider', $(".pluginSlider").length == 1);
Modernizr.addTest('pluginTipped', $(".pluginTipped").length == 1);
Modernizr.addTest('pluginFancybox', $(".pluginFancybox").length == 1);
Modernizr.addTest('pluginSuperfish', $(".pluginSuperfish").length == 1);
Modernizr.addTest('pluginIsotope', $(".pluginIsotope").length == 1);

Next run the tests that determine what plugins are on the page.


Modernizr.load([
    {
        test: Modernizr.pluginSlider, // This will be truthy or falsy
        nope: ['/js/libs/slides.min.jquery.js']
    },
    {
        test: Modernizr.pluginTipped,
        nope: ['/js/libs/spinners.js', '/js/libs/tipped.js', '/css/tipped.css'],
        callback: function (url, result, key) { 
                      Modernizr.load([{ 
                          test: Modernizr.canvas, nope: ['/js/libs/excanvas.js']
                      }]); 
                  }
    },
    {
        test: Modernizr.pluginIsotope,
        nope: ['/js/libs/jquery.isotope.min.js']
    }
]);

Great! Scripts will now load if a class name such as “.pluginSlider” is on some element. Except one more thing that needs to be addressed. I want to separate the page specific logic. I like to develop using closures so what I can do is initiate whatever my page js object is. By adding the complete() method to the end of my tests, I can initiate my page object which has all my page specific logic in it.


Modernizr.load([
    {
        test: Modernizr.pluginSlider, // This will be truthy or falsy
        nope: ['/js/libs/slides.min.jquery.js']
    },
    {
        test: Modernizr.pluginTipped,
        nope: ['/js/libs/spinners.js', '/js/libs/tipped.js', '/css/tipped.css'],
        callback: function (url, result, key) { 
                      Modernizr.load([{ 
                          test: Modernizr.canvas, nope: ['/js/libs/excanvas.js']
                      }]); 
                  }
    },
    {
        test: Modernizr.pluginIsotope,
        nope: ['/js/libs/jquery.isotope.min.js'],

        /* HERE IS THE INIT OBJECT */
        complete: function () {
            /* Run this after everything in this group has downloaded
            and executed, as well everything in all previous groups */

            /* Each page should contain the object myapp else we just 
               fall back to an empty object */

            if (typeof myapp == 'function') {
                var app = new myapp();
                app.init();
            }


        }
    }
]);

Now on my page all I need to have is the closure model that initiates. To understand javascript closures view my other post here.


var myapp = (function () {

    var root = this;
    
    root.init = function(){
        /* CALL YOUR PLUGINS HERE */
        $("pluginSlider").slider();
    };

});

Summary: Clean separation of global dependencies and page specific logic. Improved performance by loading only scripts that are actually needed.

  1. mickeyelliott posted this