¿Cómo cargar archivos CSS usando Javascript?

316

¿Es posible importar hojas de estilo CSS en una página html usando Javascript? Si es así, ¿cómo se puede hacer esto?

PD: el javascript estará alojado en mi sitio, pero quiero que los usuarios puedan poner la <head>etiqueta de su sitio web, y debería poder importar un archivo CSS alojado en mi servidor en la página web actual. (tanto el archivo CSS como el archivo JavaScript se alojarán en mi servidor).

Haga clic en Upvote
fuente
También hay preguntas sobre jQuery stackoverflow.com/questions/2685614/…
jcubic

Respuestas:

416

Aquí está la forma de hacerlo de la "vieja escuela", que con suerte funciona en todos los navegadores. En teoría, usaría setAttributedesafortunadamente IE6 no lo admite de manera consistente.

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 ejemplo verifica si el CSS ya se agregó, por lo que lo agrega solo una vez.

Coloque ese código en un archivo javascript, haga que el usuario final simplemente incluya el javascript y asegúrese de que la ruta CSS sea absoluta para que se cargue desde sus servidores.

VanillaJS

Aquí hay un ejemplo que usa JavaScript simple para inyectar un enlace CSS en el headelemento basado en la parte del nombre de archivo de la 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>

Inserte el código justo antes de la headetiqueta de cierre y el CSS se cargará antes de que se renderice la página. El uso de un .jsarchivo externo JavaScript ( ) hará que aparezca un Flash de contenido sin estilo ( FOUC ).

tarjeta100
fuente
66
¿Qué pasa con la ejecución de una devolución de llamada una vez que se ha cargado el archivo CSS?
jchook
1
Esto es bastante más complejo de hacer de manera confiable. Las bibliotecas populares de JavaScript ahora tienen alguna forma de cargar JavaScript y hojas de estilo con una devolución de llamada. Como ejemplo, vea YUI Get .
99
quizás sería mejor usar un carácter diferente que $ para el acceso directo del documento, ya que puede interferir con jQuery fácilmente (como lo hizo en mi caso);)
Escritor de Zathrus el
2
@jonnybojangles Usar jQuery.noConflict significaría renombrar todas sus referencias a jQuery como $. Sería mucho más simple usar un nombre de variable diferente para el cargador de CSS.
tommypyatt
2
@jchook Pude adjuntar una devolución de llamada agregando link.onload = function(){ ... }antes de agregar
Lounge9
74

Si usa jquery:

$('head').append('<link rel="stylesheet" type="text/css" href="style.css">');
BoumTAC
fuente
1
esto solo funciona si la hoja de estilo se inyecta antes de la carga de la página, ¿verdad? Cuando ejecuto este comando dentro de la consola en una página cargada con un archivo CSS que he alojado en Dropbox, no funcionará. Alguna idea de cómo puedo hacer que esto funcione:$('head').append('<link rel="stylesheet" type="text/css" href="https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css">');
Thomas
50

Supongo que algo como este script haría:

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

Este archivo JS contiene la siguiente declaración:

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

La dirección de javascript y css necesitaría ser absoluta para que se refieran a su sitio.

Muchas técnicas de importación de CSS se analizan en este artículo "Di no a los hacks de CSS con técnicas de ramificación" .

Pero el artículo "Uso de JavaScript para agregar dinámicamente hojas de estilo CSS de Portlet" también menciona la posibilidad CreateStyleSheet (método patentado para 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
fuente
esto es lo que se me ocurrió agregar document.createStyleSheet()a los navegadores que no lo tienen: stackoverflow.com/questions/524696/…
Christoph
1
No estoy seguro exactamente en qué caso, pero en algunos casos, document.writeno se recomienda porque sobrescribe todo el cuerpo de su sitio web.
Eduard Luca
@VonC, ¿hay una función para obtener directamente el <style>elemento en lugar de asumir que es el primer hijo de <head>via ("head")[0]?
Pacerier
@Pacerier Creo que encontrarás eso discutido en groups.google.com/forum/#!topic/prototype-scriptaculous/… . Eso sería por ejemplo:var style = document.getElementsByTagName("style")[0];
VonC
20

Element.insertAdarestHTML tiene muy buena compatibilidad con el navegador y puede agregar una hoja de estilo en una línea.

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

Si desea saber (o esperar) hasta que el estilo se haya cargado, esto 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
fuente
¿Cómo uso esto
Raj Sharma
Usted haría fetchStyle (url) .then (function () {stuff goes here}) leer sobre las promesas
Ben Taliadoros
8

Sé que este es un hilo bastante viejo, pero aquí vienen mis 5 centavos.

Hay otra forma de hacerlo dependiendo de cuáles sean sus necesidades.

Tengo un caso en el que quiero que un archivo CSS esté activo solo por un tiempo. Al igual que el cambio de CSS. Active el CSS y luego, después de otro evento, desactívelo.

En lugar de cargar el css dinámicamente y luego eliminarlo, puede agregar una clase / id delante de todos los elementos en el nuevo css y luego simplemente cambiar esa clase / id del nodo base de su css (como etiqueta de cuerpo).

Con esta solución, tendría más archivos css cargados inicialmente pero tiene una forma más dinámica de cambiar los diseños de css.

JohanSellberg
fuente
7

En un navegador moderno puedes usar promiseasí. Cree una función de cargador con una promesa:

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

Entonces, obviamente, desea hacer algo después de que se haya cargado el CSS. Puede llamar a la función que debe ejecutarse después de que CSS se haya cargado así:

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

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

    return DoAfterCSSHasLoaded();
} );

Enlaces útiles si desea comprender en profundidad cómo funciona:

Documentos oficiales sobre promesas

Guía útil de promesas

Un gran video introductorio sobre promesas

Arthur Tarasov
fuente
6

Usa 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
fuente
4

Hay un complemento general de jquery que carga archivos CSS y JS de sincronización y asych bajo demanda. También mantiene un seguimiento de lo que ya se ha cargado :) ver: http://code.google.com/p/rloader/

ez2
fuente
4

Aquí hay una manera con el método de creación de elementos de jQuery (mi preferencia) y con devolución de llamada 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
fuente
2

Debajo de un código completo usando para cargar JS y / 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'])) ();
Hasan A Yousef
fuente
1

Me gustaría compartir una forma más para cargar no sólo CSS, pero todos los activos (js, css, imágenes) y el mango onload evento para el montón de archivos. Es async-assets-loader. Vea el siguiente ejemplo:

<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 acuerdo con los asincrónicos-activos-loader docs

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

Estoy usando tomillo y esto funciona bien. Gracias

ekoindra0912
fuente
¿Cuál es el punto de agregar th:hrefatributo en el lado del cliente? Thymeleaf no lo procesará, por lo que parece redundante aquí.
Slava Semushin el