A fix to the IE6 line-height/replaced element bug

2009.04.1709:16

一个经典 bug,见 PIE:http://www.positioniseverything.net/explorer/lineheightbug.html

大概描述一下:IE6 中,一个 replaced element 所在行的行高会有异常,具体就是 leading 似乎被吃掉了,如果连续多行都出现 replaced element,结果更糟糕,看起来就似乎 line-height 根本不起作用。PIE 那个页面没有给出 fix,刚捣腾出来一个。

具体就是,如果在 replaced element 所在行有一个 hasLayout 的 non-replaced inline 元素,此问题即可解决。可以看一下直接修改自 PIE 那个 bug demofix Demo1 (view with IE6)。

当然,如果给每个 replaced 元素手动加这个 fix,有点不靠谱,于是我又想起了 expression(当然是 without performance issue 的版本),哇哈哈……结果就有了这么一个较为简单的 fix:Demo2 (view with IE6)。

代码如下,自行变通:

* html input,* html img{
  zoom: expression(function(ele){
      ele.style.zoom = "1";
      var iefixer = document.createElement("b");
      iefixer.className="rlfix";
      ele.parentNode.insertBefore(iefixer,ele);
    }(this));
  }
.rlfix{zoom: 1;}

以上。

CSS Expression Reloaded

2008.10.2621:17

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

这东西的优点:

  • 使 CSS 属性动态生成,所以基本 js 能干的它都能干
  • 使用 CSS 选择符,比 js 遍历到某个特定元素要方便得多

这东西的缺点:

  • expression 会反复执行,有严重的效率问题。它的触发似乎不是通过事件,而是通过 interval 一类的机制。
  • 别的浏览器不支持,IE8 也将不再支持

那现在翻出来干嘛呢?因为我发现,第一个缺点是可以解决的。方法就是,在 expression 语句体里面,将触发该 expression 的 css 属性重置。比如 body{ zoom: expression(function(ele){ele.style.zoom = "1"; alert("xx");}(this));},执行这段 CSS 会发现,alert 只跑了一次。具体可以看我上一个关于解决背景闪烁问题的帖子

所以,解决了 expression 的效率问题,就完全可以在实战中用上了。使用时只要用一个无关紧要的 CSS 属性做触发,比如 zoom, 比如 letter-spacing,比如 unicode-bidi,等等等等,触发完了重置回默认值。可以玩的很多,我来写几个实际应用中经常会遇到的问题:

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

支持 CSS2 选择符的可以使用属性选择符,IE 则可以用 expression 给 input 加上不同 type 对应的 class:(这个例子在经典贴过

input{
  zoom: expression(function(ele){
    ele.style.zoom = "1";
    (ele.className)?ele.className+=" "+ele.type:ele.className=ele.type;
  }(this));
}
input[type="text"]{ border: 1px solid red;}
input.text{border: 1px solid red;}
input[type="button"]{ border: 1px solid blue;}
input.button{border: 1px solid blue;}

演示 1,这个还可以再发散发散,比如加上 :checked,:disabled 等等,改表单样式不愁啦~

隔行换色(zebra lists)

支持 CSS3 选择符的可以直接上 nth-child(webkit,opera 都支持,马上要发布的 firefox3.1 也支持),IE 则可以通过 expression 加上 odd 或 even 的 class:

.test{
  unicode-bidi: expression(function(ele){
    ele.style.unicodeBidi = "normal";
    var childs = ele.getElementsByTagName("li");
    for(var i=0; i<childs.length; i++){
      (i % 2)?childs[i].className+=" even":childs[i].className+=" odd";
    }
  }(this));
}
.test li.odd{background: #CCC;}
.test li.even{background: #EEE;}
	
.test li:nth-child(odd){
  background: #CCC;
}
.test li:nth-child(even){
  background: #EEE;
}

演示 2 (IE5+,Opera,Safari,Chrome,Firefox 3.1)

模拟 :before 或者 :after

Firefox 3.1 之后,:before 或者 :after 出来的东西可控的 CSS 属性更多了,比如 position/float,又有的玩了,不像以前基本废柴,只拿来清除浮动……大材小用啊。

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

演示 3

还有什么好玩的可以玩?想起来再来补充。

IE8 的 CSS 支持情况

2008.08.2810:50

blog 你好,好久不见。

IE8 beta 2 来了,关注一下 CSS 相关的情况,以下整理自 What’s New in Internet Explorer 8 [MSDN]

  • display 支持 table 那一坨东西,外加 inline-block, inline-table, run-in。
  • 支持 Data URI,可以搞那些 base64 的小图标。
  • 支持生成内容,就是那些 :after, :before, content, counter,quotes 一类。
  • 支持 outline
  • 支持若干打印相关的东东
  • 支持 :lang 和 :focus 伪类

更详细的这里有张表:CSS Compatibility and Internet Explorer [MSDN]

除了上面列的那些,个人比较喜欢的还包括:

  • 支持 CSS3 那一堆高级选择符了,很好很好。
  • 支持 box-sizing,实用啊实用,这下可以随心所欲地捣腾而不用再受 W3C 那变态的旧盒模型折磨了

比较失望的包括:

  • 不支持 CSS3 新增的伪类,:nth-child() 啦,:first-of-type 啦,:not 啦,多好的东东。
  • 不支持多重背景
  • 不支持 border-radius,哇靠!不支持多重背景就算了,border-radius 也不给玩,做圆角还是要累死啊

另外一个信息,由于 Firefox 2 开始自动推送 3 的更新,所以现在做东西基本可以不考虑 Firefox 2 了。一个重要的变化就是,现在可以放心大胆地玩 inline-block 了,哇哈哈哈。

再说 IE6 的背景闪烁

2008.01.0409:42

基本上 google 一下 IE6 flicker,第一页基本全是说这个问题,解决方法就是那个神奇的 document.execCommand("BackgroundImageCache",false,true),只不过是围绕着用 CSS expression 还是 JavaScript 的问题。JavsScript 最稳妥,不过有时候 JavaScript 未必方便改,而 CSS 虽然方便但是 expression 会反复执行,有严重的效率问题。最近的几个项目用的方法是这样的,在 expression 中把 CSS 中用来触发的属性重写一下:

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

这里用 zoom 触发,搞定之后把 zoom 写回 1(好像我很喜欢捣腾 zoom),这下就没效率问题了吧,嘿嘿。同理,其他针对 IE 的 hack,如果是只跑一次的 expression,其实都可以这样做,所谓兔死狗烹过河拆桥是也~ :D。

用图片自定义复选框

2007.05.1910:40

自定义复选框样式,推荐经典标准化专栏 snwebsite 版主的一篇帖子 《用图片模拟checkbox,简简单单》。

真是创意无限啊,想法真妙。

W3C 接受 HTML 5

2007.05.1111:56

小道消息,呵呵

http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2007-May/011228.html

The W3C’s HTML working group today resolved to start from the current WHATWG work. Specifically, the group resolved to review our work, and will probably build on it.

They also resolved to call this work HTML5.

Thus, the “Web Applications 1.0″ spec is now officially named “HTML5″!

所谓顺天应人,嗯。

update:

刚又在 Junchen 那里看到了“大道消息”,:D

最近遇到的几个 CSS bug

2007.05.0820:59

都和 layout 有关,记录一下

  1. IE7 下 layout 元素会有鼠标光标问题,具体就是鼠标位于文字之外时,光标也会变成 I 型。演示页面,IE7 下观看,一个框有 layout,一个没有,注意鼠标光标在两个框中的不同形状。

    但是此 bug 有例外:
    当它有背景时(包括背景色和背景图像)、当它 float 时、当它绝对定位时、当它有一个 filter 时,当它被放置于一个 float 的祖先中时,不会出现这个bug,也许还有别的情况,以后发现了再补充。

    另外如果将其相对定位,只有一部分会显示 I 形光标,另外一部分是正常箭头状。箭头状范围不随字体和行距的大小改变,始终在顶部 15px 附近,这个现象有点灵异了 o_o。

    目前比较简单的解决办法是加背景,如果需要背景透明,就用一个透明 gif 代替,或者用一个不存在的 url 代替,或者使用 filter: alpha(opacity=100)

  2. 具有 layout 的元素会裁切掉内部元素的默认 margin,但内部元素的自定义 marign 不受影响,演示页面可以参考经典论坛的这个帖子。比较奇怪,默认 margin 和自定 margin 难道还有不同的机制?不知道 IE 对于默认样式是什么处理的,IE6 和 IE7 都受影响。这 bug 由于一般都会写一个 *{margin: 0; padding: 0;} 的样式,所以平时不容易发觉。开始以为和 margin-collapsing 有关,结果似乎不是这个问题,margin-collapsing 和 layout 的相关 bug 可以参考 Bruno 的测试页面

CSS 2.2 ?

2007.05.0722:53

HTML 5 最近风头大起,争论不断,现在又来了一个 CSS 2.2

的确,CSS 3 拖的时间实在太长了…… Andy Budd 认为它之所以迟迟不能定稿是因为贪多嚼不烂(有 40 个模块),WEB 的变化越来越快,以前定下来的东西过了一段时间发现又需要修改,这样怎么改也改不完,何时是个尽头。总想让自己完美,总想尽可能考虑周全未来的种种状况,结果忽略了当前真正亟待解决的问题,这是 CSS 3 目前定稿最大的障碍。于是 Andy 提议将 CSS 3 中的部分急迫内容,或者说用来满足一些常见需求的内容加入 CSS 2.1 中,升级为 CSS 2.2 以促进新的 CSS 版本推出。

不过个人感觉,这个没有浏览器厂商的合作,就算 W3C 定了个 CSS 2.2 出来又能如何?Mozilla 和 Opera 倒是可以持乐观态度,但是 IE 呢?占浏览器市场份额最多的 IE 呢?且不说 IE7 的份额还很少,就是还在计划中的 IE 8 目前的目标也仅仅是完善对 CSS 2.1 的支持!CSS 2.2 出来了谁能保证它的命运不像 2.1 一样悲惨?

CSS naked day

2007.04.0500:13

去年忘了脱,今年来脱一下。嘿嘿。

What happened to the design?

To know more about why styles are disabled on this website visit the Annual CSS Naked Day website for more information.

IE 中的 html 元素

2007.03.1421:48

<html> 元素,XHTML 文档中的根元素,再熟悉不过了。不过最近折腾一个布局,发现在 IE 中,它不是那么简单的角色,有一些很特殊的“性质”,总结一下备查:

IE6 标准模式:

  • 不管给它设置什么样的高度和宽度,它的大小都始终充满整个视区。
  • 不管给他设置什么样的 paddingborder,同样,大小始终充满整个视区。
  • margin 会被忽略。
  • initial containing block 是视区矩形减去 <html>border 宽度

用 CSS3 来表述,我们可以把 IE6 中的 <html> 看成 heigh:100%; width:100%; box-sizing:border-box; 的一个特殊元素,而且这些属性不可变

IE7 标准模式:

IE7 虽说修复了 IE6 的若干 CSS bug,但对于 <html> 的理解,要比 IE6 复杂得多。IE6 虽然诡异但可以改的属性毕竟少,所以还算简单。IE7 的 <html> 倒是可以接受更多的属性了,但算法却不按照规范老老实实的来,所以搞明白它要比 IE6 头疼得多。

  • 首先是自动扩展特性。

    <html> 元素在 y 方向上比较简单,和 IE6 对普通元素 height 的理解方式类似——如果内容高度超过 <html> 的高度,或者 <html> 没有定高(即默认值 auto),那么 <html> 会自动扩展自身高度以包含其中内容。

    而在 x 方向上有些诡异,问题主要集中在对 <body> 宽度的理解,这里分两种情况讨论:(不是说 <html> 么,怎么又说到 <body> 的宽度了?因为 <html> 要自动扩展,必须要知道 <body> 有多宽才好扩展嘛。)

    • 第一种情况:<html>width 如果是非 0 值之外的一切值(包括默认值 auto),那么 <body> 的宽度由以下规则决定:

      • 1. 如果 <body>width 是个固定值,那宽度就是这么多。
      • 2. 如果 <body>width 是默认值 auto,那宽度会充满 <html> 的内容空间。
      • 3. 如果 <body> 本身有收缩包围特性,比如被设置了 position:absolute 或者 display:inline(奇怪的是 float 却不满足这一条,它满足2),那么就根据内容的宽度来定。
    • 第二种情况:如果 <html>width 是 0,那第 1、3 点和上面的情况相同,而第 2 点,如果 <body>width 是默认值 auto那宽度根据内容自适应,但有一个奇怪的现象,就是如果 <body> 同时具有不为 0 的 border 或者 padding 时,它的宽度就不会根据内容自适应而会变成第一种情况下的第 2 点——充满 <html> 的内容空间,由于这时 <html> 的宽度是 0,所以 <body> 宽度也坍缩成 0。
  • 其次是 <html> 的宽高设置会奇怪地影响 <body> 的百分比参考(或者说 <body> 的 containing block)。

    在 y 方向上,如果 <html>height 是默认值 auto,那么 <body>height 如果取一个百分比的值,将会被忽略。但一旦 <html>height 值有了一个具体高度,哪怕是 0,<body> 的百分比高度就会被应用了。不过诡异的是,这个百分比高度的计算参考并不是刚刚设置的 <html> 的高度,而是视区高度减去 <html>margin+border+padding 高度之和。

    而在 x 方向上,如果 width 取默认值 auto,和 y 方向不同,<body> 的百分比宽度将不会被忽略,但其计算参考依旧和 y 方向一样诡异,为视区宽度减去 <html>margin+border+padding 宽度之和。如果 width 有了具体取值,它就会取而代之作为 <body> 的百分比宽度参考。

  • 再次,当 <body> 设置为 position:absolute 时,<html>border-color 会失效。这是另外一个奇怪的 bug。
  • 最后,initial containing block 采用视区矩形,这个基本正常。但无法使 <html> 创建绝对定位元素的 containing block,不过也许 <html> 创建的 containing block 就是视区矩形,谁知道呢。

好乱,整理下来除了头大还是头大,不知道以后回过头再看还能不能看明白。IE7 啊 IE7……想说爱你不容易……

IE5 以及 Quirks 模式

  • <html><body> 所有宽高设置都会被忽略而保持充满视区。
  • <html> 不接受 paddingmargin
  • <body> 接受 paddingmargin 但负值 margin 没有视觉效果,不过会在计算其他相应参数时带入。
  • <body>border, background 等属性会向上转移给 <html> 元素。
  • initial containing block 是 <body>padding 边缘。

用处

这个总结是从一开头的布局问题引出来的,那个布局问题就是用处之一,等下重写一个 post 来整理。但那个布局只用到了很少一部分特性,应该还有更多的潜力可以挖,慢慢研究吧。

另外上面总结的东西都是简单试验试推出,所以很可能有理解错误的地方,如果阅读本文的朋友发现了,希望可以留言告知。