hasLayout详解及触发条件

众所周知,BFC和haslayout是CSS布局基础之一,本文主要讲解下haslayout(拥有布局)属性,关于BFC我在下一篇文章做了总结

之前我们说过,给元素添加相关属性可激活BFC,进而解决诸如浮动引起的元素覆盖,外边距重叠,和清除浮动等问题。但是IE7及以下版本不支持BFC,但有私有属性haslayout,于是我们可以通过触发元素的haslayout来达成BFC的相似效果

虽然现在基本已经不用再适配IE5.5/6/7了,但理解hasLayout还是很有必要的。其实可以理解为从另一个角度学习BFC吧!

 

【引文】

我们都知道ie浏览器和其他一些浏览器有很多表现不同的地方,这确实让人头疼,ie的表现与其他浏览器不同的原因之一就是我们今天要说的这个熟悉又陌生的东西:layout是一个专门针对显示引擎内部工作方式的概念(听起来好像很官方),布局问题是许多ie显示bug的根源

另外在清除浮动的时候也经常提出触发haslayout

 

【简介】

haslayout 是IE渲染引擎的一个内部组成部分

在IE中,一个元素要么自己对自身的内容进行计算大小和组织,要么依赖于父元素来计算尺寸和组织内容

(即仅能通过line-height设置内容行距,通过行距来支撑元素的高度;也无法通过width设置元素宽度,仅能由内容来决定而已)

为了调节这两个不同的概念,渲染引擎采用了 hasLayout 的属性,属性值可以为true或false

当一个元素的 hasLayout 属性值为true时,我们说这个元素有一个布局(layout),它负责对自己和可能的子孙元素进行尺寸计算和定位

 

【由来】

在理想情况下,所有元素都控制自己的尺寸和定位

但 windows上的ie使用布局概念减少它的处理开销,在ie中不是全部的元素都可以控制自己的尺寸和定位

当然,这并不是没有原因的,官方给出的解释是:这样会在ie中导致很大的性能问题,ie开发团队决定只将布局应用于实际需要它的那些元素,这样就可以充分地减少性能的开销

 

【解析】

 如果一个元素“没有拥有布局”,那么它的尺寸和位置由最近拥有布局的祖先元素控制。  ( 拥有了布局的元素会表现会矩形 )

在默认情况下,ie中本身自己就拥有布局的元素包括:

body

html(标准模式)

table

tr、td

img

hr

input、select、textarea、button

iframe、embed、object、applet

marquee

 

布局的概念是ie特有的,它不是css属性,但是可以通过javascript获取到hasLayout,这是一个只读属性,不可以设置,所以我们不能用js来设置这个属性。

但是我们可以通过设置一些css属性来使没有拥有布局的元素自动拥有布局,我们可以通过设置下面这些属性:

float: left|right;

display: inline-block;

width: any;

height:any;

zoom:any;           //  用zoom来触发haslayout的扩展内容

writing-mode:tb-rl;

 

在ie7中以下的属性也成了布局触发器

overflow: hidden、scroll、auto

min-width: any

max-widht: 除了none以外的任何值

ie8已经放弃了hasLayout属性

 

【haslayout 问题的调试与解决】

  当网页在 IE 中有异常表现时,可以尝试激发 haslayout 来看看是不是问题所在。常用的方法是给某元素 css 设定 zoom:1。使用 zoom:1 是因为大多数情况下,它能在不影响现有环境的条件下激发元素的 haslayout。而一旦问题消失,那基本上就可以判断是haslayout 的原因。然后就可以通过设定相应的 css 属性来对这个问题进行修正了。建议首先要考虑的是设定元素的width/height 属性,其次再考虑其他属性。

  对 IE6 及更早版本来说,常用的方法被称为霍莉破解(Holly hack),即设定这个元素的高度为 1%(height:1%;)。需要注意的是,当这个元素的 overflow 属性被设置为 visible 时,这个方法就失效了。或者使用 IE的条件注释。

  对 IE7 来说,最好的方法时设置元素的最小高度为 0 (min-height:0;)。

  haslayout 问题引起的常见 bug

  E6 的躲躲猫(peek-a-boo) bug

  bug 修复: _height:1%;

 

【实际操作】

zoom:1; 是很不错的触发方法,不会改变原来的任何式样,而且仅仅是IE可以识别,但是唯一的坏处就是他不能通过W3C

设置 display:inline-block 然后再设置回原始的 display 属性,这样不会移除 layout,我们就可以达到设置 layout 而不使用IE的条件注释的目的(原理是利用haslayout触发不可逆)

下面是例子:

div { display: inline-block; }   
div { display: block; } /* 分别在两段 css 块中设置 */   

 

【案例解析---hasLayout都会引发什么问题? 】

1. 浮动元素会被layout元素自动包含

正常情况下,浮动元素会按照left和top的设置偏离原来文档流中的位置,父元素是不会调整高宽去包含该浮动元素的(也就解释了为什么浮动元素不能撑开父容器),但在IE中,layout元素会自动调整高和宽以包含浮动元素(给父容器_height:1%;即可解决)

2.浮动元素旁边的元素。当一个块级元素紧跟在一个左浮动元素之后时,其中的文字内容应该沿着浮动元素的右边顺序排列并会滑到浮动元素下方。但是如果这个块级元素有 layout,那么这个元素就会表现为一个矩形,其中文字不会滑向浮动元素下方

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>IE6 hasLayout 会影响非浮动元素中的文字是否围绕浮动元素</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        .box{
            width:220px;
            overflow:auto;
            font-size:12px;
        }
        .leftbox{
            background:#CCC;
            width:100px;
            height:100px;
            float:left;
            *margin-right:-3px; /*针对IE6 浮动元素水平右外边距移动-3px 即可解决*/
        }
        .textbox{
            background:#FFCCCC;
            height:1%;/*去掉后 IE6下 文字不会再围绕浮动*/
        }   
    </style>
</head>

<body>
<div class="box">
    <div class="leftbox">浮动元素</div>
    <p class="textbox">文本文本文本文本文本文本文本文本文
        本文本文本文本文本文本文本文本文本文本文本文本文本文本文本
        文本文本文本文本文本文本文本文本文本文本文本文本文
        本文本文本文本文本文本文本文本</p>
</div>
</body>
</html>

3. IE专有的滤镜属性filter是只适用于 layout 元素的,也就是说如果你给一个DIV设置透明用的是filter:alpha(opacity=80);如果你没有让DIV触发hasLayout,那么这个透明将无效

<!DOCTYPE html>  
<html>  
<head>  
<meta charset="utf-8" />  
<title>IE6 filter透明滤镜 需要触发该元素的hasLayout</title>  
<style>  
*{  
    margin:0;  
    padding:0;    
}  
body{  
    background:#000;  
    font-size:12px;  
}  
.textbox{  
    background:#FFCCCC;  
    opacity:0.8;  
    filter:alpha(opacity=80);  
    zoom:1;  
}  
</style>  
</head>  
<body>  
<div class="textbox">
       文本文本文本文本文本
       文本文本文本文本本文本文本文本文本文本文本文本文本
       文本文文本文本文本文本文本文本文本文本文本文本文本文
        本文本文本文本文本文本文本文本文本文本文本文本文本文
      本文本文本</div>  
</body>  
</html>  

    

【总结】

①hasLayout表现出来的特性跟BFC很相似,所以可以认为是IE中的BFC。上面的规则几乎都遵循,所以上面的问题在IE里都可以通过触发hasLayout来解决。

          虽然 hasLayout 也会像 BFC 那样影响着元素的尺寸和定位,但它却又不是一套完整的标准,并且由于它默认只为某些元素触发,这导致了 IE 下很多前端开发的 bugs ,触发 hasLayout 更大的意义在于解决一些 IE 下的 bugs ,而不是利用它的一些“副作用”来达到某些效果。另外由于触发 hasLayout 的元素会出现一些跟触发 BFC 的元素相似的效果,因此为了统一元素在 IE 与支持 BFC 的浏览器下的表现,这里建议为触发了 BFC 的元素同时触发 hasLayout ,当然还需要考虑实际的情况,也有可能只需触发其中一个就可以达到表现统一 

 

 

【IE下因为haslayout导致的bug】

1、浮动元素与普通元素之间产生3px bug

2、块级元素与浮动元素不会重叠

3、浮动闭合元素

4、ie下margin不塌陷

5、ie下margin-left/right失效

具体问题及解决方案我在后面文章http://570109268.iteye.com/admin/blogs/2410192里做了总结

 

 

【最后分享一个不错的文章------普遍定义】

 在ie中,一个元素要么自己对自身的内容进行计算大小和组织,要么依赖于父元素来计算尺寸和组织内容。为了调节这两个不同的概念,渲染引擎采用了

hasLayout 的属性,属性值可以为true或false。当一个元素的
hasLayout属性值为true时,我们说这个元素有一个布局(layout)。

如果它设置成了true,它就不得不去渲染它自己,因此元素不得不扩展去包含它的流出的内容。例如浮动或者很长很长的没有截断的单词,如果haslayout没有被设置成true,那么元素得依靠某个祖先元素来渲染它。这就是很多的ie
bugs诞生的地方。

当一个元素有一个布局时,它负责对自己和可能的子孙元素进行尺寸计算和定位。简单来说,这意味着这个元素需要花更多的代价来维护自身和里面的内容,而不是依赖于祖先元素来完成这些工作。因此,一些元素默认会有一个布局。当我们说一个元素“拥有layout”或 “得到layout,

或者说一个元素“has layout” 的时候,我们的意思是指它的微软专有属性 hasLayout 被设为了 true。通过IE Developer Toolbar 可以查看 IE 下 HTML元素是否拥有haslayout,在 IE Developer Toolbar 下,拥有 haslayout的元素,通常显示为“haslayout = -1”。

  值得注意的是,css下是没有haslayout这一个属性的,只能通过把某些属性设置特定值来使ie下的hasLayout属性触发。这个属性在ie8及以后版本中被抛弃。

激活“haslayout”的方式——调整下列css属性:

  • width:非auto任意值——优先考虑

  • height:非auto任意值——对 IE6 及更早版本来说很常用,该方法被称为霍莉破解(Holly hack),即设定这个元素的高度为 1% (height:1%;)。但是要注意,当这个元素的 overflow 属性被设置为 visible 时,这个方法就失效了。

  • zoom:非normal任意值——该属性也为ie特有属性。一般测试的时候用zoom:1。可以避免改变其他属性破坏布局。

  • position:absolute——可能引发新问题。

  • float:left/right——ie 常见bug很多都因为元素设置了浮动而触发haslayout产生的。

  • display:inline-block——当一个内联元素想获得layout就要使用这个属性。

  • min-heightmax-height(除none)、min-widthmax-width(除none)设置任意值——针对ie7。

  • overflowoverflow-xoverflow-yvisible外任意值——针对ie7。

  • position:fixed——针对ie7。

重置“haslayout”:需要没有其他属性激活haslayout的前提下。

  • widthheight (设为 "auto")

  • max-widthmax-height (设为 "none")(在 IE 7 中)

  • position (设为 "static")

  • float (设为 "none")

  • overflow (设为 "visible") (在 IE 7 中)

  • zoom (设为 "normal")

  • writing-mode (从 "tb-rl" 设为 "lr-t")

注意:当用inline-block激活了haslayout 属性时,就算在一条独立的规则中覆盖这个属性为blockinline,haslayout 这个标志位也不会被重置为 false。把 min-widthmin-height 设为它们的默认值"0"仍然会赋予 hasLayout,但是 IE 7 却可以接受一个不合法的属性auto来重置 hasLayout。

 

.

猜你喜欢

转载自570109268.iteye.com/blog/2410164