2011-11-09 40 views
11

我想動態添加使用javascript CSS樣式表規則,類似例子2 here當一個樣式表添加到document.styleSheets

它工作的大部分時間,但似乎是一個競爭狀態,使得它在(至少)鉻(15.0.874和17.0.933)有時會失敗。緩存爲空時(或已被清除)很少發生。

這裏是我已經能夠縮小它。首先,我通過將外部樣式表附加到<head>,然後創建一個新的樣式表(我將添加規則)。然後我打印document.styleSheets(立即和1秒後)的長度。

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

(在http://jsfiddle.net/amirshim/gAYzY/13/用它玩)

當緩存是明確的,它有時打印2然後4(的jsfiddle增加了它自己的2個css文件),這意味着它不會添加風格任工作表立即到document.styleSheets ...但可能會等待外部文件加載。

這是預期嗎?

如果是這樣,Example 2 on MDN(和其他許多人在那裏)壞了?由於第27行:

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

可能與document.styleSheets.length == 0

注意評估,當我不先加載外部CSS文件,這種情況不會發生。

+1

我想問你你想要的最終結果是什麼。在什麼情況下,你想'注入'一個規則到一個CSS文件,而不是隻寫在CSS文件內的第一個地方? – Sotkra

+0

我也在動態地添加樣式表......但是隻有在$(document).ready已經觸發後... –

+1

@Kees:我給出的代碼是在'$(document).ready'中做所有事情。這就是'$(function(){...});'做的。 – Amir

回答

4

如果JavaScript位於CSS下面的頁面(它幾乎總是),那麼HTML解析器必須等待JS執行,直到JS和CSS完全加載並解析爲止,因爲JS可能會請求樣式信息(Chrome只有當腳本實際做到這一點時才這樣做)。 這幾乎在所有情況下都會有效地加載外部CSS阻塞。 當你稍後通過JavaScript插入它們或頁面中沒有JS'(或JS被加載非阻塞)時,CSS異步加載意味着它們被加載和解析而不會阻​​止DOM的解析。 因此,只有在表單處於DOM內部並且僅在完全加載並解析後纔會更新documents.stylesheets計數。

在這種情況下,有可能是一些涉及時間差異。 考慮到大多數瀏覽器只有有限數量的管道通過它們加載數據(有些只有兩個像IE6,大多數有6個,有些甚至有12個像IE9),樣式表的加載被添加到隊列末尾加載。 瀏覽器仍在加載內容,因爲您在DOMReady上調用了函數。 這會導致樣式表在一秒鐘後未完全加載和解析,因此不會影響document.stylesheets.length。

和所有樣式表的例子我已經在網絡上碰到假設DOM是完全解析和加載。 OffDOM樣式表甚至不允許插入或檢查規則,因爲它們可以具有@import規則,並且必須在外部加載規則,因此對於瀏覽器,很難確定何時可以安全地與表單交互,除非他們完全加載並解析。 OffDOM樣式表確實會公開一個空白圖紙屬性,但不會讓您與該圖紙進行交互,直到該圖紙被添加到DOM中。

我總是發現最好動態地插入樣式表,並在該表中執行所有更改並單獨保留document.stylesheet。 這具有很大的優勢,即當您以相同的特性覆蓋樣式時,由於插入到錯誤的工作表中,您不會遇到麻煩。 由於document.stylesheets是一個活的nodeList,每次調用函數時(除非存儲在var中),document.stylesheets [2]都可以指向另一個表。 所以我傾向於使用動態插入的工作表,只能在那個工作表上工作。

1

這應該有助於: 'When is a stylesheet really loaded'

至於 '實施例2'。如果在調用addStylesheetRules()的時候會出現樣式表加載,當然這是在Chrome中。

+1

因此,示例2並不總是工作。即如果我(或其他js庫)在調用'addStylesheetRules()'之前添加了外部樣式表。 – Amir