0

I am trying to write a conditional statement for my css files, because I am hoping to host them on CDN. Anyhow, I need to write a fallback for it, so if the CDN encountered a possible downtime, I could run the file right away on my own server. The problem is my knowledge of writing javascript is still a beginner, therefore I have no idea how to write the script.

Can anybody please help me out on this?

The piece code below is one I hope to use upon CDN:

<link rel="stylesheet" type="text/css" href="http://cdn.jsdelivr.net/animatecss/3.2.0/animate.min.css">

Please educate me on how may I create this conditional function properly?

Elizabeth
  • 291
  • 1
  • 3
  • 7

1 Answers1

3

Disclaimer

Seems like all of these very kind people have marked your question as a duplicate, however they didn't notice that the answer provided to that question does not work (the answer is from 2011 for god's sake, see why it doesn't work in the notes). I've already flagged it to moderators to see if they can unmark that.

Anyways, I've created a new demo for my updated answer taking into consideration your need to check for multiple cdn css files and how that may affect your websites performance. (I've used the head method in the XMLHttpRequest() which is faster according to this cool guy since it doesn't retrieve the pages body.

Also I've provided a format to easily replace failed external <link> tags which their local counterpart.

JavaScript

CSSback = {
    local: "cssfallback/",
    fallbacks: {
        "animate.min.css": "localanimate.css",
        "nonexistent.min.css": "localnonexistent.css"
    }
}

CSSback.init = function () {
    var links = document.head.querySelectorAll("link");
    for (var i = 0, l = links.length; i < l; i++) {
        var link = links[i];
        this.ping(link);
    }
}.bind(CSSback);

CSSback.ping = function (link) {
    var url = link.href;
    var http = new XMLHttpRequest();
    http.onreadystatechange = function () {
        if (http.readyState == 4 && http.status != 200) this.fallback(link);
    }.bind(this);
    http.open("head", url, true);
    http.send();
}.bind(CSSback);

CSSback.fallback = function (link) {
    var url = link.href.split("/");
    var name = url[url.length - 1];
    var fallback = this.fallbacks[name];
    if (fallback) {
        link.parentNode.removeChild(link);
        var link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = this.local + fallback;
        document.head.appendChild(link);
    }
}.bind(CSSback);

window.addEventListener("load", CSSback.init);

Usage

You should modify the CSSBack{}'s local (for the path to the local stylesheets) and fallbacks (for a key-value relationship between the name of the external stylesheet, and the name of the local stylesheet).

HTML

<link href="http://cdn.jsdelivr.net/animatecss/3.2.0/animate.min.css" (..) >
<link href="http://cdn.jsdelivr.net/animatecss/3.2.0/nonexistent.min.css" (..) >

Modified JavaScript

CSSback = {
    local: "cssfallback/",
    fallbacks: {
        "animate.min.css": "localanimate.css",
        "nonexistent.min.css": "localnonexistent.css"
    }
}

If any <link> fails, it will remove it and replace it with it's local counterpart, in this case nonexistent.min.css will fail and it will be replaced leaving the final <link> tags being:

<link href="http://cdn.jsdelivr.net/animatecss/3.2.0/animate.min.css" (..) >
<link href="cssfallback/nonexistent.css" (..) >

Notes

  • A <link> will fail if it's response status is 0 (non-allowed) or 404 (not-found), that means if the stylesheet is online but it's server doesn't have a Access-Control-Allow-Origin="*" policy it will think it failed too. (Fortunately most cdn's have it, including yours).
  • The selected answer in the other question does not work because document.styleSheets.cssRules in external stylesheets returns null in Chrome and Firefox just bluntly throws you a Security Error.

Hope it helps! :)

undefined
  • 3,949
  • 4
  • 26
  • 38
  • Thank you very much @Rou. Very detailed and helpful explanation. It educates me a bit in the server side of programming too. I will keep this in my list of techniques. Anyhow, would this affect my web performance if I was to write this script for every CDN linked? I'm also wondering if a fallback is actually really needed when CDN has some many other servers, so they could run on another one when one's down? – Elizabeth Feb 15 '15 at 20:46
  • I've updated my answer to make it as fast as possible and to easily implementate more than one cdn link, but in my personal opinion, the only reason why a cdn hosted file would be down it's if they removed it from there servers manually ;) – undefined Feb 15 '15 at 23:38
  • Thank you very much!! You're amazing help. Yes, I got very upset when I saw the down vote and marked as duplicate comments... I read all the other similar questions and their so long ago and I don't quite seem to understand them ... I thought I was just too naive, haha. :D So thank you for the answer. Big help. Would recommend others to read it too! Loved the demo as well!!! ;D – Elizabeth Feb 16 '15 at 21:09
  • No problem, glad I could help :) (pd:You can mark your question as answered by clicking on the green tick next to the answer) – undefined Feb 16 '15 at 21:11