65 votes

Comment utiliser le Javascript pour vérifier et charger le CSS s'il n'est pas chargé ?

J'ai besoin de vérifier (en Javascript) si un fichier CSS est chargé et, si ce n'est pas le cas, de le charger. jQuery est parfait.

93voto

Andy E Points 132925

Vérifiez simplement si un <link> existe avec l'élément href avec l'URL de votre fichier CSS :

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

La méthode JS est également simple, en utilisant la fonction collection document.styleSheets :

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();

2 votes

Comment fonctionne le crossbrowser document.styleSheets ?

49 votes

J'ai compris que la question était "comment vérifier si un fichier css est chargé ou non" plutôt que "comment vérifier si le fichier css est chargé ou non". <link> élément existe". Le site <link> peut exister (et le chemin d'accès peut aussi être correct) mais cela ne signifie pas que le fichier css a été chargé avec succès. Donc, en reformulant la question : si un fichier css n'est pas chargé (problèmes de communication avec le serveur cdn par exemple), comment charger un fichier css (local) (fallback) à la place ?

0 votes

@JFK : cela mérite probablement sa propre question sur Stack Overflow. Il y a le load y error mais ils ne sont pas largement pris en charge (IE et Safari ne les prennent pas en charge, selon MDN). Je me pencherais probablement sur l'option document.styleSheets Vous pouvez vérifier le nombre de règles dans chaque feuille de style de la collection, si c'est le cas. 0 alors il n'a probablement pas réussi à se charger.

16voto

akinuri Points 1019

Je devais juste écrire quelque chose comme ça et je voulais le partager. Celui-ci est préparé pour de multiples cas.

  • S'il n'y a pas de demande pour le fichier css (le fichier css n'est pas lié ...)
  • S'il y a une demande pour le fichier css, mais si elle a échoué (le fichier css n'est plus disponible ...)

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
    }
}

Version TL;DR

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
    }
}

Mise à jour : Comme ma réponse a reçu quelques upvotes et que cela m'a amené à réviser le code, j'ai décidé de le mettre à jour.

// 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.
    }
}

1 votes

Dans Firefox, si le code CSS n'a pas encore été analysé, l'appel à la fonction cssRules échouera avec l'erreur InvalidAccessError : Un paramètre ou une opération n'est pas pris en charge par l'objet sous-jacent. .

0 votes

L'accès à cssRules dans Firefox déclenchera un message d'erreur erreur de sécurité

0 votes

Il existe une solution de contournement pour Firefox ici phpied.com/Quand une feuille de style est vraiment chargée ? .

5voto

Sean Patrick Floyd Points 109428

Quelque chose comme ceci fera l'affaire (en utilisant 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 + '" />')
       );
   }
}

0 votes

Ça ne marchera pas. Si une feuille de style est liée à l'intérieur d'un document, elle sera représentée dans le format document.styleSheets qu'il soit chargé ou non. Testez-le en créant un lien vers une feuille de style avec une URL invalide. Elle sera toujours là.

1voto

Shadow Wizard Points 38568

Un moyen : utiliser document.getElementsByTagName("link") itérer sur chacun et vérifier si son href est égal au fichier CSS que vous vérifiez.

Autre possibilité : si vous savez qu'une règle CSS n'est définie que dans ce fichier, vérifiez si cette règle s'applique vraiment, par exemple si l'arrière-plan d'un élément est vraiment rouge.

1voto

joksnet Points 1298
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);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X