#靈感筆記#關於增強IE對CSS選擇符的支援

來源:互聯網
上載者:User

雖然在官方規範之中,HTML有版本,CSS有層級,但實踐當中無所謂版本層級,關鍵是看瀏覽器是否支援。

如IE6不支援CSS子項目選擇符,就非常令人沮喪。
雖有其它替代方案,比如給HTML元素都加上類名,但那樣代碼量會增加不少,而且不能很好的利用HTML元素語義。

目前有一個第三方js庫 Selectivizr(http://selectivizr.com/),目前的版本v1.0.2,可增強IE對很多CSS3的偽類選擇符及屬性選擇符的支援效果,需要配合一些“第四方”js庫(如jQuery)來使用。
其原理大概如此:分析當前頁面載入的外部樣式表URL,通過ajax重新讀取這些樣式表,將其中IE6不支援的選擇符替換成特定的類名,同時給其對應的HTML元素也加上此類名,最後將修改過的樣式表附加到文檔。
不足之處:
1.只能處理外部樣式表,頁面內嵌的<style></style>元素未做處理。
2.需要通過ajax重新載入一次樣式表,不必要的資源消耗。
3.對於複雜的選擇符,只用一個簡單的類名代替,原有的CSS優先順序權重關係被嚴重破壞。
4.修改過的樣式表破壞了原有的順序,也有可能影響到優先順序。
5.關鍵是它目前還不支援在IE6中使用子項目選擇符“E>F”

下面討論如何來進一步增強IE的選擇符支援
IE提供了一些DOM API來訪問CSS規則(CSS Rules),代碼形式大致如下:

document.styleSheets // 擷取當前文檔的全部樣式表,包括外部和頁內的document.styleSheets[0].rules // 擷取某個樣式表的全部規則document.styleSheets[0].rules[0].selectorText // 擷取樣式規則的選擇符文本(MS官方DHTML手冊說明為可讀寫,但實際上寫操作未實現)document.styleSheets[0].rules[0].style.cssText // 擷取樣式規則的內容document.styleSheets[0].removeRule([index]); // 移除一條樣式規則document.styleSheets[0].addRule(selector, cssText, [index]); // 增加一條樣式規則

利用這些API,前面提到的Selectivizr不足點1,2,好像都可以避免,但它為何沒有這麼做呢?
可能原因是:對於IE不支援的選擇符,rule.selectorText會返回“UNKNOW”或者包含“unknow”的字串。
所以無法用此API得知原始的選擇符文本。

但是IE又有另一個特點:對於它不支援的樣式規則內容,基本上會保持原始文本。例如

<style type="text/css">:my-pseudo-class {foo: bar;}[attr] {selector: [attr];}</style><script type="text/javascript">alert(document.styleSheets[0].rules.length);alert(document.styleSheets[0].rules[0].selectorText); // :unknowalert(document.styleSheets[0].rules[0].style.cssText); // foo: baralert(document.styleSheets[0].rules[1].selectorText); // UNKNOWalert(document.styleSheets[0].rules[1].style.cssText); // selector: [attr]</script>

所以在新方案中,可以採取一個折中的辦法來解決前面的1、2點不足:
首先擷取選擇符:
約定一種格式(樣式屬性名稱),利用css hack來記錄選擇符,比如:“selector: body>nav”;
遍曆rule,通過rule.style.cssText擷取規則內容,並解析selector(如果不包含selector屬性則跳過)。

然後分析選擇符並建立新類名進行選擇符替換:
對於有“包含選擇符”(E F)關係的複雜選擇符,按照包含的層次關係,將其劃分為多個段;
對每個段依次進行分析,如果IE6完全支援,則不作處理;
如果某個段包含IE6不支援的偽類(:pseudo-class)、屬性([attr])、關係(E>F,E+F,E~F)、多類名(.cls1.cls2)等選擇符,則建立一個新的類名對應此段,同時給相應的HTML元素加上新類名(可利用“第四方”庫來完成);
各段處理完成之後,按照其原有的順序重新組合成一個新的“包含選擇符”,通過removeRule()和addRule()來替換原有規則。
對於無“包含”關係的選擇符,可以直接採取建立新類名替換的辦法處理。
至此,前面的3、4、5點不足也基本解決。

新方案優點:

1.支援頁內樣式和外部樣式。
2.盡量減少了對複雜選擇符替換造成的優先順序權重影響。
3.可擴充性好,可以支援未來可能出現的新型選擇符。

新方案缺點:

1.使用了css hack,樣式代碼增加了體積;
2.需要預先判斷哪些selector是IE不支援的,維護可能會帶來一點小麻煩(需要hack的selector必須寫兩遍),不過也許可以通過一些自動化指令碼來處理。

需要進一步最佳化的方向:
文檔內容動態變化之後,需要重新審查文件項目與新類名的關聯關係。
需要針對IE6~8不同版本進行最佳化。

擴充思考:
調研的時候考慮過,其它非IE瀏覽器是否也可以使用類似的hack辦法來實現一些瀏覽器本身不支援的“選擇符”,不過暫時未發現通過API能方便讀取hack寫法的方法;唯一可以利用的倒是font-family屬性——可以包含各種字元,易於讀取,也能被瀏覽器選擇性忽略的屬性。

PS:IE選擇符支援情況簡單測試法。

<script type="text/javascript">function isSupportSelector(selector) {var head = document.getElementsByTagName('head')[0];var style = document.createElement('style');head.appendChild(style);style.styleSheet.cssText = selector+'{}';// alert(style.styleSheet.cssText);var support = !/unknow/i.test(style.styleSheet.cssText);head.removeChild(style);return support;}alert(isSupportSelector('nav a'));alert(isSupportSelector('nav:first-child'));alert(isSupportSelector('nav:first-child a'));alert(isSupportSelector('.cls1.cls2')); // 多類名檢測不到,待改進</script>

PS:關於selector的解析,可以參考jQuery/Sizzle源碼中的chunkerRegex。

PS:暫只記錄想法,無完整代碼實現。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.