Jak ładować pliki CSS za pomocą Javascript?


316

Czy można importować arkusze stylów css do strony HTML za pomocą Javascript? Jeśli tak, jak to zrobić?

PS javascript będzie hostowany na mojej stronie, ale chcę, aby użytkownicy mogli wstawić <head>tag swojej witryny i powinien móc importować plik css hostowany na moim serwerze na bieżącą stronę internetową. (zarówno plik css, jak i plik javascript będą hostowane na moim serwerze).


Istnieje również pytanie dotyczące jQuery stackoverflow.com/questions/2685614/…
jcubic

Odpowiedzi:


416

Oto sposób „starej szkoły”, który, mam nadzieję, działa we wszystkich przeglądarkach. Teoretycznie setAttributeużyłbyś niestety IE6 nie obsługuje go konsekwentnie.

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

Ten przykład sprawdza, czy CSS został już dodany, więc dodaje go tylko raz.

Umieść ten kod w pliku javascript, poproś użytkownika końcowego o dołączenie javascript i upewnij się, że ścieżka CSS jest bezwzględna, aby została załadowana z twoich serwerów.

VanillaJS

Oto przykład, który używa zwykłego JavaScript do wstrzykiwania linku CSS do headelementu na podstawie nazwy pliku 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>

Wstaw kod tuż przed headtagiem zamykającym, a CSS zostanie załadowany przed wyrenderowaniem strony. Użycie zewnętrznego .jspliku JavaScript ( ) spowoduje wyświetlenie Flash niestylizowanej treści ( FOUC ).


6
Co z uruchomieniem wywołania zwrotnego po załadowaniu pliku CSS?
jchook

1
Jest to bardziej skomplikowane, aby zrobić niezawodnie. Popularne biblioteki JavaScript mają teraz zwykle pewną formę ładowania javascript i arkuszy stylów z wywołaniem zwrotnym. Jako przykład zobacz YUI Get .

9
być może lepiej byłoby użyć skrótu dokumentu innego niż $, ponieważ może łatwo zakłócać działanie jQuery (tak jak w moim przypadku);)
Zathrus Writer

2
@jonnybojangles Korzystanie z jQuery.noConflict oznaczałoby zmianę nazwy wszystkich odniesień do jQuery na $. Byłoby o wiele prostsze użycie innej nazwy zmiennej dla modułu ładującego CSS.
tommypyatt

2
@jchook Byłem w stanie dołączyć oddzwonienie, dodając link.onload = function(){ ... }przed dołączeniem
Lounge9

74

Jeśli używasz jquery:

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

1
działa to tylko wtedy, gdy arkusz stylów jest wstrzykiwany przed ładowaniem strony, prawda? Gdy uruchomię to polecenie w konsoli na załadowanej stronie z plikiem css, który hostowałem na Dropbox, to nie zadziała. Każdy pomysł, jak mogę sprawić, by to działało:$('head').append('<link rel="stylesheet" type="text/css" href="https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css">');
Thomas

50

Wydaje mi się, że coś takiego zrobiłby ten skrypt:

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

Ten plik JS zawiera następującą instrukcję:

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

Adres javascript i css musiałby być bezwzględny, jeśli mają odnosić się do Twojej witryny.

Wiele technik importowania CSS omówiono w tym artykule „Powiedz nie hackom CSS za pomocą technik rozgałęziających” .

Ale artykuł „Korzystanie z JavaScript do dynamicznego dodawania arkuszy stylów CSS Portlet” wspomina również o możliwości CreateStyleSheet (własna metoda dla 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);
}
//]]>

oto, co wymyśliłem, aby dodać document.createStyleSheet()do przeglądarek, które go nie mają: stackoverflow.com/questions/524696/…
Christoph

1
Nie jestem pewien, w którym dokładnie przypadku, ale w niektórych przypadkach document.writenie jest to zalecane, ponieważ zastępuje ono całą treść witryny.
Eduard Luca,

@VonC, Czy istnieje funkcja, która bezpośrednio pobiera <style>element zamiast zakładać, że jest to pierwszy element potomny <head>via ("head")[0]?
Pacerier

@Pacerier Wierzę, że znajdziesz to omówione w groups.google.com/forum/#!topic/prototype-scriptaculous/… . To byłoby na przykład:var style = document.getElementsByTagName("style")[0];
VonC

20

Element.insertAdjacentHTML ma bardzo dobrą obsługę przeglądarki i może dodawać arkusz stylów w jednym wierszu.

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

12

Jeśli chcesz wiedzieć (lub czekać), aż sam styl się załaduje, działa to:

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

jak tego używać
Raj Sharma

Zrobiłbyś fetchStyle (url). Then (function () {stuff is here}) czytaj dalej o obietnicach
Ben Taliadoros

8

Wiem, że to dość stary wątek, ale oto moje 5 centów.

Jest inny sposób na zrobienie tego w zależności od potrzeb.

Mam przypadek, w którym chcę, aby plik css był aktywny tylko przez chwilę. Jak przełączanie css. Aktywuj css, a następnie po innym zdarzeniu dezaktywuj go.

Zamiast dynamicznie ładować css, a następnie go usuwać, możesz dodać identyfikator klasy / id przed wszystkimi elementami w nowym css, a następnie po prostu przełączyć tę klasę / id węzła podstawowego twojego css (jak znacznik body).

Dzięki temu rozwiązaniu początkowo zostanie załadowanych więcej plików css, ale masz bardziej dynamiczny sposób przełączania układów css.


7

W nowoczesnej przeglądarce możesz używać promisetego w ten sposób. Utwórz funkcję modułu ładującego z obietnicą:

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

Wtedy oczywiście chcesz coś zrobić po załadowaniu CSS. Możesz wywołać funkcję, która musi działać po załadowaniu CSS w następujący sposób:

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

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

    return DoAfterCSSHasLoaded();
} );

Przydatne linki, jeśli chcesz dokładnie zrozumieć, jak to działa:

Oficjalne dokumenty dotyczące obietnic

Przydatny przewodnik po obietnicach

Świetny film wprowadzający o obietnicach


6

Użyj tego kodu:

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

Oto sposób z metodą tworzenia elementów jQuery (moje preferencje) i wywołaniem zwrotnym 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

Poniżej pełnego kodu używanego do ładowania JS i / lub 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

Chciałbym udostępnić jeszcze jeden sposób, aby załadować nie tylko css, ale wszystkie zasoby (js, css, obrazy) i obsłużyć zdarzenie onload dla grupy plików. Jest async-assets-loader. Zobacz przykład poniżej:

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

Według asynchroniczny-aktywów-ładowarki 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")

Używam thymeleaf i to działa dobrze. Dzięki


Po co dodawać th:hrefatrybut po stronie klienta? Nie zostanie przetworzony przez Thymeleaf, więc wydaje się tutaj zbędny.
Slava Semushin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.