CSS Expression是自IE5开始提供的特性,虽然因安全性、性能问题臭名昭著,到IE8也终于
寿终正寝。回过头看,与XMLHttpRequest一样,CSS Expression的理念确实也有先驱之功,从CSS Expression也可看出由jQuery发扬光大的用CSS selector绑定行为的编程方式的雏形。不过雏形只能是雏形。由于设计上的缺陷,CSS Expression不堪大用,通常只局限为patch一些CSS特性,例如min-width/max-width。
不过CSS Expression在patch IE方面其实还可以发挥更大的功用。Dean Edwards首创了
一次性执行experssion的模式,巧妙的利用了IE的内建Selector机制,同时又避免了experssion被反复计算的性能问题。这种模式被许多patch所使用。例如Peter Nederlof的
hover/active/focus伪类补丁。
但是这个模式仍然有不足。Dean使用的是behavior属性。而单个CSS属性只能被用一次,即在一个元素上,最后根据cascade规则只会有一个behavior声明会胜出,因此你无法为一个元素同时启用多个特性(即调用多个行为)。
Peter Nederlof因为要绑定三个行为(分别对应于三个伪类),因此征用了3个不常用的css property(text-kashida, text-kashida-space, text-justify)。
显然,可以征用的css属性是很有限的(比方说你不能把background这样常用的属性给搞坏了,所以西方人也就是会欺负一下日本人专用的CSS属性)。如果能使用任意自定义的css属性的话,就好了。实际上IE对于不认识的property也是可以通过currentStyle返回其cascade之后的值的,而且expression对于自定义property也是有效的。
但是custom property存在一些问题:
1. 无法用runtimeStyle来override自定义属性
2. 即使删除包含expression的stylesheet,expression仍然有效
3. 在expression调用的方法里也不能调用removeExpression来强行删除表达式(会扔异常)
下面我讲一下我对这个问题的研究和解决方法。
根据我的研究,expression的机制与普通CSS属性不同,是设置在每个元素的style上的。
span {
behavior: expression(test1(this));
pie-test: expression(test2(this));
}
通常我们可以从currentStyle.propName来得到属性值,但是这样只是得到计算后的结果,且currentStyle上并无getExpresssion方法。但是调用span.style.getExpression('behavior')或('pie-test')会得到'test1(this)'和'test2(this)'
因此可以认为,对于这个rule,相当于对每个span都调用了一次 .style.setExpression('behavior', 'test1(this)') 以及 .style.setExpression('pie-test', 'test2(this)')
且通过对应的 .style.removeExpression 可以清除expression。
但是方法调用有一个限制,就是如果当前在expression所调用的函数(这里就是test2()函数)中,是不能调用 .style.set/removeExpression 方法的,会扔出异常。
设置runtimeStyle.behavior时,也会清除expression,相当于调用了style.removeExpression('behavior'),但是没有上面描述的限制。然而对于自定义属性无效。甚至任何时候runtimeStyle.setExpression('pie-test', null),也不会覆盖style上已经设定的expression。
以上。
显然一个解决方案是在expression之外调用 .style.removeExpression 。
示例代码:
function test2(e) {
setTimeout(function () {
e.style.removeExpression('pie-test')
}, 1)
...
}
这是有效的。问题是定时器只能保证最终自定义属性上的expression会被移除,但是不能确保expression只被执行一次(实测下来会执行多少次是不确定的,一次到数次都有可能)。
当然,我们可以给每个元素加上标志位来判断是否已经执行过,不过这还是挺麻烦的。
另一个解决方案是先把元素存起来,然后统一删除expression。
示例代码:
var spans = []
function test(e) {
spans.push(e)
...
}
<head>
...
<script defer>
for (var i = 0; i < spans.length; i++)
spans[i].style.removeExpression('pie-test')
spans = []
</script>
经过实测defer的script能确保正好执行一次。不过有趣的是如果打印spans.length会发现是在不断增加的,也就是并非所有元素上的test2执行完成后才执行defer的脚本,而是恰好一次test2,一次循环。这个也太巧合了,我对这个行为吃不太准。另外这个方式不能应对后续动态加入的匹配元素,丧失了使用css expression的最大好处之一。
最终的方案是利用CSS的规则。
实际上不是所有expression都会被反复执行。IE其实有基本的优化,比如对于expression(0)就只会计算一次,不会反复求值,因为很容易判断该值是不会变化的。
虽然如前所述不能在test2里直接调用 .style.setExpression ,但是可以通过改变match条件来override expression,如示例代码:
<style>
span {
pie-test: expression(test2(this));
}
span.pie-test {
pie-test: expression(true);
}
</style>
<script>
function test2(e) {
e.className += ' pie-test'
...
}
</script>
经过测试该方式可以完美达到只执行一次的目标!
该方法还有个好处,如果要再次执行test2,只需要从元素的class中删除pie-test即可。
后续的blog中我会展示一下使用这个模式来给IE打一些重要的特性补丁。
分享到:
相关推荐
- **定期更新和打补丁**:保持系统及软件版本最新,及时修复已知的安全漏洞。 综上所述,虽然利用CSS中的`v:expression`属性能够有效地帮助我们防御iframe挂马攻击,但考虑到其局限性和潜在的安全隐患,开发者在...
人脸识别项目实战
内容概要:本文详细描述了一个完整的Web应用程序的开发过程。该项目主要采用了Hono作为服务器框架,Prisma作为ORM工具,JWT用于认证鉴权,以及一系列现代化的最佳实践确保系统的健壮性和安全性。项目初期构建了基础架构,并设置了必要的依赖和工具。在后端方面涵盖了公共API接口的设计、CRUD增删改查逻辑、用户认证和授权等功能。此外还特别关注到了API的安全保护,如输入输出的校验,跨站请求伪造CSRF的防范,XSS防御等措施;为确保代码的质量引入了代码检测(比如ESLint搭配Prettier),并建立了完善的测试框架以保障后续开发阶段的功能正确。对于可能出现的问题预先定义了一组规范化的异常响应,并提供OpenAPI文档以方便开发者理解和调用。数据存储层面上利用了关系型与非关系型数据库各自的特性,实现了数据的有效组织,最后提供了实用的脚本,可用于种子数据插入以及执行必要的初始化工作。 适合人群:面向具有一定JavaScript/TypeScript开发经验,尤其是Node.js后台服务搭建经验的中级程序员和技术团队。 使用场景及目标:这份材料非常适合那些需要快速建立安全高效的RES
【资源介绍】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,也可以作为小白实战演练和初期项目立项演示的重要参考借鉴资料。 3、本资源作为“学习资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研和多多调试实践。 掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip掌静脉识别算法源码(门禁).zip
手势识别项目实战
(参考GUI)MATLAB BP的交通标志系统.zip
人脸识别项目实战
内容概要:本文详细介绍了 C++ 函数的基础概念及其实战技巧。内容涵盖了函数的基本结构(定义、声明、调用)、多种参数传递方式(值传递、引用传递、指针传递),各类函数类型(无参无返、有参无返、无参有返、有参有返),以及高级特性(函数重载、函数模板、递归函数)。此外,通过实际案例展示了函数的应用,如统计数组元素频次和实现冒泡排序算法。最后,总结了C++函数的重要性及未来的拓展方向。 适合人群:有一定编程基础的程序员,特别是想要深入了解C++编程特性的开发人员。 使用场景及目标:① 学习C++中函数的定义与调用,掌握参数传递方式;② 掌握不同类型的C++函数及其应用场景;③ 深入理解函数重载、函数模板和递归函数的高级特性;④ 提升实际编程能力,通过实例强化所学知识。 其他说明:文章以循序渐进的方式讲解C++函数的相关知识点,并提供了实际编码练习帮助理解。阅读过程中应当边思考边实践,动手实验有助于更好地吸收知识点。
Comsol光学仿真模型:包括纳米球 柱 Mie散射多级分解 ,Comsol光学仿真模型; 纳米球; 柱; Mie散射; 多级分解,Comsol光学仿真模型:纳米结构Mie散射多级分解
永磁同步电机全速域控制高频方波注入法、滑模观测器法SMO、加权切矢量控制Simulink仿真模型 低速域采用高频方波注入法HF,高速域采用滑膜观测器法SMO,期间采用加权形式切 送前方法 1、零低速域,来用无数字滤波器高频方波注入法, 2.中高速域采用改进的SMO滑模观测器,来用的是sigmoid函数,PLL锁相环 3、转速过渡区域采用加权切法 该仿真各个部分清晰分明,仿真波形效果良好内附详细控制方法资料lunwen 带有参考文献和说明文档,仿真模型 ,核心关键词: 1. 永磁同步电机; 2. 全速域控制; 3. 高频方波注入法; 4. 滑模观测器法SMO; 5. 加权切换矢量控制; 6. Simulink仿真模型; 7. 零低速域控制; 8. 中高速域控制; 9. 转速过渡区域控制; 10. 仿真波形效果; 11. 详细控制方法资料; 12. 参考文献和说明文档。,永磁同步电机多域控制策略的仿真研究
基于蜣螂优化算法的无人机三维路径规划【23年新算法应用】可直接运行 Matlab语言 主要内容:读取地形数据,利用蜣螂算法DBO优化三维路径,目标函数为总路径最短,同时不能撞到障碍物,效果如图所示,包括迭代曲线图、三维路径图、二维平面图等等 ,基于蜣螂优化算法;无人机;三维路径规划;总路径最短;障碍物避免;Matlab语言;迭代曲线图;三维路径图;二维平面图,蜣螂算法优化无人机三维路径规划:实时避障、路径最短新应用
清华大学2024年研究生复试上机考试题.zip
南京理工大学研究生入学考试2011年复试上机试题
手势识别项目实战
这里是3501的内容,用于复习资料
异步电动机变压变频调速系统,包含六千多字的文档、框架图、Simulink仿真模型,电力拖动、电机控制仿真设计 仿真模型+报告 开关闭环对比仿真都有,资料如图所见如所得 ,异步电动机;变压变频调速系统;六千字文档;框架图;Simulink仿真模型;电力拖动;电机控制仿真设计;开闭环对比仿真;资料如图。,异步电机控制仿真系统:六千字详解与图解
人脸识别项目实战
手势识别项目实战
人脸识别项目实战
c语言学习