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

Kliknij opcję Upvote
źródło
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 ).

card100
źródło
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">');
BoumTAC
źródło
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);
}
//]]>
VonC
źródło
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\" />");
dangowans
źródło
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);
  });
};
sandstrom
źródło
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.

JohanSellberg
źródło
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

Artur Tarasow
źródło
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);
Gaurav Tripathi
źródło
4

Istnieje ogólna wtyczka jquery, która ładuje synchronizację plików css i JS i asych na żądanie. Śledzi także to, co zostało już załadowane :) patrz: http://code.google.com/p/rloader/

ez2
źródło
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);
Lounge9
źródło
3

Biblioteki YUI może być to, czego szukasz. Obsługuje także ładowanie między domenami.

Jeśli używasz jquery, ta wtyczka robi to samo.

anand.trex
źródło
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'])) ();
Hasan A Yousef
źródło
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

v.babak
źródło
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

ekoindra0912
źródło
Po co dodawać th:hrefatrybut po stronie klienta? Nie zostanie przetworzony przez Thymeleaf, więc wydaje się tutaj zbędny.
Slava Semushin