5

I'm using a CDN to Load Bootstrap.css. My question is how can i check if CDN bootstrap was loaded/found. And if it wasn't, then load local Boostrap.

Here's Jquery fallback..

    <script type="text/javascript">
        Modernizr.load([
            {
                load: '//cdnjs.cloudflare.com/ajax/libs/jquery/1.10.1/jquery.min.js',
                complete: function () {
                    if ( !window.jQuery ) {
                        Modernizr.load([
                            {
                                load: config.js + 'vendor/jquery-1.10.1.min.js',
                                complete: function () {
                                    console.log("Local jquery-1.10.1.min.js loaded !");
                                }
                            }
                        ]);
                    } else {
                        console.log("CDN jquery-1.10.1.min.js loaded !");
                    }
                }
            }
        ]);
    </script>

And this is how i load Modernizr than Css:

    <script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js"></script>
    <script type="text/javascript">
    if (typeof Modernizr == 'undefined') {
        document.write(unescape("%3Cscript src='" + config.js + "/vendor/modernizr-2.6.2-respond-1.1.0.min.js' type='text/javascript'%3E%3C/script%3E"));
        console.log("Local Modernizer loaded !");
    }
    </script>

    <script type="text/javascript">
        Modernizr.load([
        {
            load: config.css + "bootstrap.css",
            complete: function () {
                console.log("bootstrap.css loaded !");
            }
        },
        {
            load: config.css + "responsive.css",
            complete: function () {
                console.log("responsive.css loaded !");
            }
        },
        {
            load: config.css + "icons.css",
            complete: function () {
                console.log("Fontello icons.css loaded !");
            }
        },
        {
            load: config.css + "icons-ie7.css",
            complete: function () {
                console.log("Fontello icons-ie7.css loaded !");
            }
        },
        {
            load: config.css + "animation.css",
            complete: function () {
                console.log("Fontello animation.css loaded !");
            }
        }
        ]);
    </script>

I have no idea how i could check if the css was loaded.. just like i did with modernizr and Jquery..

Thanks in advance...

João Costa
  • 487
  • 2
  • 6
  • 19

1 Answers1

1

Stoyan Stefanov has had a Pure JS solution for this for some time now, which actually just got an update not too long ago. Check out the link for an in depth breakdown.

But style.sheet.cssRules will only be populated once the file is loaded, so by checking for it repeatedly with a setInterval you are able to detect once your CSS file is loaded.

d = document;
d.head || (d.head = d.getElementsByTagName('head')[0]);

var style = d.createElement('style');
style.textContent = '@import "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"';

var fi = setInterval(function() {
    try {
        style.sheet.cssRules;
        console.log('loaded!');
        clearInterval(fi);
    } catch(e){
        console.log('loading...');
    }
}, 10);

d.head.appendChild(style);

YepNope acknowledges the use of this technique, though they note in their documentation that YepNope's "callback does not wait for the css to actually be loaded".

Plus with YepNope's recent depreciation, let's move onto to a solution that integrates with Modernizr (who will no longer be including YepNope in their software), but does not utilize any of Modernizr's libraries, since they still do not have a native solution. Offirmo combines a couple of neat techniques from Robert Nyman and Abdul Munim to let Modernizr know the CSS is actually loaded.

We start with the following function, which allows us to get the CSS property of an element:

function getStyle(oElm, strCssRule){
    var strValue = "";

    if (document.defaultView && document.defaultView.getComputedStyle){
        strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
    } else if (oElm.currentStyle){
        strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
            return p1.toUpperCase();
        });
        strValue = oElm.currentStyle[strCssRule];
    }

    return strValue;
}

Then we use the following funtion to create an hidden DOM element to test out CSS properties within:

function test_css(element_name, element_classes, expected_styles, rsrc_name, callback) {
    var elem = document.createElement(element_name);
    elem.style.display = 'none';
    for (var i = 0; i < element_classes.length; i++){
        elem.className = elem.className + " " + element_classes[i];
    }
    document.body.appendChild(elem);

    var handle = -1;
    var try_count = 0;
    var test_function = function(){
    var match = true;
    try_count++;
    for (var key in expected_styles){
        console.log("[CSS loader] testing " + rsrc_name + " css : " + key + " = '" + expected_styles[key] + "', actual = '" + get_style_of_element(elem, key) + "'");
        if (get_style_of_element(elem, key) === expected_styles[key]) match = match && true;
        else {
            console.error("[CSS loader] css " + rsrc_name + " test failed (not ready yet ?) : " + key + " = " + expected_styles[key] + ", actual = " + get_style_of_element(elem, key) );
            match = false;
        }
    }

    if (match === true || try_count >= 3){
          if (handle >= 0) window.clearTimeout(handle);
          document.body.removeChild(elem);

          if (!match) console.error("[CSS loader] giving up on css " + rsrc_name + "..." );
          else console.log("[CSS loader] css " + rsrc_name + " load success !" );

          callback(rsrc_name, match);
        }

        return match;
    }

    if(! test_function()){
        console.info("" + rsrc_name + " css test failed, programming a retry...");
        handle = window.setInterval(test_function, 100);
    }
}

Now we can reliably know, within Modernizr, if our CSS is ready to go:

Modernizr.load([
    {
        load: { 'bootstrap-css': 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css' },
        callback: function (url, result, key){
            //THIS IS OUR TEST USING THE ABOVE FUNCTIONS
            test_css('span', ['span1'], {'width': '60px'}, function(match){
                if (match){
                    console.log('CDN Resource Loaded!');
                } else {
                    console.log('Fallback to local resource!')
                }
            }
        }
    }
]);
Community
  • 1
  • 1
Madness
  • 2,730
  • 3
  • 20
  • 29
  • A note for testing this: The CDN is very fast, and that file is minified, so it loads extremely fast. JSFiddle & CodePen shows "loaded!" right away. You will have better results making and running a local HTML file. – Madness Aug 08 '15 at 01:51
  • This is a great answer. It's just that it uses a custom check, so in this respect one might just as well use a framework like [fallback.io](http://fallback.io/). But given that the answer clearly states there's no native solution with Modernizr, I guess it is worthy of the bounty? – Izhaki Aug 10 '15 at 21:26
  • Yeah, I tried to stay as true to the original question as possible, but alot has changed since 2013. The once great YepNope is depreciated. Modernizr is dropping it next release as a result. Modernizr still does not have a native solution. So I went under the assumption that the OP would still want to use Modernizr, so I went with the solution of using the pure JS checks rather than in the direction of ANOTHER library. But I, for certain, cannot decide if I deserve the bounty, that is for the community to decide :) – Madness Aug 10 '15 at 21:32
  • 1
    Well. Personally I feel no other answer can better this one and I got an answer. Bounty given. Thank you so much for the effort! – Izhaki Aug 10 '15 at 21:38