2011-11-09 13 views
11

Próbuję dynamicznie dodać regułę arkusza stylów CSS za pomocą javascript, coś jak przykład 2 here.Kiedy jest dodawany arkusz stylów do dokumentu.styleSheets

Działa przez większość czasu, ale wydaje się, że jest to sytuacja wyścigowa, która czasami kończy się niepowodzeniem w (przynajmniej) Chrome (15.0.874 i 17.0.933). Zdarza się to rzadko, gdy pamięć podręczna jest pusta (lub została wyczyszczona).

Oto, co udało mi się zawęzić. Najpierw ładuję zewnętrzny arkusz stylów, dołączając go do <head>, a następnie tworzę nowy arkusz stylów (gdzie będę dodawał reguły). Następnie wydrukuję długość document.styleSheets (natychmiast i po 1 sekundzie).

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

(grać z nim w http://jsfiddle.net/amirshim/gAYzY/13/)

gdy bufor jest jasne, że czasami drukuje 2 następnie 4 (jsfiddle dodaje swoje własne 2 pliki CSS), co oznacza, że ​​nie dodaje ani stylu arkusze do document.styleSheets natychmiast ... ale prawdopodobnie czeka na załadowanie zewnętrznego pliku.

Czy to jest oczekiwane?

Jeśli tak, czy jest Example 2 on MDN (i wiele innych tam) zepsuty? Od linii 27:

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

może oceniać z document.styleSheets.length == 0

Zauważ, że tak się nie stanie, kiedy nie wczytać zewnętrzny plik CSS pierwszy.

+1

Chciałbym zapytać, jaki jest pożądany efekt końcowy. W jakich okolicznościach chciałbyś "wstrzyknąć" regułę do pliku css zamiast po prostu napisać ją w pliku css na pierwszym miejscu? – Sotkra

+0

Również dynamicznie dodajem arkusz stylów ... ale dopiero po tym, jak $ (document) .ready został zwolniony ... –

+1

@Kees: Kod, który podałem, robi wszystko w '$ (document) .ready'. To właśnie robi '$ (function() {...});'. – Amir

Odpowiedz

4

Jeśli JavaScript znajduje się na stronie pod CSS (co prawie zawsze jest), parser HTML musi czekać z wykonaniem JS, aż JS i CSS będą w pełni załadowane i przeanalizowane, ponieważ JS może zażądać informacji o stylizacji (Chrome robi to tylko wtedy, gdy skrypt faktycznie to robi). Skutecznie powoduje to ładowanie zewnętrznego blokowania CSS w prawie wszystkich przypadkach. Po wstawieniu ich później za pomocą skryptu JavaScript lub braku strony JS na stronie (lub ładowanie JS bez blokowania) ładunki CSS są asynchronicznie oznaczane jako załadowane i przeanalizowane bez blokowania parsowania DOM. Dzięki temu dokuments.stheetsheets count jest aktualizowany tylko wtedy, gdy arkusz znajduje się wewnątrz DOM i dzieje się tak tylko po pełnym załadowaniu i przeanalizowaniu.

W tej sytuacji mogą występować pewne różnice w czasie. Biorąc pod uwagę, że większość przeglądarek ma ograniczoną liczbę potoków, przez które ładują dane (niektóre mają tylko dwa, takie jak IE6, większość ma 6, a niektóre nawet 12, jak IE9) ładowanie arkusza stylów jest dodawane na końcu kolejki, aby zostać załadowany. Przeglądarka wciąż ładuje rzeczy, ponieważ wywołujesz funkcję w DOMReady. Powoduje, że arkusz stylów nie jest w pełni załadowany i przeanalizowany sekundę później, co nie ma wpływu na document.stylesheets.length.

Wszystkie przykłady arkuszy stylów, które spotkałem w Internecie, zakładają, że dom jest w pełni przeanalizowany i załadowany. Arkusze stylów OffDOM nie zezwalają nawet na wstawianie lub sprawdzanie reguł, ponieważ mogą mieć reguły @import, a te muszą być ładowane zewnętrznie, więc w przypadku przeglądarek trudno jest określić, kiedy można bezpiecznie korzystać z arkusza, chyba że są w pełni załadowane i przeanalizowane. Arkusze stylów OffDOM przedstawiają pustą właściwość arkusza, ale nie pozwalają na interakcję z nią, dopóki arkusz nie zostanie dodany do DOM.

Zawsze uważałem, że lepiej jest dynamicznie wstawiać arkusz stylów i wykonywać wszystkie zmiany w tym jednym arkuszu, pozostawiając sam dokument.stylesheets. Ma to tę wielką zaletę, że gdy nadpisujesz style o tej samej specyfice, nie będziesz mieć problemów z powodu wstawienia niewłaściwego arkusza. Ponieważ dokument.stylesheets jest Live node, program document.stylesheets [2] może wskazywać na inny arkusz za każdym razem, gdy wywołasz funkcję (chyba że jest ona zapisana w var). Dlatego używam dynamicznie wstawianego arkusza i operuję tylko na tym.

1

Powinno to: 'When is a stylesheet really loaded'

jak dla przykładu 2 ''. Zerwie się, jeśli podczas ładowania wywołania metody addStylesheetRules() będzie ładowany arkusz stylów, oczywiście w przeglądarce Chrome.

+1

Przykład 2 nie zawsze działa. tj. jeśli I (lub inna biblioteka js) właśnie dodała zewnętrzny arkusz stylów przed wywołaniem 'addStylesheetRules()'. – Amir

Powiązane problemy