#灵感笔记#关于增强IE对CSS选择符的支持

5 篇文章 0 订阅
4 篇文章 0 订阅
本文探讨了如何使用Selectivizr库增强IE对CSS3选择符的支持,以及新方案来处理IE不支持的选择符,包括分析选择符、创建新类名和替换规则,以解决资源消耗、优先级破坏等问题。同时,提出了新方案的优点、缺点和优化方向,以及对其他非IE浏览器的思考。
摘要由CSDN通过智能技术生成

虽然在官方规范之中,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); // :unknow
alert(document.styleSheets[0].rules[0].style.cssText); // foo: bar
alert(document.styleSheets[0].rules[1].selectorText); // UNKNOW
alert(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源码中的chunker正则表达式。

PS:暂只记录想法,无完整代码实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值