There's a similar post already, but I don't feel it answers my particular question well enough.
I want to check that an external stylesheet has loaded. For example, if it has been stymied by a network problem then I want to know and load a fallback. This is as a fallback for a CDN for jQuery's themes CSS but I'd prefer this doesn't end up being specifically about that as I've other external CSS I use that I'd like to apply this to as well.
link
element will be there on the page, so pattern matching for the existence of the link element in the head is not acceptable.Edit: A new thought. What about if the stylesheet was loaded via AJAX, and the status code checked? Is that a viable option, does anyone know?
Here's the script I have currently:
<script type="text/javascript">
var cdn = 'http://code.jquery.com/ui/1.10.1/themes/black-tie/jquery-ui.min.css';
var ss = document.styleSheets;
for (var i = 0, max = ss.length; i < max; i++) {
var sheet = ss[i];
var rules = sheet.rules ? sheet.rules : sheet.cssRules;
if (sheet.href == cdn) {
if ( rules == null || rules.length == 0) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = '/js/jquery-ui/1.10.1/themes/black-tie/jquery-ui.min.css';
document.getElementsByTagName("head")[0].appendChild(link);
}
break;
}
}
</script>
What I've found on using the console (Chrome v25.0.1364.172) is that even when the stylesheet has loaded from the CDN, document.styleSheets[x].rules
is null
. I'm not sure if I'm accessing it correctly in the console though, maybe there's another function I should use or object?
CSSStyleSheet {rules: null, cssRules: null, ownerRule: null, media: MediaList, title: null…}
cssRules: null
disabled: false
href: "http://code.jquery.com/ui/1.10.1/themes/black-tie/jquery-ui.min.css"
media: MediaList
ownerNode: link
ownerRule: null
parentStyleSheet: null
rules: null
title: null
type: "text/css"
__proto__: CSSStyleSheet
If anyone can help me find how to check the stylesheet has loaded, that would be very helpful and much appreciated.
The <link> tag is most often used to link to external style sheets or to add a favicon to your website. The <link> element is an empty element, it contains attributes only.
See the production code at the github repo for the rack-jquery_ui-themes library. Ignore all interpolation of constants and the uppercase symbols like :THEME
, they get substituted elsewhere. Just imagine it's pristine javascript.
Many thanks to Brian in the comments to my question for providing the main source of inspiration for this.
<meta id='rack-jquery-ui-themes-fallback-beacon' />
<script type="text/javascript">
var meta = $("#rack-jquery-ui-themes-fallback-beacon");
meta.addClass("ui-icon");
if ( meta.css('width') != "16px" ) {
$('<link rel="stylesheet" type="text/css" href="/js/jquery-ui/#{JQueryUI::JQUERY_UI_VERSION}/themes/:THEME/#{JQUERY_UI_THEME_FILE}" />').appendTo('head');
}
meta.remove();
</script>
Adding a meta tag, then applying a CSS class from the jQuery UI stylesheet, then checking it had changed and adding the fallback link if not, then removing the meta tag.
There is a reason we use a meta tag in the head instead of something like a div in the body. Most CSS files are included by link elements in the head. If the script to check if it loaded comes immediately after that, since it is in the context of the head, the body has not been loaded into the DOM yet. Accessing document.body in that context will cause a null ref error.
<script type="text/javascript">
$.ajax({
type: "HEAD",
url: ':CDNURL',
success: function(css,status) {
// do nothing
},
error: function(xhr,status,error) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = ':FALLBACK_URL';
document.getElementsByTagName("head")[0].appendChild(link);
}
});
</script>
I found out that this is a potential security threat so browsers won't allow it.
<script type="text/javascript">
var has_jquery_rules = false;
var i = document.styleSheets.length - 1;
while (i >= 0 ) {
var sheet = document.styleSheets[i];
if(sheet.href == ":CDNURL/ui/#{JQueryUI::JQUERY_UI_VERSION}/themes/:THEME/jquery-ui.min.css") {
var rules = sheet.rules ? sheet.rules : sheet.cssRules;
has_jquery_rules = rules.length == 0 ? false : true;
break; // end the loop.
}
has_jquery_rules = false;
i--;
}
if ( has_jquery_rules == false ) {
$('<link rel="stylesheet" type="text/css" href="/js/jquery-ui/#{JQueryUI::JQUERY_UI_VERSION}/themes/:THEME/#{JQUERY_UI_THEME_FILE}" />').appendTo('head');
}
</script>
This also doesn't work, as some (all?) browsers block access to rules added by an external stylesheet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With