2011-11-09 8 views
11

Sto provando ad aggiungere dinamicamente una regola del foglio di stile CSS utilizzando javascript, ad esempio l'esempio 2 here.Quando è aggiunto un foglio di stile a document.styleSheets

Funziona la maggior parte del tempo, ma sembra che ci sia una condizione di competizione che a volte fallisce in (almeno) Chrome (15.0.874 e 17.0.933). Succede raramente quando la cache è vuota (o è stata cancellata).

Ecco a cosa sono riuscito a restringerlo. Per prima cosa carico un foglio di stile esterno aggiungendolo a <head> e poi creo un nuovo foglio di stile (dove aggiungerei le regole). Quindi stampo la lunghezza di document.styleSheets (immediatamente e dopo 1 secondo).

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

(giocare con lui a http://jsfiddle.net/amirshim/gAYzY/13/)

Quando la cache è chiaro, a volte stampa 2 poi 4 (jsfiddle aggiunge che è proprio 2 file CSS), il che significa che non aggiunge né dello stile fogli a document.styleSheets immediatamente ... ma probabilmente attende il caricamento del file esterno.

È previsto?

Se sì, è Example 2 on MDN (e molti altri là fuori) rotto? Dal momento che la linea 27:

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

potrebbe valutare con document.styleSheets.length == 0

Si noti che questo non succede quando non caricare il file CSS esterno prima.

+1

Mi piacerebbe chiederti qual è il risultato finale desiderato. In quali circostanze vorreste "iniettare" una regola in un file css invece di averlo scritto all'interno del file css al primo posto? – Sotkra

+0

Aggiungo dinamicamente anche il foglio di stile ... ma solo dopo che $ (document) .ready ha sparato ... –

+1

@Kees: Il codice che ho dato sta facendo tutto in '$ (document) .ready'. Questo è ciò che '$ (function() {...});' does. – Amir

risposta

4

Se JavaScript è nella pagina sotto il CSS (che è quasi sempre) il parser HTML deve attendere con l'esecuzione di JS fino a quando JS e CSS sono completamente caricati e analizzati a causa del fatto che JS potrebbe richiedere informazioni sullo stile (Chrome solo così quando lo script lo fa comunque). Questo rende in effetti il ​​caricamento del blocco CSS esterno in quasi tutti i casi. Quando li inserisci in seguito tramite JavaScript o non ci sono JS 'nella pagina (o il JS è caricato non bloccante) CSS carica in modo asincrono, significa che sono caricati e analizzati senza bloccare l'analisi del DOM. Quindi il conteggio di documents.stylesheets viene aggiornato solo dopo che il foglio si trova all'interno del DOM e ciò accade solo dopo che è stato caricato e analizzato completamente.

In questa situazione potrebbero esserci alcune differenze temporali. Considerando che la maggior parte dei browser ha solo un numero limitato di pipe attraverso cui caricano i dati (alcuni ne hanno solo due come IE6, la maggior parte ne ha 6 e alcuni ne hanno addirittura 12 come IE9) il caricamento del foglio di stile viene aggiunto alla fine della coda caricato. Il browser sta ancora caricando le cose perché si chiama la funzione su DOMReady. Quali risultati nel foglio di stile non vengono caricati e analizzati completamente un secondo dopo, quindi non influenzano document.stylesheets.length.

E tutti gli esempi di fogli di stile che ho eseguito sul Web presuppongono che dom sia completamente analizzato e caricato. I fogli di stile OffDom non consentono nemmeno l'inserimento o il controllo delle regole, poiché possono avere le regole @import e quelle devono essere caricate esternamente, quindi per i browser è piuttosto difficile determinare quando è sicuro interagire con il foglio a meno sono completamente caricati e analizzati. I fogli di stile OffDOM espongono una proprietà di un foglio vuoto ma non consentono di interagire con esso fino a quando il foglio non è stato aggiunto al DOM.

Ho sempre trovato preferibile inserire un foglio di stile in modo dinamico ed eseguire tutte le modifiche in quel foglio e lasciando solo i file document.styles. Questo ha il grande vantaggio che quando si sostituiscono gli stili con la stessa specificità non si avranno problemi a causa dell'inserimento nel foglio sbagliato. Poiché document.stylesheets è un nodo vivo, document.stylesheets [2] può puntare a un altro foglio ogni volta che si chiama la funzione (a meno che non sia memorizzato in una var). Quindi tendo ad usare un foglio inserito dinamicamente e ad operare solo su quello.

1

Questo dovrebbe aiutare: 'When is a stylesheet really loaded'

Per quanto riguarda 'Esempio 2'. Si interromperà se c'è un caricamento di fogli di stile quando chiami addStylesheetRules(), ovviamente in Chrome.

+1

Quindi l'Esempio 2 non funziona sempre. Ad esempio, se I (o un'altra libreria js) ha appena aggiunto un foglio di stile esterno prima di chiamare 'addStylesheetRules()'. – Amir

Problemi correlati