"HasLayout" 综述

原文地址http://msdn.microsoft.com/en-us/library/bb250481(v=vs.85).aspx

作者:Markus Mielke (Microsoft Corporation)

2005-08-30

什么叫做"HasLayout",为什么它很重要?

一些IE下的bug可以通过激活元素的"layout"(一种IE内置的数据结构)来得到解决(例如, dimensional bug fixes和 Holly hack),但是为什么要给元素加上一个"layout"的数据结构,实际上大多数用户并不了解。这篇文章解释了当一个元素拥有"layout"之后会有什么变化,以及设置"layout"的原因。

首先,我们从分析元素的类型开始,页面中通常有两类元素:

  1. 依赖父元素来进行尺寸计算和内容定位的元素
  2. 可以自身进行尺寸计算和内容定位的元素

总体来说,在DHTML中,大部分元素属于第一种元素,DHTML引擎不支持元素对自身尺寸和内容进行计算,虽然像divp这样的元素在文档流和优先级规则中拥有自己的定位,但是其内部元素的布局还是依赖与其最近的拥有布局的祖先元素(通常是body)来进行。这些元素通过祖先元素的布局来进行自身内部复杂的尺寸计算和内容编排。

Note:拥有布局影响力的元素不一定是元素直接的父元素,有可能是其祖先元素,放弃让每一个元素拥有布局的好处在于其简洁性,从而提高了页面性能。

所以,什么叫做"拥有了Layout"?

  • 简单来讲,拥有了layout是指一个元素拥有了对自身(甚至其所有子元素)的尺寸和定位进行计算的能力(如果它的其中一个子元素拥有自己的布局,这个子元素将负责计算自己及其子元素的尺寸,但是该子元素的定位会受其父元素的影响)
  • 一些拥有“固定”尺寸的元素,和一些比较特殊的具有默认尺寸约束的元素,通常会拥有Layout,例如,button,images,inputs,selects,和marquee等元素,这些元素即使没有设置宽高,也会拥有自身默认的尺寸。
  • 有一些元素不像一般元素那样来获取Layout,比如divspan,它们会有一些特殊的属性来激发layout,从而来获得另外的特性,比方说,一些元素通过获得布局来拥有滚动条特性。
  • 元素一旦设置了Layout,元素的"hasLayout"属性就被设置成true(可以通过工具查看到)。

为什么拥有Layout很重要?

  • 它会将元素限制在一个矩形的盒子内,从而保证元素的内容不会分散到另一个盒子周围,例如,在IE引擎中,一个拥有布局边框的元素不会环绕相邻的浮动元素。
  • 拥有Layout的元素会建立起一个新的块级上下文(block formatting context)(有关BFC的解释可参考http://rlog.cn/?p=623)
  • 由于Layout使得浏览器渲染引擎要额外地在内存中调用算法来计算元素尺寸和方位,所以它并不轻量,它会消耗更多的内存,并可能导致性能的下降。
  • 会产生元素无法自适应大小的副作用,一个拥有Layout的元素不会“自动缩小”来适应其子元素,例如,一个绝对定位具有Layout的盒模型如果有一个拥有Layout的子元素,它是不会自动缩小来适应这个子元素的尺寸的。
  • 而一个拥有Layout的盒模型会被子元素给撑开(IE6下的heigh bug)
  • 人们通常利用Layout来解决IE6bug,特别是与相对定位元素有关的,但实际上,相对定位元素不需要拥有Layout,如果让它们拥有Layout在一些情况下反而会产生问题。

哪些元素自身即拥有Layout

一般来说,如果某个元素拥有自己的“领地”,需要在领地内展现特定的信息和功能,并且这种信息和功能会影响到其领地内容的位置和渲染,那它即会拥有一个Layout。例如:

  • Images
  • Tables, TableRows, TableCells
  • HR
  • Input elements: text, button, file, select
  • Marquee
  • Framesets, Frames
  • Objects, applets, plugins
  • Absolute positioned elements
  • Floated elements
  • Inline-block elements
  • Filters (rotation, dropshadow, etc.)
  • Body (as well as HTML element in strict mode)

哪些元素可以获得Layout

  • 在strict mode下,指定width或height的块级元素。
  • 兼容模式下, 指定了widht或height的任何元素
  • 设定了zoom属性的元素
  • 可编辑状态下的元素
  • 拥有viewlink行为的元素
  • 元素的Layout-flow属性跟父元素的不同(rtl to ltr)(译者注:Layout-flow现已不赞成使用,writing-mode代替)

布局"hacks"举例

这里列举了一些已知的在不产生视觉变化的情况下让元素拥有haslayout属性的场景,当你看到或使用它们时,请注意它们所带来的影响(感谢Ingo chao及列表的收集者们)

haslayout造成的影响

场景1:floating

见下方代码:

<div style="float:left; border: 2px solid red"> 123</div>
<span style="border: 2px solid blue">
The quick brown fox jumped over the lazy dog's back.
The quick brown fox jumped over the lazy dog's back.
The quick brown fox jumped over the lazy dog's back.
The quick brown fox jumped over the lazy dog's back.
The quick brown fox jumped over the lazy dog's back.
</span>

 

执行代码,我们将会看到

Bb250481.HasLayout_1(en-us,VS.85).gif

  • 不出所料,文字环绕在了浮动元素div周围
  • 蓝色的边框可以证明,span元素也拥有一个“盒模型”

如果我们让span元素拥有'Layout'会产生神马效果?

<style>
.gainlayout
{zoom: 1;}
</style>
<span class="gainlayout" style="border: 2px solid blue">

Bb250481.HasLayout_2(en-us,VS.85).gif

  • 拥有布局后,span整体呈现出矩形特征
  • 文本不再环绕在div周围,了解这一点很重要,因为它会影响原本期望的文本布局(你也可以试一下让一个p元素拥有布局)

场景2 自动布局

<div style="position: absolute; background:red">
<div>
123
</div>
</div>

执行代码,我们将会看到:

Bb250481.HasLayout_3(en-us,VS.85).gif

  • 第一个div被设置成绝对定位,脱离了文档流,这个布局影响了其包含的块级元素
  • 红色的背景"收缩并包裹"住"123",因为其布局是由其被设置成绝对定位的父元素决定的。

如果我们让子元素div拥有'layout'会产生什么效果?

<style>
.gainlayout
{zoom: 1;}
</style>

<div style="position: absolute; background:red">
<div class="gainlayout">
123
</div>
</div>

Bb250481.HasLayout_4(en-us,VS.85).gif

  • 子元素div现在拥有了自己布局的所有权并且完全忽视父元素对他的任何'指令'
  • 我们完全失去了父元素所带来的"压缩包裹"效果,当你让元素拥有布局时需要注意这一副作用


场景三 相对定位

现在我们来看一看如何利用'haslayout'来处理bug

<div style="position: relative; border: 2px solid blue">
<div style="float:left; border: 2px solid red">
<img style="position: relative; border: 2px solid green; width:100px; height:100px"
src
="slider.jpg">
</div>
</div>

我们希望在IE下达到以下效果

  • 蓝色边框闭合成4px的蓝线(闭合是因为其子元素被移出文档流)
  • 红色边框的浮动div像盒子一样包含了绿色边框的图片。

理想效果应该是:

Bb250481.HasLayout_5(en-us,VS.85).gif

但是我们会惊奇地发现,IE6下是这样子的:

Bb250481.HasLayout_6(en-us,VS.85).gif

这是为什么呢?

  • 因为image是相对定位,所以它的位置取决于它父元素拥有的布局
  • image的父元素是向左浮动的div元素,本身即'拥有Layout'
  • IE6下对相对定位元素尺寸的计算方式很不完善(这是一个bug并已在IE7中修复),所以image的父元素错误地计算了image的尺寸和方位。
  • 注意: 你可能也会注意到那两条合并起来的蓝色边框并没有像原先预想的那样穿过红线,这一点需要我们注意,元素一旦浮动起来即拥有了布局,就像例子中一样,浮动的div并不会受旁边的div的蓝色边框的影响。而在这种场景下,是IE6的一个bug

一般解决这类bug的方法是让原先没有布局的元素"拥有Layout"。

<style>
.gainlayout
{zoom: 1;}
</style>

<div class="gainlayout" style="position: relative; border: 2px solid blue">

结果如下:

优点:

  • image按要求出现在了理想的位置(最高布局法则会正确计算浮动元素和image的尺寸及位置)

缺点:

  • div本身的"布局"呈现出一些副作用
    • 蓝色边框不再闭合,而是获得了"布局"并环绕在浮动元素和image之外
    • 浮动元素周围的文档流将被阻塞
    • 在这个场景中,表现出的问题还算比较小,你想象下如果页面中有50个类似的场景...

在这个场景中,你不需要做太多修改(除了可以移除不必要的"position:relative"语句),我们并不反对使用"haslayout"的方法去解决Ie6的bug,只是想给大家解释一下触发元素"haslayout"后会造成的影响。从长远来看,这些bug都会被修复掉,即使不在IE7,也会在IE后续的版本中。

总结:

我试着向大家解释一些IE内核Trident有关'haslayout'的内部工作机制以及它带来的副作用,并列举了哪些元素本身即自带内置布局,哪些元素可以通过触发获得布局。最后,我讨论了元素获得布局后会带来的影响并列举了一些典型案例。

理想状态下,用户不应该也不需要知道这个特性,因为它主要用于解决IE内部的一些css的布局问题,但是,它如今已经成为一种修复IE6下布局bug的有效手段。另外,IE的这个特性并未与css规范产生冲突,而是用来更加规范地实现css特性,鉴于这个考虑,我很乐意为'haslayout'属性的理解和运用做一些贡献。

致谢:

感谢Web Standards Group(WaSP) 对本文的支持和反馈,特别感谢Dean Edwards 和 Chris Wilson的审校,感谢Holly Bergevin, Ingo Chao, Bruno Fassino, John Gallant, Georg S?rtun, and Philippe Wittenbergh积极参与讨论本文的创作,本文希望能为社区有关'haslayout'的讨论作出贡献

  • http://www.satzansatz.de/cssd/onhavinglayout.html
  • www.positioniseverything.net
  • http://www.webmasterworld.com/forum83/6999.htm

Markus Mielke 是微软Internet Explorer 团队的一名项目经理

你可能感兴趣的:(layout)