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


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.


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

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

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\" />");

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

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.


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


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


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



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'])) ();

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


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


Qual é o objetivo de adicionar th:hrefatributo no lado do cliente? Não será processado pelo Thymeleaf, por isso parece redundante aqui.
Slava Semushin
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.