Come caricare i file CSS usando Javascript?


316

È possibile importare fogli di stile CSS in una pagina HTML usando Javascript? In tal caso, come si può fare?

PS il javascript sarà ospitato sul mio sito, ma voglio che gli utenti siano in grado di inserire il <head>tag del loro sito Web e dovrebbe essere in grado di importare un file CSS ospitato sul mio server nella pagina Web corrente. (sia il file css che il file javascript saranno ospitati sul mio server).


Ci sono anche domande su jQuery stackoverflow.com/questions/2685614/...
jcubic

Risposte:


416

Ecco il modo "old school" di farlo, che si spera funzioni su tutti i browser. In teoria, setAttributeuseresti purtroppo IE6 non lo supporta in modo coerente.

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

Questo esempio verifica se il CSS è già stato aggiunto, quindi lo aggiunge solo una volta.

Inserisci quel codice in un file javascript, chiedi all'utente finale di includere semplicemente il javascript e assicurati che il percorso CSS sia assoluto in modo che venga caricato dai tuoi server.

VanillaJS

Ecco un esempio che utilizza JavaScript semplice per iniettare un collegamento CSS headnell'elemento in base alla parte del nome file dell'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>

Inserisci il codice appena prima del headtag di chiusura e il CSS verrà caricato prima del rendering della pagina. L'uso di un .jsfile JavaScript ( ) esterno farà apparire un Flash di contenuto non stilato ( FOUC ).


6
Che ne dici di eseguire un callback dopo aver caricato il file CSS?
jchook,

1
Questo è abbastanza più complesso da fare in modo affidabile. Le popolari librerie Javascript ora hanno solitamente una qualche forma di caricamento di javascript e fogli di stile con un callback. Ad esempio, vedi YUI Get .

9
forse sarebbe meglio usare un carattere diverso da $ per la scorciatoia del documento, poiché può interferire facilmente con jQuery (come nel mio caso);)
Zathrus Writer

2
@jonnybojangles L'uso di jQuery.noConflict significherebbe rinominare tutti i riferimenti a jQuery come $. Sarebbe molto più semplice usare un nome di variabile diverso per il caricatore CSS.
tommypyatt,

2
@jchook Sono stato in grado di allegare una richiamata aggiungendo link.onload = function(){ ... }prima di aggiungere
Lounge9

74

Se usi jquery:

$('head').append('<link rel="stylesheet" type="text/css" href="style.css">');

1
questo funziona solo se il foglio di stile viene iniettato prima del pageload giusto? Quando eseguo questo comando all'interno della console su una pagina caricata con un file CSS che ho ospitato su Dropbox non funzionerà. Qualche idea su come posso farlo funzionare:$('head').append('<link rel="stylesheet" type="text/css" href="https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css">');
Thomas,

50

Immagino che qualcosa come questo script farebbe:

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

Questo file JS contiene la seguente dichiarazione:

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

L'indirizzo di JavaScript e CSS dovrebbe essere assoluto se devono fare riferimento al tuo sito.

Molte tecniche di importazione CSS sono discusse in questo articolo "Dì di no agli hacker CSS con tecniche di ramificazione" .

Ma l'articolo "Uso di JavaScript per aggiungere dinamicamente fogli di stile CSS Portlet" menziona anche la possibilità di CreateStyleSheet (metodo proprietario per 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);
}
//]]>

ecco cosa mi è venuto in mente di aggiungere document.createStyleSheet()ai browser che non ce l'hanno: stackoverflow.com/questions/524696/…
Christoph

1
Non sono sicuro esattamente in quale caso, ma in alcuni casi, document.writenon è raccomandato perché sovrascrive l'intero corpo del tuo sito web.
Eduard Luca,

@VonC, esiste una funzione per ottenere direttamente l' <style>elemento anziché supporre che sia il primo figlio di <head>via ("head")[0]?
Pacerier,

@Pacerier Credo che lo troverai discusso in groups.google.com/forum/#!topic/prototype-scriptaculous/… . Sarebbe ad esempio:var style = document.getElementsByTagName("style")[0];
VonC,

20

Element.insertAdjacentHTML ha un ottimo supporto per il browser e può aggiungere un foglio di stile in una riga.

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

12

Se vuoi sapere (o aspettare) fino a quando lo stile stesso non ha caricato questo funziona:

// 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);
  });
};

come posso usare questo
Raj Sharma,

Faresti fetchStyle (url) .then (function () {cose che vanno qui}) a leggere le promesse
Ben Taliadoros,

8

So che questo è un thread piuttosto vecchio, ma ecco che arrivano i miei 5 centesimi.

C'è un altro modo per farlo a seconda delle tue esigenze.

Ho un caso in cui voglio che un file CSS sia attivo solo per un po '. Come la commutazione css. Attiva il CSS e poi dopo un altro evento disattivalo.

Invece di caricare il css in modo dinamico e quindi rimuoverlo puoi aggiungere un Class / un id davanti a tutti gli elementi nel nuovo css e quindi cambiare quella classe / id del nodo base del tuo css (come il body tag).

Con questa soluzione avresti inizialmente caricato più file CSS ma hai un modo più dinamico di cambiare layout CSS.


7

In un browser moderno puoi usare promisecosì. Crea una funzione caricatore con una promessa in essa:

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!' ); 
        };
    } );
}

Quindi ovviamente vuoi fare qualcosa dopo che il CSS è stato caricato. Puoi chiamare la funzione che deve essere eseguita dopo che il CSS è stato caricato in questo modo:

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

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

    return DoAfterCSSHasLoaded();
} );

Link utili se vuoi capire in profondità come funziona:

Documenti ufficiali sulle promesse

Guida utile alle promesse

Un grande video introduttivo sulle promesse


6

Usa questo codice:

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

4

Esiste un plugin jquery generale che carica la sincronizzazione dei file css e JS e asych su richiesta. Tiene traccia anche di ciò che è già stato caricato :) vedi: http://code.google.com/p/rloader/


4

Ecco un modo con il metodo di creazione degli elementi di jQuery (la mia preferenza) e con callback 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);



2

Di seguito un codice completo che utilizza per caricare JS e / o 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'])) ();

1

Vorrei condividere un altro modo per caricare non solo css ma tutte le risorse (js, css, immagini) e gestire l' evento onload per il gruppo di file. Lo è async-assets-loader. Vedi l'esempio seguente:

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

Secondo i asincroni-asset-loader docs


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

Sto usando thymeleaf e questo funziona bene. Grazie


Qual è il punto di aggiungere un th:hrefattributo sul lato client? Non verrà elaborato da Thymeleaf, quindi sembra ridondante qui.
Slava Semushin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.