什么是hasLayout
hasLayout property: Gets a value that indicates whether the object has layout.
hasLayout 是IE渲染引擎的一个内部实现. IE中, 一个元素要么自己计算大小组织内容(自己渲染), 要么依赖父元素来计算大小和组织内容(依赖祖先元素渲染). 为了区分两者, 渲染引擎采用了 hasLayout 属性, 该属性可以设置为 true 或 false. 若一个元素的 hasLayout 属性值为 true 时, 这个元素便拥有了一个布局(layout), 该元素便不在依赖某个祖先元素进行渲染, 而是它自己就去渲染自己了, 它会负责对自己和可能的子孙元素进行尺寸计算和定位, 这意味着这个元素需要花更多的代价来维护自身和里面的内容; 相反的, 若元素的 hasLayout 属性值为 false时, 它会直接依赖于某个祖先元素来完成这些工作, 最终造成很多的IE bugs.
默认情况下hasLayout=true的元素
下列元素默认拥有 layout:
- html body
- table tr th td
- img
- hr
- input button file select textarea fieldset
- marquee
- frameset frame iframe
- objects applets embed
怎么触发及清除 hasLayout
以下css样式的设置, 会触发元素的 hasLayout:
- position: absolute(IE5+)
- float: left|right(IE5+)
- display: inline-block(IE5+)
- width|height: “auto”以外的任何值(IE5+; 只对block元素有效)
- zoom: “normal”以外的任何值(IE5.5+; IE私有属性)
- writing-mode: tb-rl(IE5+; IE私有属性)
- overflow: hidden|scroll|auto(IE7; 此属性在IE6及更早版本中不能应用在未触发hasLayout的元素上)
- overflow-x|-y: hidden|scroll|auto(IE7; 此属性在IE6及更早版本中不触发hasLayout; 此属性在CSS3中才获支持)
- position: fixed(IE7)
- min-width: 任何值(IE7; 即使是0)
- max-width: “none”以外的任何值(IE7)
- min-height: 任何值(IE7)
- max-height: “none”以外的任何值(IE7)
- position: fixed(IE7)
以下css样式的设置, 会清除已经触发的 hasLayout:
- position: static(IE5+)
- float: none(IE5+)
- display: “inline-block”以外的任何值(IE5+)
- width|height: “auto”(IE5+; 对inline元素无效)
- zoom: “normal”(IE5.5+; IE私有属性)
- writing-mode: 从’tb-rl’到’lr-tb’(IE5+; IE私有属性)
- max-width|max-height: “none”(IE7)
- overflow: visible(IE7)
hasLayout 的影响
- 浮动元素可以被 layout 元素自动包含. 一般情况下, 由于浮动元素脱离普通文档流会造成父元素的坍塌. 但是在IE6-7下, 通过触发父元素的 hasLayout, 可以使得父元素自动包含浮动的子元素, 从而修复坍塌问题. 一般我们设置父元素的 *height:1%; 即可, 1%并不会改变实际高度, 只是触发了 hasLayout, 该方法被称为霍莉破解(Holly hack), 需要注意的是, 当这个元素的 overflow 属性被设置为 visible 时, 这个方法就失效了.
- 正常情况下, 浮动元素旁边的元素, 其内容应该环绕该浮动元素. 如果这个元素拥有 layout, 那么这个元素就会表现为一个矩形, 其内容不会环绕浮动元素.
- IE独有的滤镜属性(filter) 只适用于 layout 元素, 若一个div 设置了filter:alpha(opacity=90), 又没有触发该div 的 hasLayout, 那么透明的设置将无效.
- hasLayout 影响块级元素鼠标的响应区域, 通常 hasLayout=false时, 只有文字区域才有响应, 而 hasLayout=true 时, 整个块级元素都是可以响应的.
hasLayout 引起的bug
- IE6 及更低版本的双空白边浮动 bug, 修复方案: display:inline;
- IE5-6的 3 像素偏移 bug, 修复方案: _height:1%;
- IE6 的躲躲猫(peek-a-boo) bug, 修复方案: _height:1%;
- IE6-7负margin隐藏Bug, 修复方案: 去掉父元素的hasLayout; 或者赋hasLayout给子元素, 并添加position:relative;
怎么检测IE下的某个元素是否拥有hasLayout
在 IE Developer Toolbar 下, 拥有 haslayout的元素, 通常显示为 “haslayout = -1”. 也可通过js的方式检测, 如下所示:
var element = document.getElementById("myDiv");
console.log(element.currentStyle.hasLayout);//该方式只能获取值, 而不能设置
以下代码可用于在IE6-7下测试某个元素是否拥有hasLayout:
Code example: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/refs/hasLayout.htm
<!DOCTYPE html>
<html>
<head>
<title>hasLayout Property</title>
</head>
<body>
<h1>hasLayout Property</h1>
<p>This example uses the <strong>hasLayout</strong> property of the <strong>currentStyle</strong> object to
show that an element has layout when it is absolutely positioned, or when its height and/or width are specified.
The <strong>hasLayout</strong> property returns <strong>true</strong> for an object that has layout, and
<strong>false</strong> for an object that has no layout.</p>
<fieldset style="width: 50%; text-align: center;">
<legend><strong>hasLayout</strong> Property</legend>
<p style="text-align: left;"><em>Which DIV element has layout?</em></p>
<div id="oWidthSet" style="width: 100%; text-align: left;"><strong>DIV</strong> element A has its <strong>width</strong> set to <strong>100%</strong>.</div>
<div id="oNotSet" style="text-align: left;"><strong>DIV</strong> element B is not positioned, and neither its <strong>height</strong> nor <strong>width</strong> is set.</div>
<br>
<button onclick="document.getElementById('messageBox').textContent = document.getElementById('oWidthSet').currentStyle.hasLayout;">DIV Element A</button>
<button onclick="document.getElementById('messageBox').textContent = document.getElementById('oNotSet').currentStyle.hasLayout;">DIV Element B</button>
</fieldset>
<div id="messageBox" style="padding-top: 1em; font-weight: bold;"></div>
</body>
</html>
另外, 若一个元素没有布局(layout), 那么IE下 clientWidth/clientHeight 总是返回0. 基于这点, 可以使用另一种js的方法检测元素是否拥有hasLayout, 如下:
console.log(element.clientHeight==0);//等于true则表示该元素不拥有hasLayout
需要注意的是
- hasLayout 功能只存在于IE7及低版本的浏览器上, IE8中已删除 hasLayout 功能.
- hasLayout 触发后, 没有办法直接设置 hasLayout=false, 只有将那些触发 hasLayout 的 css 属性去除, 才能恢复原样.
本文就讨论这么多内容,大家有什么问题或好的想法欢迎在下方参与留言和评论.
本文作者: louis
本文链接: http://louiszhai.github.io/2016/03/31/css-hasLayout/
参考文章