How to fallback to local stylesheet (not script) if CDN fails
Solution 1
Not cross-browser tested but I think this will work. Will have to be after you load jquery though, or you'll have to rewrite it in plain Javascript.
<script type="text/javascript">
$.each(document.styleSheets, function(i,sheet){
if(sheet.href=='http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css') {
var rules = sheet.rules ? sheet.rules : sheet.cssRules;
if (rules.length == 0) {
$('<link rel="stylesheet" type="text/css" href="path/to/local/jquery.mobile-1.0b3.min.css" />').appendTo('head');
}
}
})
</script>
Solution 2
One could use onerror
for that:
<link rel="stylesheet" href="cdn.css" onerror="this.onerror=null;this.href='local.css';" />
The this.onerror=null;
is to avoid endless loops in case the fallback it self is not available. But it could also be used to have multiple fallbacks.
However, this currently only works in Firefox and Chrome.
Update: Meanwhile, this seems to be supported by all common browsers.
Solution 3
Assuming you are using the same CDN for css and jQuery, why not just do one test and catch it all??
<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1/themes/start/jquery-ui.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script type="text/javascript">
if (typeof jQuery == 'undefined') {
document.write(unescape('%3Clink rel="stylesheet" type="text/css" href="../../Content/jquery-ui-1.8.16.custom.css" /%3E'));
document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-1.6.4.min.js" %3E%3C/script%3E'));
document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-ui-1.8.16.custom.min.js" %3E%3C/script%3E'));
}
</script>
Solution 4
I guess the question is to detect whether a stylesheet is loaded or not. One possible approach is as follows:
1) Add a special rule to the end of your CSS file, like:
#foo { display: none !important; }
2) Add the corresponding div in your HTML:
<div id="foo"></div>
3) On document ready, check whether #foo
is visible or not. If the stylesheet was loaded, it will not be visible.
Demo here -- loads jquery-ui smoothness theme; no rule is added to stylesheet.
Solution 5
this article suggests some solutions for the bootstrap css http://eddmann.com/posts/providing-local-js-and-css-resources-for-cdn-fallbacks/
alternatively this works for fontawesome
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script>
(function($){
var $span = $('<span class="fa" style="display:none"></span>').appendTo('body');
if ($span.css('fontFamily') !== 'FontAwesome' ) {
// Fallback Link
$('head').append('<link href="/css/font-awesome.min.css" rel="stylesheet">');
}
$span.remove();
})(jQuery);
</script>
Related videos on Youtube
ssn
Updated on July 08, 2022Comments
-
ssn almost 2 years
I am linking to the jQuery Mobile stylesheet on a CDN and would like to fall back to my local version of the stylesheet if the CDN fails. For scripts the solution is well known:
<!-- Load jQuery and jQuery mobile with fall back to local server --> <script src="http://code.jquery.com/jquery-1.6.3.min.js"></script> <script type="text/javascript"> if (typeof jQuery == 'undefined') { document.write(unescape("%3Cscript src='jquery-1.6.3.min.js'%3E")); } </script>
I would like to do something similar for a style sheet:
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />
I am not sure if a similar approach can be achieved because I am not sure whether the browser blocks in the same way when linking a script as it does when loading a script (maybe it is possible to load a stylesheet in a script tag and then inject it into the page) ?
So my question is: How do I ensure a stylesheet is loaded locally if a CDN fails ?
-
Fosco almost 13 yearsI'd like to know if this is possible as well... If I really fretted about the CDN being down, I would just use local hosting.
-
Shawn Mclean almost 13 years@Stefan Kendall, i think the right statement is that his site will more than likely to go down than a CDN
-
nmit026 over 7 yearsBest way: stackoverflow.com/questions/26192897/…
-
-
Admin almost 13 yearsYes, at least in modern browser, I am not sure about IE6.
-
Shawn Mclean almost 13 yearsIs there a way to just check instead of downloading the whole thing?
-
Stefan Kendall almost 13 yearsThe only possible reason to do the OPs request is to avoid excess network traffic. This creates excess network traffic.
-
Admin almost 13 years@stefan Kendall: no that is not even the possible reason he wan'ts to make sure that the files get loaded.
-
Stefan Kendall almost 13 yearsIf that was the only concern, you would just not use a CDN. Testing just the header is better, but I'm pretty sure most CDNs and your browser aren't going to allow XSS.
-
Admin almost 13 yearsSure thing not using a CDN is the safest way but I give the answer assuming that the OP has some bandwith/speed issue.
-
Admin almost 13 years@stefan Kendall: I am wondering if you down-voted because the answer is not the best for your assumption of OP situation but not the actual question.
-
Stefan Kendall almost 13 years@Omeid: I explained why this probably won't work. Go try and create a jsfiddle testing this. Also, this doesn't account for when the CDN returns 503s, or when it returns 200s with empty content. There are many "potential edge cases" this doesn't cover, and it's almost certainly better handled at the CDN level anyway.
-
Admin almost 13 years@stefan: the OP asked to check for the CSS if its loaded or not and then to decide to download it from its server and it actually works.
-
GeorgeU almost 13 yearsgood solution, one issue it does not address is if the CDN is way too slow to load... maybe some sort of timeout?
-
Jannie Theunissen almost 12 years+1 for a clever solution. Only problem is, one normally can't go and add a line to the end of a style sheet that is hosted on someone's CDN
-
simplfuzz about 11 yearsFor code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css, I get rules = null, even though it's been loaded properly. I am using Chrome 26 and I think it's because the script is cross domain?
-
icebreaker about 11 yearsCDN can be reliable, but not the development environment internet connection ;)
-
AlicanC over 10 years@BenSchwarz, that doesn't mean you can paste some irrelevant code which in no way answers the asked question.
-
Maksim Vi. over 10 yearsThe solution doesn't really work for all CDNs/Stylesheets, for example
CSSStyleSheet
js objects that come from bootstrapcdn.com all have emptyrules
andcssRules
fields in my browser (Chrome 31). UPD: it actually might be a crossdomain issue, css file in the answer also doesn't work for me. -
Ahamed about 10 yearsUnfortunately, we can't type in our own classes to CDN files. May be we can try to utilize the one that exists already.
-
Hoppe over 9 yearsDoes this work with the protocol-less syntax? I.e. href="//ajax.googleapis.com/ajax/libs/jqueryui/1/themes/start/jquery-ui.css"
-
Nosnibor over 9 yearsI like this one A LOT, thank you. It's quite powerful really. Obviously I cannot manipulate the CDN stylesheet but I know what classes are being used so I amended the code to show check if they are visible - very clever indeed :)
-
Jack over 9 yearsMay I ask what the issue with using unescaped strings initially, e.g.
document.write("<script type='text/javascript' src='path/to/file.js'>")
? -
Brad Christie over 9 years@JackTuck: The parser can't differentiate between
<script>
inside a JS string and one found outside. This is commonly why you also see<\/script>
when writing out tags for CDN fallbacks. -
Flimzy almost 9 years-1
why not just do one test and catch it all?
-- Because there are a million reasons that one might fail, and the others succeed. -
Chemical Programmer almost 9 yearsThis is also good soloution using
onerror
event. stackoverflow.com/questions/30546795/… -
John Vinopal almost 9 yearsI like the encapsulation, but in general you can't inspect sheet.rules for a cross-domain stylesheet. You can still use this general idea but need to do a different check.
-
Salman A over 7 yearsDoes it work for CSS loaded from another domain? No, you cannot enumerate
.rules
/.cssRules
for external stylesheets. jsfiddle.net/E6yYN/13 -
Salman A over 7 yearsNB: you do not really have to add a new rule to the external CSS. Just use an existing rule whose behavior is known. In my demo I use ui-helper-hidden class which is supposed to hide the element, i then check if the element gets hidden on page load.
-
Jason Clark about 6 yearsFor those looking to use this with Font Awesome 5, you'll want to change 'FontAwesome' (in the if clause) to 'Font Awesome 5 Free' (if you're using the free fonts). Otherwise, it should work fine.
-
Alwin Kesler over 5 yearswith
document.styleSheets[i].ownerNode.dataset
you can access<link data-* />
attributes -
fabio almost 4 yearsCan't you check for the name or href? If so, how?
-
Jerry Krinock almost 4 yearsCONGRATULATIONS to all of you who, like me, couldn't believe that the complicated schemes proposed in earlier answers could still be the best way, and made it all the way down to here. This half-of-a-one-liner works perfectly. Let us see how fast we can up-vote it to the top. Or maybe someone with moderator access can delete the old answers.
-
Connor Low about 3 yearsWe don't delete old answers for being "not as elegant", but this is a good answer all the same.
-
Mafii over 2 yearsI searched for so long. This is great! How was this so hard to find. Thank you so much!
-
G M about 2 yearsHowever, sometimes the CDN just doesn't respond so you don't have any error and just keep waiting....