Comment charger des fichiers CSS en utilisant Javascript?

317

Est-il possible d'importer des feuilles de style CSS dans une page html en utilisant Javascript? Si tel est le cas, comment cela peut-il se faire?

PS le javascript sera hébergé sur mon site, mais je veux que les utilisateurs puissent mettre la <head>balise de leur site web, et il devrait pouvoir importer un fichier css hébergé sur mon serveur dans la page web actuelle. (le fichier css et le fichier javascript seront hébergés sur mon serveur).

Cliquez Upvote
la source
Il y a aussi une question sur jQuery stackoverflow.com/questions/2685614/…
jcubic

Réponses:

416

Voici la façon de faire "à l'ancienne", qui, espérons-le, fonctionne sur tous les navigateurs. En théorie, vous utiliseriez setAttributemalheureusement IE6 qui ne le prend pas en charge de manière cohérente.

var cssId = 'myCss';  // you could encode the css path itself to generate id..
if (!document.getElementById(cssId))
{
    var head  = document.getElementsByTagName('head')[0];
    var link  = document.createElement('link');
    link.id   = cssId;
    link.rel  = 'stylesheet';
    link.type = 'text/css';
    link.href = 'http://website.com/css/stylesheet.css';
    link.media = 'all';
    head.appendChild(link);
}

Cet exemple vérifie si le CSS a déjà été ajouté, il ne l'ajoute qu'une seule fois.

Mettez ce code dans un fichier javascript, demandez à l'utilisateur final d'inclure simplement le javascript et assurez-vous que le chemin CSS est absolu afin qu'il soit chargé à partir de vos serveurs.

VanillaJS

Voici un exemple qui utilise du JavaScript simple pour injecter un lien CSS dans l' headélément en fonction de la partie du nom de fichier de l'URL:

<script type="text/javascript">
var file = location.pathname.split( "/" ).pop();

var link = document.createElement( "link" );
link.href = file.substr( 0, file.lastIndexOf( "." ) ) + ".css";
link.type = "text/css";
link.rel = "stylesheet";
link.media = "screen,print";

document.getElementsByTagName( "head" )[0].appendChild( link );
</script>

Insérez le code juste avant la headbalise de fermeture et le CSS sera chargé avant le rendu de la page. L'utilisation d'un .jsfichier JavaScript ( ) externe provoquera l'apparition d'un Flash de contenu non stylisé ( FOUC ).

card100
la source
6
Qu'en est-il de l'exécution d'un rappel une fois le fichier CSS chargé?
jchook
1
C'est beaucoup plus complexe à faire de manière fiable. Les bibliothèques Javascript populaires ont désormais généralement une forme de chargement de javascript et de feuilles de style avec un rappel. À titre d'exemple, voir YUI Get .
9
il serait peut-être préférable d'utiliser un caractère différent de $ pour le raccourci du document, car il peut interférer facilement avec jQuery (comme dans mon cas);)
Zathrus Writer
2
@jonnybojangles L'utilisation de jQuery.noConflict signifierait renommer toutes vos références à jQuery en $. Il serait beaucoup plus simple d'utiliser simplement un nom de variable différent pour le chargeur CSS.
tommypyatt
2
@jchook J'ai pu joindre un rappel en ajoutant link.onload = function(){ ... }avant d'ajouter
Lounge9
74

Si vous utilisez jquery:

$('head').append('<link rel="stylesheet" type="text/css" href="style.css">');
BoumTAC
la source
1
cela ne fonctionne que si la feuille de style est injectée avant le chargement de la page, n'est-ce pas? Lorsque j'exécute cette commande à l'intérieur de la console sur une page chargée avec un fichier css que j'ai hébergé sur dropbox, cela ne fonctionnera pas. Toute idée comment je peux faire fonctionner cela:$('head').append('<link rel="stylesheet" type="text/css" href="https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css">');
thomas
50

Je suppose que quelque chose comme ce script ferait:

<script type="text/javascript" src="/js/styles.js"></script>

Ce fichier JS contient l'instruction suivante:

if (!document.getElementById) document.write('<link rel="stylesheet" type="text/css" href="https://stackoverflow.com/css/versions4.css">');

L'adresse du javascript et du css devrait être absolue pour faire référence à votre site.

De nombreuses techniques d'importation CSS sont abordées dans cet article «Dites non aux hacks CSS avec des techniques de branchement» .

Mais l'article "Utilisation de JavaScript pour ajouter dynamiquement des feuilles de style CSS Portlet" mentionne également la possibilité CreateStyleSheet (méthode propriétaire pour IE):

<script type="text/javascript">
//<![CDATA[
if(document.createStyleSheet) {
  document.createStyleSheet('http://server/stylesheet.css');
}
else {
  var styles = "@import url(' http://server/stylesheet.css ');";
  var newSS=document.createElement('link');
  newSS.rel='stylesheet';
  newSS.href='data:text/css,'+escape(styles);
  document.getElementsByTagName("head")[0].appendChild(newSS);
}
//]]>
VonC
la source
voici ce que j'ai trouvé pour ajouter document.createStyleSheet()aux navigateurs qui ne l'ont pas: stackoverflow.com/questions/524696/…
Christoph
1
Je ne sais pas exactement dans quel cas, mais dans certains cas, ce document.writen'est pas recommandé car il écrase tout le corps de votre site Web.
Eduard Luca
@VonC, Existe-t-il une fonction pour obtenir directement l' <style>élément au lieu de supposer que c'est le premier enfant de <head>via ("head")[0]?
Pacerier
@Pacerier Je pense que vous trouverez cela discuté dans groups.google.com/forum/#!topic/prototype-scriptaculous/… . Ce serait par exemple:var style = document.getElementsByTagName("style")[0];
VonC
21

Element.insertAdjacentHTML a une très bonne prise en charge du navigateur et peut ajouter une feuille de style sur une seule ligne.

document.getElementsByTagName("head")[0].insertAdjacentHTML(
    "beforeend",
    "<link rel=\"stylesheet\" href=\"path/to/style.css\" />");
dangowans
la source
12

Si vous voulez savoir (ou attendre) que le style lui-même soit chargé, cela fonctionne:

// this will work in IE 10, 11 and Safari/Chrome/Firefox/Edge
// add ES6 poly-fill for the Promise, if needed (or rewrite to use a callback)

let fetchStyle = function(url) {
  return new Promise((resolve, reject) => {
    let link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.onload = function() { resolve(); console.log('style has loaded'); };
    link.href = url;

    let headScript = document.querySelector('script');
    headScript.parentNode.insertBefore(link, headScript);
  });
};
sandstrom
la source
comment utiliser ceci
Raj Sharma
Vous feriez fetchStyle (url) .then (function () {stuff va ici}) lire les promesses
Ben Taliadoros
8

Je sais que c'est un fil assez ancien, mais voici mes 5 cents.

Il existe une autre façon de procéder en fonction de vos besoins.

J'ai un cas où je veux qu'un fichier CSS ne soit actif que pendant un certain temps. Comme la commutation CSS. Activez le CSS puis, après un autre événement, désactivez-le.

Au lieu de charger le css dynamiquement puis de le supprimer, vous pouvez ajouter une classe / un id devant tous les éléments du nouveau css, puis changer simplement cette classe / id du nœud de base de votre css (comme la balise body).

Avec cette solution, vous auriez initialement plus de fichiers css chargés, mais vous avez une manière plus dynamique de changer de disposition css.

JohanSellberg
la source
7

Dans un navigateur moderne, vous pouvez utiliser promisecomme ça. Créez une fonction de chargeur avec une promesse:

function LoadCSS( cssURL ) {

    // 'cssURL' is the stylesheet's URL, i.e. /css/styles.css

    return new Promise( function( resolve, reject ) {

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

        link.rel  = 'stylesheet';

        link.href = cssURL;

        document.head.appendChild( link );

        link.onload = function() { 

            resolve(); 

            console.log( 'CSS has loaded!' ); 
        };
    } );
}

Alors, évidemment, vous voulez que quelque chose soit fait après le chargement du CSS. Vous pouvez appeler la fonction qui doit s'exécuter après le chargement de CSS comme ceci:

LoadCSS( 'css/styles.css' ).then( function() {

    console.log( 'Another function is triggered after CSS had been loaded.' );

    return DoAfterCSSHasLoaded();
} );

Liens utiles si vous souhaitez comprendre en détail comment cela fonctionne:

Documents officiels sur les promesses

Guide utile des promesses

Une superbe vidéo d'introduction sur les promesses

Arthur Tarasov
la source
6

Utilisez ce code:

var element = document.createElement("link");
element.setAttribute("rel", "stylesheet");
element.setAttribute("type", "text/css");
element.setAttribute("href", "external.css");
document.getElementsByTagName("head")[0].appendChild(element);
Gaurav Tripathi
la source
4

Il existe un plugin jquery général qui charge la synchronisation des fichiers css et JS et asych à la demande. Il garde également la trace de ce qui a déjà été chargé :) voir: http://code.google.com/p/rloader/

ez2
la source
4

Voici un moyen avec la méthode de création d'élément de jQuery (ma préférence) et avec le rappel onLoad:

var css = $("<link>", {
  "rel" : "stylesheet",
  "type" :  "text/css",
  "href" : "style.css"
})[0];

css.onload = function(){
  console.log("CSS IN IFRAME LOADED");
};

document
  .getElementsByTagName("head")[0]
  .appendChild(css);
Salon9
la source
3

La bibliothèque YUI est peut-être celle que vous recherchez. Il prend également en charge le chargement entre domaines.

Si vous utilisez jquery, ce plugin fait la même chose.

anand.trex
la source
2

Ci-dessous un code complet utilisant pour charger JS et / ou CSS

function loadScript(directory, files){
  var head = document.getElementsByTagName("head")[0]
  var done = false
  var extension = '.js'
  for (var file of files){ 
    var path = directory + file + extension 
    var script = document.createElement("script")
    script.src = path        
    script.type = "text/javascript"
    script.onload = script.onreadystatechange = function() {
        if ( !done && (!this.readyState ||
            this.readyState == "loaded" || this.readyState == "complete") ) {
            done = true
            script.onload = script.onreadystatechange = null   // cleans up a little memory:
            head.removeChild(script)  // to avoid douple loading
        }
  };
  head.appendChild(script) 
  done = false
 }
}

function loadStyle(directory, files){
  var head = document.getElementsByTagName("head")[0]
  var extension = '.css'
  for (var file of files){ 
   var path = directory + file + extension 
   var link = document.createElement("link")
   link.href = path        
   link.type = "text/css"
   link.rel = "stylesheet" 
   head.appendChild(link) 
 }
}

(() => loadScript('libraries/', ['listen','functions', 'speak', 'commands', 'wsBrowser', 'main'])) ();
(() => loadScript('scripts/', ['index'])) ();

(() => loadStyle('styles/', ['index'])) ();
Hasan A Yousef
la source
1

Je voudrais partager une autre façon de charger non seulement css mais tous les actifs (js, css, images) et gérer l' événement onload pour le tas de fichiers. Ça l'est async-assets-loader. Voir l'exemple ci-dessous:

<script src="https://unpkg.com/async-assets-loader"></script>
<script>
var jsfile = "https://code.jquery.com/jquery-3.4.1.min.js";
var cssfile = "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css";
var imgfile = "https://logos.keycdn.com/keycdn-logo-black.png";
var assetsLoader = new asyncAssetsLoader();
assetsLoader.load([
      {uri: jsfile, type: "script"},
      {uri: cssfile, type: "style"},
      {uri: imgfile, type: "img"}
    ], function () {
      console.log("Assets are loaded");
      console.log("Img width: " + assetsLoader.getLoadedTags()[imgfile].width);
    });
</script> 

Selon les async-actifs-chargeur docs

v.babak
la source
0
var fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("th:href", "@{/filepath}")
fileref.setAttribute("href", "/filepath")

J'utilise thymeleaf et cela fonctionne très bien. Merci

ekoindra0912
la source
Quel est l'intérêt d'ajouter un th:hrefattribut côté client? Il ne sera pas traité par Thymeleaf, il semble donc redondant ici.
Slava Semushin