Como carregar arquivos CSS usando Javascript?

316

É possível importar folhas de estilo css para uma página html usando Javascript? Se sim, como isso pode ser feito?

PS, o javascript estará hospedado no meu site, mas quero que os usuários possam inserir a <head>tag do site, e deve poder importar um arquivo css hospedado no meu servidor para a página da web atual. (o arquivo css e o arquivo javascript serão hospedados no meu servidor).

Click Voto a favor
fonte
Há também pergunta sobre jQuery stackoverflow.com/questions/2685614/...
jcubic

Respostas:

416

Aqui está a maneira "antiga" de fazer isso, que, esperançosamente, funciona em todos os navegadores. Em teoria, você usaria setAttributeinfelizmente o IE6 não o suporta consistentemente.

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

Este exemplo verifica se o CSS já foi adicionado e o adiciona apenas uma vez.

Coloque esse código em um arquivo javascript, faça com que o usuário final inclua o javascript e verifique se o caminho CSS é absoluto para que seja carregado nos seus servidores.

VanillaJS

Aqui está um exemplo que usa JavaScript simples para injetar um link CSS no headelemento com base na parte do nome do arquivo da 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>

Insira o código imediatamente antes da headtag de fechamento e o CSS será carregado antes da renderização da página. O uso de um .jsarquivo JavaScript ( ) externo fará com que um Flash de conteúdo não estilizado ( FOUC ) apareça.

card100
fonte
6
Que tal executar um retorno de chamada depois que o arquivo CSS for carregado?
jchook
1
Isso é bem mais complexo de se fazer com segurança. As bibliotecas Javascript populares agora geralmente têm alguma forma de carregar javascript e folhas de estilo com um retorno de chamada. Como um exemplo, consulte YUI Get .
9
talvez seria melhor usar um personagem diferente de US $ para o atalho documento, pois ele pode interferir com jQuery facilmente (como fez no meu caso);)
Zathrus Escritor
2
@jonnybojangles Usar o jQuery.noConflict significaria renomear todas as suas referências ao jQuery como $. Seria muito mais simples usar um nome de variável diferente para o carregador CSS.
tommypyatt
2
@jchook eu era capaz de anexar um retorno de chamada, adicionando link.onload = function(){ ... }antes de acrescentar
Lounge9
74

Se você usa jquery:

$('head').append('<link rel="stylesheet" type="text/css" href="style.css">');
BoumTAC
fonte
1
isso só funciona se a folha de estilo for injetada antes do carregamento da página, certo? Quando executo esse comando no console em uma página carregada com um arquivo css que eu hospedei no dropbox, ele não funciona. Alguma idéia de como eu posso fazer isso funcionar:$('head').append('<link rel="stylesheet" type="text/css" href="https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css">');
thomas
50

Eu acho que algo como este script faria:

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

Este arquivo JS contém a seguinte instrução:

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

O endereço do javascript e do css precisaria ser absoluto para se referir ao seu site.

Muitas técnicas de importação de CSS são discutidas neste artigo "Diga não aos hacks de CSS com técnicas de ramificação" .

Mas o artigo "Usando JavaScript para adicionar dinamicamente folhas de estilo CSS do Portlet" menciona também a possibilidade CreateStyleSheet (método proprietário do 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
fonte
aqui está o que eu vim para adicionar document.createStyleSheet()aos navegadores que não o possuem: stackoverflow.com/questions/524696/… #
Christoph
1
Não tenho certeza exatamente de qual caso, mas em alguns casos, document.writenão é recomendado porque substitui todo o corpo do seu site.
Eduard Luca
@VonC, Existe uma função para obter diretamente o <style>elemento em vez de assumir que é o primeiro filho da <head>via ("head")[0]?
Pacerier
@Pacerier Acredito que você encontrará isso discutido em groups.google.com/forum/#!topic/prototype-scriptaculous/… . Isso seria, por exemplo:var style = document.getElementsByTagName("style")[0];
VonC 30/04/2014
20

O Element.insertAdjacentHTML possui um suporte muito bom ao navegador e pode adicionar uma folha de estilo em uma linha.

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

Se você deseja saber (ou esperar) até que o próprio estilo seja carregado, isso funciona:

// 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
fonte
Como faço para usar isso
Raj Sharma
Você faria fetchStyle (url) .then (function () {material vai aqui}) ler sobre promessas
Ben Taliadoros
8

Eu sei que este é um tópico bastante antigo, mas aqui vem meus 5 centavos.

Há outra maneira de fazer isso, dependendo de quais são suas necessidades.

Eu tenho um caso em que eu quero que um arquivo css fique ativo apenas um tempo. Como troca de CSS. Ative o css e depois de outro evento, desative-o.

Em vez de carregar o css dinamicamente e removê-lo, você pode adicionar um ID de classe / um na frente de todos os elementos no novo css e depois alternar essa classe / ID do nó base do seu css (como tag corporal).

Nesta solução, você teria mais arquivos css carregados inicialmente, mas você tem uma maneira mais dinâmica de alternar layouts de css.

JohanSellberg
fonte
7

Em um navegador moderno, você pode usar promiseassim. Crie uma função loader com uma promessa:

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

Então, obviamente, você deseja fazer algo após o CSS ser carregado. Você pode chamar a função que precisa ser executada após o CSS ser carregado da seguinte maneira:

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

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

    return DoAfterCSSHasLoaded();
} );

Links úteis se você quiser entender em profundidade como ele funciona:

Documentos oficiais sobre promessas

Guia útil de promessas

Um ótimo vídeo de introdução sobre promessas

Arthur Tarasov
fonte
6

Use este código:

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

Existe um plug-in jquery geral que carrega sincronização de arquivos css e JS e asych sob demanda. Ele também rastreia o que já foi carregado :) consulte: http://code.google.com/p/rloader/

ez2
fonte
4

Aqui está uma maneira com o método de criação de elementos do jQuery (minha preferência) e com retorno de chamada 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
fonte
3

A biblioteca YUI pode ser o que você está procurando. Ele também suporta carregamento entre domínios.

Se você usa jquery, este plugin faz a mesma coisa.

anand.trex
fonte
2

Abaixo de um código completo usando para carregar JS e / 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
fonte
1

Gostaria de compartilhar mais uma maneira de carregar não apenas css, mas todos os recursos (js, css, imagens) e manipular o evento onload para o monte de arquivos. É async-assets-loader. Veja o exemplo abaixo:

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

De acordo com os assíncronos-ativos-loader docs

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

Estou usando thymeleaf e isso é bom trabalho. obrigado

ekoindra0912
fonte
Qual é o objetivo de adicionar th:hrefatributo no lado do cliente? Não será processado pelo Thymeleaf, por isso parece redundante aqui.
Slava Semushin