Foros del Web » Programando para Internet » Javascript »

Crear hoja de estilo CSS con javascript

Estas en el tema de Crear hoja de estilo CSS con javascript en el foro de Javascript en Foros del Web. Buenas, Me interesaría saber cómo crear una hoja de estilo con javascript, insertarla en head y luego obtener un valor para poder referenciarla y usarla ...
  #1 (permalink)  
Antiguo 09/12/2013, 07:09
 
Fecha de Ingreso: julio-2006
Ubicación: Barcelona
Mensajes: 244
Antigüedad: 17 años, 9 meses
Puntos: 32
Crear hoja de estilo CSS con javascript

Buenas,

Me interesaría saber cómo crear una hoja de estilo con javascript, insertarla en head y luego obtener un valor para poder referenciarla y usarla a través de document.styleSheets. He pensado lo siguiente:

1) Creo un elemento link y le inserto el atributo type="text/css"
2) Inserto dicho elemento link usando document.head.appendChild( ... )
3) Guardo en una variable indice el valor document.styleSheets.length - 1 ( ¿seria la referencia a la ultima hoja de estilos insertada )
4) Inserto en doucment.styleSheets[indice] varias reglas mediante el método insertRule

Dudo, sobretodo, de si el punto 3 es correcto. Pues no se si del punto 2 se deduce que se insetará una nueva hoja de estilos al final de document.styleSheets . También he leído que StyleSheetList( la clase de document.styleSheets ) no tiene metodo para insertarle hojas de estilo.

También dudo en el punto 1. Pues no sé que comportamiento tendría una hoja de estilo que no haga referencia a ningún fichero en concreto con href.

Edit:
Con códigos como estos puede verse que añadir un link a document head no afecta a document.styleSheets:
Código Javascript:
Ver original
  1. console.log( document.styleSheets.length );
  2.     css = document.createElement( 'link' );
  3.     css.setAttribute( 'type', 'text/css' );
  4.     document.getElementsByTagName( 'head' )[0].appendChild( css );
  5.     console.log( document.styleSheets.length );

Un saludo y gracias!

Última edición por Pantaláimon; 09/12/2013 a las 08:38
  #2 (permalink)  
Antiguo 12/12/2013, 03:26
 
Fecha de Ingreso: julio-2006
Ubicación: Barcelona
Mensajes: 244
Antigüedad: 17 años, 9 meses
Puntos: 32
Respuesta: Crear hoja de estilo CSS con javascript

Bueno,

Después de buscar y buscar información he conseguido crear una función createStyleSheet que funcione para algún caso.

Código Javascript:
Ver original
  1. if(typeof document.createStyleSheet === 'undefined') {
  2.     document.createStyleSheet = function(href) {
  3.             if(typeof href !== 'undefined') {
  4.                 var element = document.createElement('link');
  5.                 element.type = 'text/css';
  6.                 element.rel = 'stylesheet';
  7.                 element.href = href;
  8.             }
  9.             else {
  10.                 var element = document.createElement('style');
  11.                 element.type = 'text/css';
  12.             }
  13.             console.log( element );
  14.  
  15.             var index = document.styleSheets.length;
  16.             document.getElementsByTagName('head')[0].appendChild(element);
  17.            
  18.             //comprobar si index document.styleSheets tienen los valores correctos
  19.             console.log( index );
  20.             console.log( document.styleSheets );
  21.  
  22.             //devolver referencia a hoja de estilos insertada
  23.             var sheet = document.styleSheets[index];
  24.             return sheet;
  25.     }
Es una función que añado a document tal que si le paso por parametro la localizacion de un fichero css me lo carga. En caso de no pasar ningún parametro me crea un elemento style. La función retorna la hoja de estilos insertada para luego modificarla insertando o removiendo reglas css a voluntad.

La cosa es que soy bastante quisquilloso y me gusta probar si dicha función funciona como debería funcionar para todos los casos. Lastimosamente he encontrado almenos un caso en la que no funciona correctamente:

Código Javascript:
Ver original
  1. window.onload = function() {
  2.     document.createStyleSheet( 'css/test.css' ); // cargar css externo
  3.     var sheet = document.createStyleSheet(); // crear css anonimo
  4.     sheet.insertRule('h1 { color: red; }', 0 );
  5.     console.log( sheet );
  6. }

Aquí el error que me manda por Chrome:

Código BASH:
Ver original
  1. <link type="text/css" rel="stylesheet" href="css/test.css">
  2. 1 insert_text.js:33
  3. StyleSheetList {0: CSSStyleSheet, length: 1, item: function}
  4.  insert_text.js:34
  5. <style type=&#8203;"text/​css">​</style>​
  6.  insert_text.js:27
  7. 1 insert_text.js:33
  8. StyleSheetList {0: CSSStyleSheet, length: 1, item: function}
  9.  Uncaught TypeError: Cannot call method 'insertRule' of undefined

Parece ser que cuando inserto un elemento link o style en head, no se actualiza directamente la lista document.styleSheets. Veo que quizá podría solucionarlo usando el truco de setTimeout( .., 0 ) después de insertar el elemento. Sin embargo este código:
Código Javascript:
Ver original
  1. var sheet = document.styleSheets[index];
  2. return sheet;
debería estar dentro de setTimeout. Y a mi me sobrepasa cómo poder insertar un return dentro de setTimeout.

PD.: Normalmente se aprende mucho de los pequeños baches que te vas encontrando pero para un novato como yo en Javascript esto empieza a parecerme frustrante. Parezco un imán de bugs.

Un saludo y gracias!
  #3 (permalink)  
Antiguo 12/12/2013, 12:40
Avatar de marlanga  
Fecha de Ingreso: enero-2011
Ubicación: Murcia
Mensajes: 1.024
Antigüedad: 13 años, 3 meses
Puntos: 206
Respuesta: Crear hoja de estilo CSS con javascript

Usa callbacks, que para eso están.

Código Javascript:
Ver original
  1. if(typeof document.createStyleSheet === 'undefined') {
  2.                 document.createStyleSheet = function(param){
  3.  
  4.                     var index = document.styleSheets.length;
  5.                     var head=document.getElementsByTagName('head')[0];
  6.                     if(typeof param == 'string')
  7.                     {
  8.                         var element = document.createElement('link');
  9.                         element.type = 'text/css';
  10.                         element.rel = 'stylesheet';
  11.                         element.href = param;
  12.                     }
  13.                     else
  14.                     {
  15.                         var element = document.createElement('style');
  16.                         element.type = 'text/css';
  17.                     }
  18.                     head.appendChild(element);
  19.                     function loaded(){
  20.                         if (typeof param != 'function') return;
  21.                         if (document.styleSheets.length==index)
  22.                         {
  23.                             setTimeout(loaded,1);
  24.                         }
  25.                         else
  26.                         {
  27.                             param(document.styleSheets[index]);
  28.                         }
  29.                     }
  30.                     loaded();
  31.                     console.log( element );
  32.                 }
  33.             }
  34.             window.onload = function() {
  35.                 document.createStyleSheet( 'test.css' );
  36.                 document.createStyleSheet(
  37.                     function(sheet){
  38.                         sheet.insertRule('h1 { color: red; }', 0 );
  39.                     }
  40.                 );
  41.             }
  #4 (permalink)  
Antiguo 13/12/2013, 08:17
 
Fecha de Ingreso: julio-2006
Ubicación: Barcelona
Mensajes: 244
Antigüedad: 17 años, 9 meses
Puntos: 32
Respuesta: Crear hoja de estilo CSS con javascript

Hola marlanga.

Quizá aún no sé como funcionan los callbacks y por eso pregunto algo de perogrullo. Pero al añadir un console.log al final del código para comprobar que document.styleSheets tiene los datos correctos me encuentro que no es así.

Código Javascript:
Ver original
  1. window.onload = function() {
  2.     document.createStyleSheet( 'css/test.css' );
  3.     document.createStyleSheet(
  4.         function(sheet){
  5.             sheet.insertRule('h1 { color: red; }', 0 );
  6.         }
  7.     );
  8.     console.log( document.styleSheets );
  9. }
Esta es la salida de la consola:

Código Javascript:
Ver original
  1. <link type="text/css" rel="stylesheet" href="css/test.css">
  2. <style type=&#8203;"text/​css">&#8203;</style>&#8203;
  3. - StyleSheetList {0: CSSStyleSheet, length: 1, item: function}
  4.    + 0: CSSStyleSheet
  5.    - 1: CSSStyleSheet
  6.       - cssRules: CSSRuleList
  7.          - 0: CSSStyleRule
  8.             cssText: "h1 { color: red; }"
  9.             parentRule: null
  10.             parentStyleSheet: CSSStyleSheet
  11.             selectorText: "h1"
  12.             style: CSSStyleDeclaration
  13.             type: 1
  14.             __proto__: CSSStyleRule
  15.          + 1: CSSStyleRule
  16.          + 2: CSSStyleRule
  17.          + 3: CSSStyleRule
  18.          + 4: CSSStyleRule
  19.          + 5: CSSStyleRule
  20.          + 6: CSSStyleRule
  21.          + 7: CSSStyleRule
  22.          + 8: CSSStyleRule
  23.          length: 9
  24.          __proto__: CSSRuleList
  25.          disabled: false
  26.          href: "http://js.test/css/test.css"
  27.          media: MediaList
  28.          ownerNode: link
  29.          ownerRule: null
  30.          parentStyleSheet: null
  31.          rules: CSSRuleList
  32.          title: null
  33.          type: "text/css"
  34.          __proto__: CSSStyleSheet
  35.       + 2: CSSStyleSheet
  36.          cssRules: CSSRuleList
  37.          length: 0
  38.          __proto__: CSSRuleList
  39.          disabled: false
  40.          href: null
  41.          media: MediaList
  42.          ownerNode: style
  43.          ownerRule: null
  44.          parentStyleSheet: null
  45.          rules: CSSRuleList
  46.          title: null
  47.          type: "text/css"
  48.          __proto__: CSSStyleSheet
  49.          length: 3
  50.          __proto__: StyleSheetList

En la linea 3 ya se ve la primera cosa extraña, pues indica que document.styleSheets.length vale 1. Sin embargo cuando se expande la descripción en la linea 49 se observa que ahora length toma el valor de 3.
En la linea 4 está la hoja de estilos por defecto de Chrome.
En la linea 5 está la hoja de estilos que hacer referencia al fichero css/test.css . Si se expanden la lista de reglas se ve que la primera( linea 7 a 14 ) se corresponde con la regla "h1 { color: red; }" que debería estar insertada en la hoja de estilos anónima.
Sin embargo, en la hoja de estilos anónima(linea 35) no hay ninguna regla insertada.

Un saludo!
  #5 (permalink)  
Antiguo 13/12/2013, 08:51
Avatar de marlanga  
Fecha de Ingreso: enero-2011
Ubicación: Murcia
Mensajes: 1.024
Antigüedad: 13 años, 3 meses
Puntos: 206
Respuesta: Crear hoja de estilo CSS con javascript

Parece que sabes programar. Mirando mi código y teniendo en cuenta las 4 últimas líneas que escribiste en tu segundo post, deberías deducir qué utilidad tienen los callbacks, cómo he implementado uno, y por qué tu último console.log no tiene los datos actualizados.
Por ejemplo ajax también funciona con callbacks. Es una idea, una técnica, que en entre otras cosas se usa para ejecutar código sobre algún elemento o dato que en el momento de tratarlos, aún no existen; no esperes encontrar un "objeto" llamado Callback ni nada parecido.

Última edición por marlanga; 13/12/2013 a las 09:01
  #6 (permalink)  
Antiguo 13/12/2013, 10:44
 
Fecha de Ingreso: julio-2006
Ubicación: Barcelona
Mensajes: 244
Antigüedad: 17 años, 9 meses
Puntos: 32
Respuesta: Crear hoja de estilo CSS con javascript

Yo, por la documentación que estoy viendo de momento, entiendo por callback el hecho de pasar una función como parámetro de otra. Lo que de momento me está costando es encontrar información sobre como los callbacks ayudan a sincronizar ciertos procedimientos. Pues, vaya, el problema que tengo parece ser de sincronización. Claro está que estoy descartando todo enlace de este tipo que se relacione con ajax pues me parece demasiado avanzado y quiero tener una base en javascript antes que entrar a mirar ajax.

De todas manera tengo que repasar y encontrar más información sobre como se implementa el flujo de eventos en javascript. Pues hasta que no tenga esto claro veo que voy a seguir teniendo problemas. Cuando tenga un rato supongo que organizaré mis dudas y si no encuentro información adecuada ya preguntaré algo por aquí.

Gracias.
  #7 (permalink)  
Antiguo 13/12/2013, 11:01
Avatar de marlanga  
Fecha de Ingreso: enero-2011
Ubicación: Murcia
Mensajes: 1.024
Antigüedad: 13 años, 3 meses
Puntos: 206
Respuesta: Crear hoja de estilo CSS con javascript

Es que haces cosas muy raras, entendiendo raro como "poco usual".
¿Cuál es la utilidad de crear CSS con javascript? Eso atenta contra todos los profesionales del diseño y maquetación de páginas webs xd.

Pero el problema no es la rareza de lo que haces, es que insertar algunos tipos de elementos en el DOM realmente hacen operaciones asíncronas. Creo que son scripts y CSS link, que se tienen que hacer dos operaciones: Insertar el nodo en el DOM, que es instantáneo, y procesarlo de forma asíncrona: se carga en memoria y se ejecuta el JS, y el CSS se carga en memoria y se aplican los estilos a los nodos que deban. Ese tiempo de proceso no es instantáneo, y dependerá de la potencia de la máquina que lo hace. No sé por qué no lo hicieron síncrono, tal vez porque cuando se cargan hojas de estilo o ficheros JS, el tiempo que tarde el servidor en devolver los recursos puede ser descabellado, y para no hacer la misma operación de forma síncrona y asíncrona, optaron por hacerlo siempre asíncrono.

Callback es hacer que una función acepte como argumento otra función, lo que permite que la primera función disparare la que le llega como argumento cuando quiera o pueda. jQuery basa casi toda su filosofía en llamadas callback.
En tu caso, tú no puedes insertar reglas CSS a un nodo recién metido, por lo que dije antes de que es asíncrono y tal. Pues con un callback bien pensado solucionas la papeleta y te olvidas. Yo le paso a createStyleSheet una función con las instrucciones de meter las reglas, y createStyleSheet ya las meterá cuando pueda sin que yo tenga que preocuparme.

Última edición por marlanga; 13/12/2013 a las 11:13

Etiquetas: css, estilo, hoja, variable
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 08:26.