2011-11-09 16 views
11

Estoy intentando agregar dinámicamente una regla de hoja de estilo css mediante javascript, algo así como el ejemplo 2 here.Cuándo se agrega una hoja de estilo a document.styleSheets

Funciona la mayor parte del tiempo, pero parece haber una condición de carrera que hace que falle a veces en (al menos) Chrome (15.0.874 y 17.0.933). Ocurre con poca frecuencia cuando el caché está vacío (o ha sido borrado).

Esto es lo que he podido limitar a. Primero cargo una hoja de estilo externa adjuntándola al <head> y luego creo una nueva hoja de estilo (donde agregaría las reglas). Luego imprimo la longitud de document.styleSheets (inmediatamente y después de 1 segundo).

$(function() { 
    // it doesn't happen if this line is missing. 
    $("head").append('<link rel="stylesheet" type="text/css"'+ 
        'href="/css/normalize.css" />'); 

    var stylesheet = document.createElement("style"); 
    stylesheet.setAttribute("type", "text/css"); 
    document.getElementsByTagName('head')[0].appendChild(stylesheet); 

    var b = $('body'); 
    b.append(document.styleSheets.length).append('<br/>'); 
    setTimeout(function() { 
     b.append(document.styleSheets.length).append('<br/>'); 
    }, 1000); 
}); 

(jugar con él en http://jsfiddle.net/amirshim/gAYzY/13/)

Cuando la caché está claro, a veces se imprime 2 continuación 4 (jsFiddle añade que es propio 2 archivos CSS), lo que significa que no añade ninguna de estilo hojas a document.styleSheets inmediatamente ... pero probablemente espera a que se cargue el archivo externo.

¿Se espera esto?

Si es así, ¿está roto el Example 2 on MDN (y muchos otros)? Desde la línea 27:

var s = document.styleSheets[document.styleSheets.length - 1]; 

podría evaluar con document.styleSheets.length == 0

Tenga en cuenta que esto no sucede cuando no cargar el archivo CSS externo en primer lugar.

+1

Me gustaría preguntarle cuál es su resultado final deseado. ¿En qué circunstancias desearía 'insertar' una regla en un archivo css en lugar de simplemente escribirla dentro del archivo css en primer lugar? – Sotkra

+0

Estoy agregando hojas de estilo dinámicamente también ... pero solo después de que el $ (documento) .ready haya disparado ... –

+1

@Kees: El código que di está haciendo todo en '$ (document) .ready'. Eso es lo que '$ (function() {...});' hace. – Amir

Respuesta

4

Si JavaScript está en la página debajo del CSS (que casi siempre es), el analizador HTML debe esperar con ejecución JS hasta que JS y CSS estén completamente cargados y analizados por el hecho de que JS podría solicitar información de estilo (Chrome solo lo hace cuando el script realmente hace esto). Esto hace que la carga del bloqueo de CSS externo sea efectiva en casi todos los casos. Cuando los inserta más tarde mediante JavaScript o no hay JS 'en la página (o el JS se carga sin bloqueo) CSS se carga de forma asíncrona, lo que significa que se cargan y analizan sin bloquear el análisis del DOM. Por lo tanto, el recuento documentos.stylesheets solo se actualiza después de que la hoja está dentro del DOM y eso solo ocurre después de que se haya cargado y analizado por completo.

En esta situación, puede haber algunas diferencias de tiempo involucradas. Considerando que la mayoría de los navegadores solo tienen un número limitado de conductos a través de los cuales cargan datos (algunos tienen solo dos como IE6, la mayoría tiene 6 y algunos tienen 12 como IE9) la carga de la hoja de estilos se agrega al final de la cola cargado. El navegador todavía está cargando cosas porque usted llama a funcionar en DOMReady. Lo que hace que la hoja de estilos no se cargue por completo y se analice un segundo después, por lo que no afecta al document.stylesheets.length.

Y todos los ejemplos de hojas de estilo que me he encontrado en la web suponen que el dom se analiza y se carga por completo. Las hojas de estilo OffDOM ni siquiera permiten que las reglas se inserten o verifiquen porque pueden tener reglas @import y tienen que cargarse externamente, por lo que para los navegadores es muy difícil determinar cuándo es seguro interactuar con la hoja a menos que están completamente cargados y analizados. Las hojas de estilo OffDOM exponen una propiedad de hoja vacía pero no le permiten interactuar con ella hasta que la hoja se haya agregado al DOM.

Siempre me ha parecido mejor insertar una hoja de estilo dinámicamente y ejecutar todos los cambios en esa hoja y dejar el document.stylesheets solo. Esto tiene la gran ventaja de que al anular estilos con la misma especificidad, no tendrá problemas debido a la inserción en la hoja incorrecta. Como document.stylesheets es una lista de nodos activa, document.stylesheets [2] puede señalar a otra hoja cada vez que llame a la función (a menos que esté almacenada en una var). Así que tiendo a usar una hoja insertada dinámicamente y solo operar en esa.

1

Esto debería ayudar: 'When is a stylesheet really loaded'

cuanto a 'Ejemplo 2'. Se romperá si hay carga de hoja de estilo cuando llamas a addStylesheetRules(), por supuesto que está en Chrome.

+1

Así que el ejemplo 2 no siempre funciona. es decir, si yo (u otra biblioteca js) acaba de agregar una hoja de estilo externa antes de llamar a 'addStylesheetRules()'. – Amir

Cuestiones relacionadas