开发者

How to use Javascript to check and load CSS if not loaded?

开发者 https://www.devze.com 2023-02-05 02:33 出处:网络
I need to check (in Javascript) if a CSS file is loaded 开发者_StackOverflow中文版and if not then to load it. jQuery is fine.Just check to see if a <link> element exists with the href attribute

I need to check (in Javascript) if a CSS file is loaded 开发者_StackOverflow中文版and if not then to load it. jQuery is fine.


Just check to see if a <link> element exists with the href attribute set to your CSS file's URL:

if (!$("link[href='/path/to.css']").length)
    $('<link href="/path/to.css" rel="stylesheet">').appendTo("head");

The plain ol' JS method is simple too, using the document.styleSheets collection:

function loadCSSIfNotAlreadyLoadedForSomeReason () {
    var ss = document.styleSheets;
    for (var i = 0, max = ss.length; i < max; i++) {
        if (ss[i].href == "/path/to.css")
            return;
    }
    var link = document.createElement("link");
    link.rel = "stylesheet";
    link.href = "/path/to.css";

    document.getElementsByTagName("head")[0].appendChild(link);
}
loadCSSIfNotAlreadyLoadedForSomeReason();


I just had to write something like that and I wanted to share it. This one is prepared for multiple cases.

  • If there is no request for the css file (css file isn't linked ...)
  • If there is a request for the css file, but if it failed (css file is no longer available ...)

var styles = document.styleSheets;
for (var i = 0; i < styles.length; i++) {
    // checking if there is a request for template.css
    if (styles[i].href.match("template")) {
        console.log("(Iteration: " + i + ") Request for template.css is found.");
        // checking if the request is not successful
        // when it is successful .cssRules property is set to null
        if (styles[i].cssRules != null && styles[i].cssRules.length == 0) {
            console.log("(Iteration: " + i + ") Request for template.css failed.");
            // fallback, make your modification
            // since the request failed, we don't need to iterate through other stylesheets
            break;
        } else {
            console.log("(Iteration: " + i + ") Request for template.css is successful.");
            // template.css is loaded successfully, we don't need to iterate through other stylesheets
            break;
        }
    }
    // if there isn't a request, we fallback
    // but we need to fallback when the iteration is done
    // because we don't want to apply the fallback each iteration
    // it's not like our css file is the first css to be loaded
    else if (i == styles.length-1) {
        console.log("(Iteration: " + i + ") There is no request for template.css.");
        // fallback, make your modification
    }
}

TL;DR version

var styles = document.styleSheets;
for (var i = 0; i < styles.length; i++) {
    if (styles[i].href.match("css-file-name-here")) {
        if (styles[i].cssRules != null && styles[i].cssRules.length == 0) {
            // request for css file failed, make modification
            break;
        }
    } else if (i == styles.length-1) {
        // there is no request for the css file, make modification
    }
}

Update: Since my answer got a few upvotes and this led me to revise the code, I decided to update it.

// document.styleSheets holds the style sheets from LINK and STYLE elements
for (var i = 0; i < document.styleSheets.length; i++) {

    // Checking if there is a request for the css file
    // We iterate the style sheets with href attribute that are created from LINK elements
    // STYLE elements don't have href attribute, so we ignore them
    // We also check if the href contains the css file name
    if (document.styleSheets[i].href && document.styleSheets[i].href.match("/template.css")) {

        console.log("There is a request for the css file.");

        // Checking if the request is unsuccessful
        // There is a request for the css file, but is it loaded?
        // If it is, the length of styleSheets.cssRules should be greater than 0
        // styleSheets.cssRules contains all of the rules in the css file
        // E.g. b { color: red; } that's a rule
        if (document.styleSheets[i].cssRules.length == 0) {

            // There is no rule in styleSheets.cssRules, this suggests two things
            // Either the browser couldn't load the css file, that the request failed
            // or the css file is empty. Browser might have loaded the css file,
            // but if it's empty, .cssRules will be empty. I couldn't find a way to
            // detect if the request for the css file failed or if the css file is empty

            console.log("Request for the css file failed.");

            // There is a request for the css file, but it failed. Fallback
            // We don't need to check other sheets, so we break;
            break;
        } else {
            // If styleSheets.cssRules.length is not 0 (>0), this means 
            // rules from css file is loaded and the request is successful
            console.log("Request for the css file is successful.");
            break;
        }
    }
    // If there isn't a request for the css file, we fallback
    // But only when the iteration is done
    // Because we don't want to apply the fallback at each iteration
    else if (i == document.styleSheets.length - 1) {
        // Fallback
        console.log("There is no request for the css file.");
    }
}

TL;DR

for (var i = 0; i < document.styleSheets.length; i++) {
    if (document.styleSheets[i].href && document.styleSheets[i].href.match("/template.css")) {
        if (document.styleSheets[i].cssRules.length == 0) {
            // Fallback. There is a request for the css file, but it failed.
            break;
        }
    } else if (i == document.styleSheets.length - 1) {
        // Fallback. There is no request for the css file.
    }
}


Something like this will do (using jQuery):

function checkStyleSheet(url){
   var found = false;
   for(var i = 0; i < document.styleSheets.length; i++){
      if(document.styleSheets[i].href==url){
          found=true;
          break;
      }
   }
   if(!found){
       $('head').append(
           $('<link rel="stylesheet" type="text/css" href="' + url + '" />')
       );
   }
}


Peer to the comment made by JFK about the accepted answer:

I understood the question as "how to check whether a css file is loaded or not" rather than "how to check if the element exists".

The element may exist (and the path may be correct too) but it doesn't mean that the css file was successful loaded.

If you access a link Element via getElementById you'll not be able to check/read the style defined inside the CSS file.

In order to check if a style has been successfully loaded we have to use getComputedStyle (or currentStyle for IE).

HTML

//somewhere in your html document

<div id="css_anchor"></div>

CSS

//somewhere in your main stylesheet

#css_anchor{display:none;}

JAVASCRIPT

//js function to check the computed value of a style element

function get_computed_style(id, name){

        var element = document.getElementById(id);

        return element.currentStyle ? element.currentStyle[name] : window.getComputedStyle ? window.getComputedStyle(element, null).getPropertyValue(name) : null;

}

 //on document ready check if #css_anchor has been loaded

    $(document).ready( function() {

            if(get_computed_style('css_anchor', 'display')!='none'){

            //if #css_anchor style doesn't exist append an alternate stylesheet

                var alternateCssUrl = 'http://example.com/my_alternate_stylesheet.css';

                var stylesheet = document.createElement('link');

                stylesheet.href = alternateCssUrl;
                stylesheet.rel = 'stylesheet';
                stylesheet.type = 'text/css';
                document.getElementsByTagName('head')[0].appendChild(stylesheet);

            }
    });

Part of the answer comes from: myDiv.style.display returns blank when set in master stylesheet

Demo here: http://jsfiddle.net/R9F7R/


Apart from all the nice answers above, you can simply put a dummy element inside your markup and in your css file, give it any style other than default. Then in the code check if the attribute is applied to the dummy element, and if not, load the css. Just a thought though, not a neat way to do that thing you want done.


My 2 cents. This checks whether there are any rules set on the css or not, meaning that it was or not successfully loaded

if(jQuery("link[href='/style.css']").prop('sheet').cssRules.length == 0){
    //Load the css you want
}


The document object contains a stylesheet collection with all the loaded stylesheets.

For a reference see http://www.javascriptkit.com/domref/stylesheet.shtml

You can loop this collection to verify that the stylesheet you want to verify is in it and thus loaded by the browser.

document.styleSheets[0] //access the first external style sheet on the page

There are some browser incompatibilities you should look out for though.


One way: use document.getElementsByTagName("link") iterate over each and check if its href is equal to the CSS file you check.

Another way: if you know some CSS rule being set only in that file, check if this rule really apply e.g. check if background of something is really red.


You can either check if the filename is within your markup, like:

var lnks    = document.getElementsByTagName('link'),
    loadcss = true;

for(var link in lnks) {
    href = link.getAttribute('href');

    if( href.indexOf('foooobar.css') > -1) ){
            loadcss = false;
            return false;
    }
});

if( loadcss ) {
        var lnk     = document.createElement('link'),
            head    = document.getElementsByTagName('head')[0] || document.documentElement;        

        lnk.rel     = 'stylesheet';
        lnk.type    = 'text/css';
        lnk.href    = '//' + location.host + 'foooobar.css';            

        head.insertBefore(lnk, head.firstChild);
}

or you could check for a specific className which should be available, if the stylesheet was loaded. This probably comes a little closer to a feature detection.


var links = document.getElementsByTagName('link');
var file  = 'my/file.css';
var found = false;

for ( var i in links )
{
    if ( links[i].type == 'text/css' && file == links[i].href ) {
        found = true; break;
    }
}

if ( !( found ) ) {
    var styles = document.getElementsByTagName('style');
    var regexp = new RegExp('/\@import url\("?' + file + '"?\);/');

    for ( var i in styles )
    {
        if ( styles[i].src == file ) {
            found = true; break;
        } else if ( styles[i].innerHTML.match(regexp) ) {
            found = true; break;
        }
    }
}

if ( !( found ) ) {
    var elm = document.createElement('link');
        elm.href = file;
    document.documentElement.appendChild(elm);
}


For a nice consistent and repeatable experience, I've written these two jQuery plugins that mimic the $.getScript(url, callback) jQuery method (however they will NOT force reloading from the server like $.getScript(). There are two methods: one that will load a CSS file anytime it's called, and one that will only load it once. I find the former handy during development when I'm making changes, and the latter great for a speedy deployment.

/**
 * An AJAX method to asynchronously load a CACHED CSS resource
 * Note: This removes the jQuery default behaviour of forcing a refresh by means
 * of appending a datestamp to the request URL. Actual caching WILL be subject to
 * server/browser policies
 */
$.getCachedCss = function getCachedCss(url, callback)
{
    $('<link>',{rel:'stylesheet', type:'text/css', 'href':url, media:'screen'}).appendTo('head');

    if (typeof callback == 'function')
        callback();
}

/**
 * An AJAX method to asynchronously load a CACHED CSS resource Only ONCE.
 * Note: This removes the jQuery default behaviour of forcing a refresh by means
 * of appending a datestamp to the request URL. Actual caching WILL be subject to
 * server/browser policies
 */
$.getCachedCssOnce = function getCachedCssOnce(url, callback)
{
    if (!$("link[href='" + url + "']").length) {
        $.getCachedCss(url, callback);

        if (typeof callback == 'function')
            callback();
    }
}

Usage example:

$(function() {
    $.getCachedCssOnce("pathToMyCss/main.css");
)}

Usage example with callback:

$(function() {
    $.getCachedCssOnce("pathToMyCss/main.css", function() {
        // Do something once the CSS is loaded
});


use .sheet in jQuery:

HTML:

<link rel="stylesheet" href="custom.css">

jQuery:

if($("link[href='custom.css']")[0].sheet.cssRules.length==0){
//custom.css was not loaded, do your backup loading here
}


simple way using javascript..,

loadCssIfNotLoaded('https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css');
loadCssIfNotLoaded('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css');

function loadCssIfNotLoaded(url) {
    var element=document.querySelectorAll('link[href="' + url + '"]');
    if (element.length == 0)
    {
        var link = document.createElement('link');
        link.rel = 'stylesheet';
        link.href = url;
        document.getElementsByTagName("head")[0].appendChild(link);
    }
}


In one line, with jQuery. If the #witness div is visible, we have to load the css file.

In the HTML, we have a:

<div id="witness"></div>

In the CSS file to load, we have:

  #witness{display:none;}

So, if the css file is loaded, the #witness div is not visible. We can check with jQuery and make decision.

!$('#witness').is(':visible') || loadCss() ;

As a snippet:

function loadCss(){
  //...
  console.log('Css file required');
};


!$('#witness').is(':visible') || loadCss();
#witness{display:none;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<div id="witness"></div>

0

精彩评论

暂无评论...
验证码 换一张
取 消