YAOHAIXIAO.COM

HTML(5),CSS(3),JavaScript,DOM,Ajax,JSON,Front-end technologies & Yaohaixiao

热门标签:JavaScript Performance 前端开发 前端性能优化 原创

Rss

Home » Frontend » CSS » CSS Expression

CSS Expression

网友 Huugle 在《CSS 实用技巧 — 利用 Position 定位,让 DIV 元素在浏览器窗口居中》评论说 IE6 中可以使用 CSS Expression 来处理固定定位问题。所以这里我在整理一些关于 CSS Expression 的资料。

CSS Expression 简介

CSS Expression,动态 CSS 属性。IE 私有,自 IE 5.0 开始引入(IE8 将不再支持),详细参考MSDN

CSS Expression 用来把 CSS 属性和 Javascript 表达式关联起来,这里的 CSS 属性可以是 CSS 元素固有的属性,也可以是自定义属性。就是说 CSS 属性后面可以是一段 Javascript 表达式,CSS 属性的值等于 Javascript 表达式计算的结果。 在表达式中可以直接引用元素自身的属性和方法,也可以使用其他浏览器对象。这个表达式就好像是在这个元素的一个成员函数中一样。

CSS Expression 优点和缺点:

优点:
使 CSS 属性动态生成,所以基本 js 能干的它都能干;
使用 CSS 选择符,比 JavaScript 遍历到某个特定元素要方便得多;
缺点:
expression 会反复执行,有严重的效率问题。它的触发似乎不是通过事件,而是通过 interval 一类的机制;
别的浏览器不支持,IE8 也将不再支持;

CSS Expression 的应用

给元素固有属性赋值

下面是定义 container 容器的宽度,如果<725就为自己的宽度,否则就等于725,相当于 max-width:725px;。

<style type="text/css" media="screen">
#container { width: expression((documentElement.clientWidth < 725) ? "725px" : "auto" ); }
</style>

给元素自定义属性赋值

粗看或许还体现不出采用 expression 的优势,但如果你的页面上有几十甚至上百个链接,这时的你难道还会机械式地 Ctrl+C,Ctrl+V 么,何况两者一比较,哪个产生的冗余代码更多呢?采用 expression 的做法如下:

<style type="text/css">
a {star : expression(onfocus=this.blur);}
</style>
<a href="link1.htm">link1</a>
<a href="link2.htm">link2</a>
<a href="link3.htm">link3</a>

说明:里面的star就是自己任意定义的属性,你可以随自己喜好另外定义,接着包含在 expression() 里的语句就是 JavaScript 脚本,在自定义属性与 expression 之间可别忘了还有一个引号,因为实质还是 CSS,所以放在 style 标签内,而非 script 内。OK,这样就很容易地用一句话实现了页面中的链接虚线框的消除。不过你先别得意,如果触发的特效是 CSS 的属性变化,那么出来的结果会跟你的本意有差别。例如你想随鼠标的移进移出而改变页面中的文本框颜色更改,你可能想当然的会认为应该写为:

<style type="text/css">
input {star : expression(onmouseover=this.style.backgroundColor="#F5F5F5";
onmouseout=this.style.backgroundColor="#FFFFFF")}
</style>
<input type="text">
<input type="text">
<input type="text">

可结果却是出现脚本出错,正确的写法应该把 CSS 样式的定义写进函数内,如下所示:

<style type="text/css">
input {star : expression(onmouseover=function()
{this.style.backgroundColor="#FF0000"},
onmouseout=function(){this.style.backgroundColor="#FFFFFF"}) }
</style>
<input type="text">
<input type="text">
<input type="text">

IE 中比较实用的应用

IE6 的背景闪烁 Bug Fix

body {
    zoom: expression(function(el){
    document.execCommand('BackgroundImageCache', false, true);
    el.style.zoom = '1';
    }(this));
}

给不同 type 的 input 赋予不同的样式

input {
    zoom: expression(function(el){
        el.style.zoom = "1";
        el.className ? el.className+=" "+el.type : el.className=el.type;
    }(this));
}

隔行换色(zebra lists)

.test {
    unicode-bidi: expression(function(el){
        el.style.unicodeBidi = "normal";
        var childs = el.getElementsByTagName("li");
        for(var i=0; i

模拟 :before 或者 :after

.test {
    letter-spacing: expression(function(el){
        el.style.letterSpacing = "0";
        var newchild = document.createElement("span");
        newchild.className="after";
        newchild.appendChild(document.createTextNode(" World!"));
        el.appendChild(newchild);
    }(this));
}

模拟图片的:max-width 和 max-height (或 min-width 和 min-height)

.max-width span img {
    max-width:120px;
    max-height:120px;
    zoom:expression(function(el){
        el.style.zoom = "1";
  
        var resizeImg = function() {
            if (el.width > 120 || el.height > 120) {
                if (el.width > el.height) {
                    el.width = "120";
                    el.height = el.height * (el.width / 120);
                } else {
                    el.height = "120";
                    el.width = el.width * (el.height / 120);
                }
            }
        }
  
        if (el.complete) {
            resizeImg();
        } else {
            el.onload = function() {
                resizeImg();
            }
        }
    }(this));
}

IE6的:hover

.ie6-hover input:hover, .ie6-hover .h {
    border:1px solid red;
}
.enable-ie6-hover input {
    _zoom:expression(function(el){
        el.style.zoom = "0";
        el.onmouseenter = function() {
            el.className = "h";
        };
        el.onmouseleave = function() {
            el.className = "";
        };
    }(this));
}

IE6 下的 line-height bug

.ie6-line-height-bug { background:#f2f2f2; line-height:50px; zoom:1; }
.ie6-line-height-bug-fixed input {
    _zoom: expression(function(el){
        el.style.zoom = "1";
        var iefixer = document.createElement("b");
        iefixer.style.zoom = 1;
        el.parentNode.insertBefore(iefixer, el);
    }(this));
}

为什么尽量不要使用 CSS Expression

我们拿隔行换色这个小示例来说明吧:

background-color: expression( (new Date()).getHours()%2 ? "#F00" : "#00F" );

上面的代码是使用 CSS Expression,实现隔一个小时切换一次背景颜色。

CSS Expression的问题就在于它的计算频率要比想象的多出很多。不仅仅是在页面显示和缩放时,就是在页面滚动、乃至移动鼠标时都会要重新计算一次。给 CSS Expression 增加一个计数器可以跟踪表达式的计算频率。在页面中随便移动鼠标都可以轻松达到10000次以上的计算量。

一个减少 CSS Expression 计算次数的方法就是使用一次性的表达式,它在第一次运行时将结果赋给指定的样式属性,并用这个属性来代替 CSS Expression。

如果样式属性必须在页面周期内动态地改变,使用事件句柄来代替CSS表达式是一个可行办法。如果必须使用CSS Expression,一定要记住它们要计算成千上万次并且可能会对你页面的性能产生影响。不要让您的用户感觉打开你的页面,机器会变的很慢。

CSS Expression 的优化

前面提到 IE 浏览器中 CSS Expression 的最大的问题:会反复执行,每秒钟可能执行了成百上千次,有严重的性能问题。那么,如何对 CSS Expression 进行优化呢?

old9 在 《CSS Expression Reloaded》一文中提供了一个解决方案:

CSS Expression 语句体里,将触发该 Expression 的 CSS 属性重置。

他的意思就是:将 CSS Expression 在匹配的元素中仅执行一次。这样以来性能将会提升很大,例如:

div {
    zoom: expression(function(el){el.style.zoom = "1"; alert(el.tagName);}(this));
}

这里我还想补充几点:

  • CSS Expression 执行在任意一个匹配的元素上。
  • CSS expression 内, “this”关键字指向当前匹配的 HTML 元素。
  • CSS 属性选用一些不常用的属性来触发,触发完重置回默认值。

最近在 Ajaxian 的文章《Creating a querySelector for IE that runs at “native speed”》 中看到作者 Dion Almaer 也提供了一个类似的解决方式:

div {
    -singlex: expression(this.singlex ? 0 : (function(t) { alert(t.tagName); t.singlex = 0; } )(this));
}

但此代码并没有完全解决 CSS Expression 最大的性能问题,因为每次触发还是要去执行 Expression 脚本。甚至你可以滚动下你鼠标的中间滚轮,意向不到的问题将会发生。

强调:仅是对 CSS Expression 做了优化,但并未说 CSS Expression 就不存在其他方面的问题。

使用 CSS Expression 的忠告

尽量不要使用 CSS Expression,如果必须使用 CSS Expression,一定要清楚它成千上万次的计算对你页面的性能产生影响,甚至导致“Visual C++ Runtime library”这样的严重错误。

我知道对于初学者,CSS Expression 的一些特性视乎非常的有吸引力,我自己当初也很热衷于此,不过代价也是惨痛的,已经介绍了,就不多说了。我这里介绍 CSS Expression 是为了让大家了解这个知识点,就像学JavaScript 时我们也学过 with 语句,eval 和 Function 对象创建函数一样,知道了它的可怕就应该敬而远之。

说明:本文引用的一些示例均来自网上,所以有些无法注明出处。关于 CSS Expression 优化的部分,摘选自 怿飞(圆心)的 《CSS Expression 的优化

声明:本文采用BY-NC-SA协议进行授权。转载请注明转自:CSS Expression

« »

1 条评论

  • 一般就是处理ie6的时候稍微用下,加个_,对其他浏览器没什么影响。除了那个ie6模拟position:fixed的其他基本不用。,博主总结的很全,收藏了。感谢。最后说一句,让ie6去死吧。。。之前还讨论过一个用.htc文件来兼容ie6的也是不怎么理想,ie6真的很蛋疼。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(Spamcheck Enabled)