[译]在非IE浏览器中模拟zoom创建块级上下文

原文:http://www.stubbornella.org/?p=726

译文:https://www.ofcss.com/2011/03/04/the-hacktastic-zoom-fix-translation.html

作者:Nicole Sullivan

本文介绍了OOCSS栅格系统中,”content:’ x x x x x x x x x x … ‘”这行怪异代码的来历。作者详细讲解了他寻找栅格系统最后一列最佳实现方式的全过程,并通过这个过程,详细讲解了zoom、overflow:hidden、display:table-cell、css生成内容等创建块级上下文的不同方法各自的优缺点,并对OOCSS最终采用的代码做了逐行讲解。

以下是译文:

每个人都问我OOCSS的栅格样式中那么多的“x”是干什么的(译者注:指OOCSS的grids.css中的一条规则,见图1)……因此我写了这篇文章。简单来说,除了清除浮动以外,即使元素几乎没有或者只有很少的内容时,让元素的宽度自适应展开。这个略有些奇妙的技巧使我们可以在所有浏览器中用display:table-cell来创建一个新的块级上下文(译注:原文此处为formatting context,根据上下文理解,作者的意思应该是指块级上下文——block formatting context)。我们还可以借助这个技巧,使用百分比宽度时解决像素值的小数舍入错误。解决这个问题对于实现栅格的可嵌套和可堆叠具有重要的作用。

QQ拼音截图未命名 图1

我不久前写过一篇关于用overflow:hidden创建块级上下文的文章。块级上下文是非常有用的,因为它让一个元素不环绕相邻的浮动元素(参见涛哥的《自适应的图文混排》、肉饼的《OverFlow – 一个秘密武器》),并清除它自身包含的所有浮动。实质上一个新的块级上下文使得元素表现得类似分栏(column)。任何尝试过创建栅格系统或多列布局的人都清楚这是很不容易的一件事。

方案一:Zoom

这是IE特有的解决方案。zoom属性在IE中激活了元素的hasLayout,hasLayout的元素就会创建一个新的块级上下文,清除浮动,避免浮动环绕,并且不会对标准浏览器产生任何不良的影响。

.lastUnit {
    zoom:1;
}

我希望在标准浏览器中也能有一个简单的属性值对做同样的事情,比如:

.lastUnit {
  formatting-context: new; /* please! */
}

在Safari, Firefox, Chrome 和 Opera 中有一些方法可以实现同样的效果,但是每一种都有自己的缺点,比如:

方案二:overflow:hidden

overflow:hidden 创建了新的块级上下文,基本上没有带来其它问题。对于大多数网站来说,这不失为一个不错的解决方案。但是它有一个主要的问题——该上下文内部的任何元素如果超出了边界,就会被强制隐藏。正常来说,如果你不指定高度,元素的高度会随内容扩展。

.lastUnit {
  overflow: hidden;
}

然而在一个像facebook这么复杂的网站以及很多其它网站(译注:比如腾讯朋友吐舌鬼脸),浮层、下拉菜单、横向菜单……统统都被强制隐藏了——因为他们超出了正常的文档流,并且对父节点的高度没有产生影响(大多采用绝对定位)——这个残酷的现实迫使我寻求另外的解决方案。

方案三:表格单元格

在w3c的规范中,能够创建新的块级上下文的属性值对包括:overflow:任何不为visible的值、display:table-cell, display:inline-block 以及float:left, float:right. 我开始逐一尝试。

首先是overflow,它的其它值(译注:hidden和visible以外)激活了滚动条,这让我很纠结,另外还有一个(一年前的陈年往事了,请原谅我实在想不起来具体是哪个了)则是在从右到左的文字会出现问题。

我开始测试 display:table-cell. 我用了一个OOCSS的栅格测试页面,在这个页面上每个栅格包含一个头部和一段占位文本(Lorem ipsum text). 让我喜出望外的是,display:table-cell有效!

.lastUnit {
  display: table-cell;
}

最后一个元素的html代码如下:

<div class="unit size1of5 lastUnit">
  <h3>1/5</h3>
  <p>Lorem ipsum atqui facilisi definitiones nec ei, vix eros consul sententiae et. Sed essent bonorum suscipiantur in. Ne per amet eirmod. Vidisse labitur inciderint ea nec, putent habemus accommodare pro te. Brute velit detraxit per at, putent vivendo mei an.</p>
</div>

我非常激动,直到我看到模块页面。所有位于最后一列的模块都收缩到文本的宽度(译注:在作者给出的模块页面,用调试工具禁用lastUnit的样式中的content,并删除.lastUnit中的内容,可以重现此bug)。我开始仔细检查正常的栅格页面和出错的模块页面之间有什么不同。在下面这张facebook评论页的截图中,你可以看到同样的问题。注意评论框变得收缩到了textarea的默认宽度。

table-cell-not-expanded 图2

我发现 display:table-cell 会使元素收缩或扩展以适应内容(很像浮动元素的表现)。在我的栅格测试页面,占位文本实际上把最后一列撑开,占满了所在行的全部可用空间。我获得了想要的表现,但它是由内容触发的。对于OOCSS来说这样的结论是不行的,因为OOCSS要求内容和结构严格分离。我不能要求栅格中必须有内容,实际上,我根本无法预知别人会怎么使用这些栅格。

方案四:生成内容

我意识到在不要求开发者弄脏他们的HTML结构的前提下,插入这些文本(上文中起重要作用的占位文本)的唯一方法是在css中生成内容。css生成的内容并不是DOM结构的一部分,因此它们会被屏幕阅读器忽略。我重新回顾了w3c的规范,并使用YUI实现的clearfix作为我的解决方案起点。我的lastUnit列继续用display:table-cell,但是同时加上下面的这些代码:

.lastUnit {
  display: table-cell;
}
.lastUnit:after {
  clear: both;
  display: block;
  visibility: hidden;
  overflow: hidden;
  height: 0 !important;
  line-height: 0;
  font-size: xx-large;
  content: " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
}

有点疯狂,是吧?让我解释一下。

代码解析

首先,在启用firebug的状态下用firefox打开模块测试页。模块被放置于使用了上面技巧实现的三列栅格系统中。改变.lastUnit:after的visibility属性以便你能看到它的工作原理(译注:用chrome自带的调试工具更容易操作)。

.lastUnit:after {
  clear: both;
  display: block;
  visibility: visible;
  overflow: hidden;
  height: 0 !important;
  line-height: 0;
  font-size: xx-large;
content: " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
}

css生成的文本将我的lastUnit撑开,和之前的占位文本在栅格测试页面所做的一样。它们让浏览器认为这个元素需要除去浮动元素之外的所有剩余空间来显示。

接下来我们一句一句地解释:

.lastUnit {
    zoom:1;
    display: table-cell;
}

首先,我们创建一个新的块级上下文以避免文字环绕浮动元素,避免边距层叠等。旧版本的IE不支持display:table-cell,但是没关系,因为zoom解决了这个问题。后面的所有代码都不是针对IE的。

.lastUnit:after {

我们用:after伪类以便在.lastUnit对应的元素中生成内容作为最后一个元素。

clear: both;

让生成的内容清除所有非css生成的相邻元素。

display: block;

我们希望lastUnit占满剩余的空间。

visibility: hidden;

使生成的内容不可见,并允许可能被生成内容盖住的内容可以进行点击和交互。

overflow: hidden;

确保容器的高度仍然由浏览器的默认行为决定,尤其是像IE这种内容实际高度优先于指定高度的浏览器。

height: 0 !important;

确保我们生成的内容不会改变原有的布局。

line-height: 0;

再次确保我们生成的内容不要改变原有的布局。

font-size: xx-large;

大号的字体使我们可以用较少的生成内容达到我们的目的。

content: " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
}

假文本承担了让display:table-cell的元素扩展到完全宽度的最重要工作。

最后:解决一个Opera的bug

google论坛上有人指出这个方法在Opera上会有问题(该页面无法显示,你懂的)。貌似Opera不能把大量的 “…” 当成是普通文本来处理(这个bug已经被提交了,所以你读到这篇文章时该bug可能已经被修正)。这个问题很好解决,把所有的点都改成字母x就可以了(这就是OOCSS的grids.css中出现茫茫多x字母的缘由),其实任何字符都是可以的,不一定要用x(如果你也是文章一开始说到的提问的人之一,看到这里是不是很想把作者拉出来K一顿?)

不足之处

table-cell 和 table-cell之间会以比较怪异的方式相互影响。其它元素在自身尺寸改变时,只会影响到相邻节点和父节点,而table-cell很怪异,难以计算,因为浏览器做了很多行为来保证单元格的整齐和良好布局(都是从前表格布局惹的祸……)。这些行为付出的昂贵代价已经得到了证明,因此我很想知道这种方法在性能上造成的影响。或许可以像YUI的Jenny Han Donnelly建议的那样,设置display:fixed——这个改日再试。

总的来说,在任何可能的情况下我都避免table-cell的使用,但是在这个例子里,我尝试过可以创建块级上下文的其它所有方法都不行,只能这样做。最后,我认为浏览器开发商未来应该提供一个方法触发块级上下文而不造成任何不良影响。

附录:

①小数舍入错误:指用百分比作为宽度或高度单位时,各浏览器对小数部分的不同舍入算法引发的各种css问题。典型的情景比如:宽度为413px的容器中包含四个宽度均为25%的元素,则IE下四个元素的宽度相等,但是总宽度大于413px;而FF中四个元素的总宽度等于413px,但四个元素的宽度却不完全一致。详见:Sub-Pixel Problems in Css

②Lorem ipsum text:一段被广泛应用于印刷和排版的占位字符,由看似随机的字母组合,模拟英文段落效果。早在14世纪这段文字就已经成为了占位文字的工业标准。有关lorem ipsum text的更多资料,请参阅:http://www.lipsum.com/

本条目发布于。属于CSS分类,被贴了 标签。
               

[译]在非IE浏览器中模拟zoom创建块级上下文》上有9条评论

  1. 一丝冰凉

    你好我想请教下 content:里面的 X需要写多少个合适呢? 是不是 除了点 都可以呢? 最后也提到了这种布局的弊端,不知道有没有更好的解决方案?

    1. 小李刀刀 文章作者

      配合较大的字号,宽度足够就可以。任何字母,甚至单词都可以。每一种布局都有自己的优缺点,适合业务需求和使用场景才是最好的。这种方式在内容溢出时会有bug,使用要谨慎。

  2. tcdona

    。。。我从官网下的尽然没有,看样子还是从git上获取比较好

  3. 小李刀刀 文章作者

    tcdona :

    您好,我非常想问一下,content:’ x x x x x x x x x x … ‘”这行怪异代码在最新的grids.css中是否已经改掉了,我没看到有这行代码啊? 希望您能给我个回复

    有的,https://github.com/stubbornella/oocss/blob/master/core/grid/grids.css

    点击打开,第一行代码,往右拉滚动条。

  4. tcdona

    您好,我非常想问一下,content:’ x x x x x x x x x x … ‘”这行怪异代码在最新的grids.css中是否已经改掉了,我没看到有这行代码啊? 希望您能给我个回复

  5. tcdona

    第四点的时候,一开始zoom:1;没加上去,后面又默默地加上了.

  6. Pingback引用通告: 全局字体调整 « 99css

  7. Pingback引用通告: 自适应的两栏图文混排改进 | 所谓技术 - 裁纸刀下

  8. Pingback引用通告: CSS“无宽度”布局 | Leo Zhang

评论已关闭。