CSS实现HTML元素透明的那些事

CSS3草案中定义了{opacity:<length> | inherit;}来声明元素的透明度,这已经得到了大多数现代浏览器的支持,而IE则很早通过特定的私有属性filter来实现的,所以HTML元素的透明效果已经无处不在了。首先看看A级浏览器所支持的用CSS实现元素透明的方案

浏览器 最低
版本
方案
Internet Explorer 4.0 filter: alpha(opacity=xx);
5.5 filter: progid:DXImageTransform.Microsoft.Alpha(opacity=xx);
8.0 filter: "alpha(opacity=xx)";
filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=xx)";
-ms-filter: "alpha(opacity=xx)";
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=30)";
Firefox (Gecko) 0.9 (1.7) opacity
Opera 9.0 opacity
Safari (WebKit) 1.2 (125) opacity

实际上在IE8中,-ms-filter是filter的别名,两者区别是-ms-filter的属相值必须被单引号或双引号包围,而filter中则不是必须,而在IE8之前的版本中,filter的属性值必须不被单引号或双引号包围。

IE中的HTML元素要实现透明,则其必须具备layout,这样的元素有仅可读的属性hasLayout,且其值为true。具体情况如下:

  1. bodyimgtabletrthtd等元素的hasLayout一直为true
  2. typetextbuttonfileselectinputhasLayout一直为true
  3. 设置{position:absolute}的元素的hasLayouttrue
  4. 设置{float:left|right}的元素的hasLayouttrue
  5. 设置{display:inline-block}的元素的hasLayouttrue
  6. 设置{height:xx}{width:xx}的元素必须具体以下两个条件之一,其hasLayout才能为true
    1. IE8兼容模式和IE8以前的浏览器中,在标准(strict)模式下其display的值是block,如demo3就不行。
    2. 元素在怪癖模式(compat mode)下。
  7. 设置了{zoom:xx}的元素在IE8的兼容模式或IE8之前的浏览器中其hasLayouttrue,但在IE8的标准模式下则不会触发hasLayout
  8. 设置了{writing-mode:tb-rl}的元素的hasLayouttrue
  9. 元素的contentEditable的属性值为true
  10. 在IE8标准模式下设置了{display:block}的元素的hasLayout一直为true,如demo8

关于hasLayout的更多详情可以看Exploring Internet Explorer “HasLayout” OverviewOn having layout

从上面就可以看出IE实现HTML元素的透明如此混乱,为了向下兼容和自己的私有属性让IE上实现元素透明有多种方式,比如CSS Opacity实例中的demo1到demo8,虽然IE团队推荐实现透明的方式是:

{
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
  filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
  opacity: .5;
}

而目前简单最好用的实现方式是如CSS Opacity中demo4这样

{
    filter:alpha(opacity=30);
    opacity:.3;
}

实际上目前最流行的JavaScript框架的设置样式方法都是应用这种方式,并且针对IE设置了{zoom:1}来让元素的hasLayouttrue,但在IE8的标准模式下zoom并不能触发hasLayout,所以利用它们设置hasLayoutfalse的元素的透明度时在IE8的标准模式下是失败的,这个bug在YUI(我已经给YUI团队提交了这个bug,他们会在下个版本修复,最新的2.8.0中依旧存在,期待2.9.0吧)PrototypejQueryMootools的最新版本中都存在,具体请在IE8标准模式下看demo9到demo11。同样由于在IE8中设置透明度的方式多种多样,所以利用JavaScript获取HTML元素的透明度值需要考虑多种情况,YUI完美解决了这个问题,Prototype比jQuery稍微周全一点,而Mootools直接是bug,具体可以在IE下看demo1到demo8的演示。从这个角度给4个框架来个排名的话,YUI第一、Prototype第二、jQuery第三、Mootools垫底。

我简单的实现了设置和获取Opacity的函数,可以避开上面框架存在的bug,请在IE8标准模式下看demo12

//设置CSS opacity 属性的函数,解决IE8的问题
var setOpacity = function(el,i){
  if(window.getComputedStyle){// for non-IE
    el.style.opacity = i;
  }else if(document.documentElement.currentStyle){ // for IE
    if(!el.currentStyle.hasLayout){
      el.style.zoom = 1;
    }
    if(!el.currentStyle.hasLayout){ //在IE8中zoom不生效,所以再次设置inline-block
      el.style.display = 'inline-block';
    }
    try{
      //测试是否已有filter
      //http://msdn.microsoft.com/en-us/library/ms532847%28VS.85%29.aspx
      if(el.filters){
        if(el.filters('alpha')){
	  el.filters('alpha').opacity = i * 100;
	}else{
	  el.style.filter += 'alpha(opacity='+ i * 100 +')';
	 }
       }
    }catch(e){
      el.style.filter = 'alpha(opacity='+ i * 100 +')';
    }
  }
}

//获取CSS opacity 属性值的函数
//借鉴自http://developer.yahoel.com/yui/docs/YAHOO.util.Dom.html#method_getStyle
var getOpacity = function(el){
  var value;
  if(window.getComputedStyle){
    value = el.style.opacity;
    if(!value){
      value = el.ownerDocument.defaultView.getComputedStyle(el,null)['opacity'];
    }
    return value;
  }else if(document.documentElement.currentStyle){
    value = 100;
    try { // will error if no DXImageTransform
        value = el.filters['DXImageTransform.Microsoft.Alpha'].opacity;
    } catch(e) {
        try { // make sure its in the document
            value = el.filters('alpha').opacity;
        } catch(err) {
        }
    }
    return value / 100;
  }
}

不得不说,这些事都是IE整出来的……

标签:, , , , , , , ,

作者:秦歌,时间:2009-09-06 23:44,归纳于:HTML & CSS, Javascript & DOM & AJAX,订阅:RSS 2.0,引用:Trackback

有评论 36 条,发表一条新评论 »

jon.ju说:2009-09-07 9:21 #1

多谢指教,我说呢,怎么有时候透明在IE下失效了。我以后就用IE团队推荐实现透明的方法了。

星光说:2009-09-07 9:33 #2

秦歌果然是秦歌~~
牛人啊!!

星光说:2009-09-07 9:39 #3

希望秦歌以后多多写些文章,让我们学习!!

kamov说:2009-09-07 9:52 #4

有时IE8下透明还有一个问题.
就是透明元素盖在链接上的时候 链接依然可以点…

Betty说:2009-09-07 10:09 #5

……hasLayout这个破玩意居然在IE8里仍然存在……

robinli说:2009-09-07 15:16 #6

受不了IE了,转行吧。

Rain-man说:2009-09-07 18:37 #7

对浏览器差异的研究果然很细^_^
IE中filter改变元素透明会增加浏览器占用内存。

CSS实现HTML元素透明的那些 « 潔靜精微说:2009-09-07 23:44 #8

[...] 今天在秦哥的文章《CSS实现HTML元素透明的那些事》看到了各种浏览器中透明的实现。值得注意的是里面提到了IE团队推荐实现透明的方式,写法如下: [...]

Tweets that mention CSS实现HTML元素透明的那些事 @ 随网之舞 -- Topsy.com说:2009-09-08 1:47 #9

[...] This post was mentioned on Twitter by 神采飞扬 and Eric. 神采飞扬 said: http://bit.ly/AxyFc 《CSS实现元素透明的那些事》 @kavenyan 秦歌同学的这篇文章很好啊 [...]

ato说:2009-09-08 9:02 #10

想不到有这么多的透明方式,这个总结得真好,收藏了

cc说:2009-09-08 9:16 #11

以前听说ie8没有了hasLayout
原来还有啊

cc说:2009-09-08 9:31 #12

http://msdn.microsoft.com/en-us/library/cc304082(VS.85).aspx
这里有一句
The hasLayout functionality has been removed in Internet Explorer 8.
那到底是有没有呢

秦歌说:2009-09-08 12:43 #13

@cc:这篇文档我也看过,IE官方blog上也有一些文档说过IE8已经移除了hasLayout,但是从目前测试来看的确存在而且直接影响filter。记得以前IE8的beta版本时IE8只支持-ms-filter这种私有属性,但是正式版的时候为了向下兼容就增加了filter作为别名了。我给IE团队发了一封信,等待他们的答复看看。

天堂左我往右说:2009-09-08 16:46 #14

也一直以为ie8没haslayout了…
ie6透明滤镜问题真多…
ie7强点…

天堂左我往右说:2009-09-08 18:24 #15

秦秦兄,你这样写会把别的滤镜覆盖的
el.style.filter = ‘alpha(opacity=’+ i * 100 +’)';

ie6下用透明滤镜时,png图(也用滤镜)那个难看啊…

秦歌说:2009-09-09 1:18 #16

@楼上:你这个问题很及时,目前所有的JavaScript框架都有这个问题,不过能出现这种问题的几率很小。我改进了setOpacity这个函数来解决这个问题,具体请看帖子中的代码。如demo12目前可能存在一个问题,就是在IE提供的“开发人员工具”中DOM查看代码显示的是第一次的设置,生效的当然是最后一次的设置。

天堂左我往右说:2009-09-09 9:33 #17

谢谢秦秦兄…

天堂左我往右说:2009-09-09 11:38 #18

尊敬的秦秦兄
$(“mapDiv”).style.filter = ‘alpha(opacity=’+ 20 +’)';
$(“mapDiv”).style.filter += ‘alpha(opacity=’+ 80 +’)';
发现生效的始终是20…
还是用$(“mapDiv”).filters.item(‘alpha’).opacity来设置吧…

秦歌说:2009-09-09 12:00 #19

呵呵,用el.filters.item(‘alpha’)和el.filters(‘alpha’)来设置都是一样的,你应该没有仔细看我的函数。
当没有filter时,是用el.style.filter来设置;当元素设置了filters(‘alpha’)之后,重设的方案是用filters(‘alpha’).opacity。请注意看http://dancewithnet.com/lab/2009/css-opacity/#demo12,我对demo12进行了3次setOpacity,最后生效的是0.5,仔细看它的透明度和前面是不一样的。

天堂左我往右说:2009-09-09 13:49 #20

秦秦兄,小弟眼瞎…

flight说:2009-09-09 23:18 #21

css达人阿!
我终于搞清楚透明是怎么回事了。。。

anlee说:2009-09-14 10:27 #22

谢谢分享

tree说:2009-09-18 14:35 #23

不说了

独孤逸辰说:2009-10-11 19:31 #24

谢谢啦,不错。。

CSS2下的透明度使用 | Naono说:2009-12-23 12:52 #25

[...] layout部分说明来自:http://dancewithnet.com/2009/09/06/css-opacity/ 归类于:XHTML/CSS/Javascript   标签: CSS, 透明. [...]

CT说:2010-01-21 1:43 #26

秦哥好用心

前端开发值得一看的文章 - 幸福收藏夹说:2010-01-27 19:16 #27

[...] 6. CSS实现HTML元素透明的那些事 [...]

树人说:2010-02-04 9:43 #28

高淫。。。

» 前端开发值得一看的文章 >> Y7L8'Blog---DIV.CSS.JAVASCRIPT.SEO说:2010-03-11 10:21 #29

[...] 6. CSS实现HTML元素透明的那些事 [...]

Digests for May 1st « 凋零的羽说:2010-05-01 8:02 #30

[...] CSS实现HTML元素透明的那些事 [...]

janey说:2010-05-31 17:10 #31

if(!el.currentStyle.hasLayout){
el.style.zoom = 1;
}
if(!el.currentStyle.hasLayout){ //在IE8中zoom不生效,所以再次设置inline-block
el.style.display = ‘inline-block’;
}
为什么不只用下面的判断?inline-block在ie8下不work?

【转】前端开发值得一看的文章 | 田园牧歌说:2010-08-03 23:35 #32

[...] 6. CSS实现HTML元素透明的那些事 [...]

小黎说:2010-09-10 17:08 #33

支持下 ,呵呵

jelle说:2010-11-30 16:19 #34

el.style.display = ‘inline-block’; 会把改变页面元素的渲染方式。比如原来是一个 宽度自动适应的DIV(block).结果被改编成inline-block;页面会乱码?时候可以考虑其他方式激活。

jelle说:2010-11-30 16:19 #35

el.style.display = ‘inline-block’; 会把改变页面元素的渲染方式。比如原来是一个 宽度自动适应的DIV(block).结果被改编成inline-block;页面会乱码?是否可以考虑其他方式激活。

支持Firefox,IE6.0,IE7.0,IE8.0的CSS透明滤镜-前台架构-网络天下说:2011-01-07 13:51 #36

[...] IE中的HTML元素要实现透明,则其必须具备layout,这样的元素有仅可读的属性hasLayout,且其值为true。具体情况参考:CSS实现HTML元素透明的那些事 [...]

发表一条评论

您可以在下面评论内容中使用下列XHTML标签:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


回到页眉