对overflow与zoom”清除浮动”的一些认识

这篇文章发布于 2010年01月31日,星期日,07:36,归类于 css相关。 阅读 142586 次, 今日 26 次

补充于2018-01-01
本文不少观点是有误的,只怪当年太年轻,大家随便看看就好了。对overflow更准确认识可以见我的书《CSS世界》

一、前面的一些YY

首先,不知道您注意到没有,标题“清除浮动”加了个引号。我最近在想,这个所谓的“清除浮动”的是否准确。人有从众的心理,尤其在我们这个集体主义文化的社会,从众并不是一个消极的标签,在亚洲集体主义文化里(例如日本),其象征着忍耐,自我控制,以及成熟,但是,有时会延续一些不准确的观点,还记得小学“两个铁球同时落地”的故事吗。

我这里要说一些个人的,很情感化的东西,非常欢迎反驳。我在国外的技术上也经常见到”clear float”一词,翻译过来就是“清除浮动”,我入行较浅,所以我只能臆想,是不是“清除浮动”确实表示了那个意思,于是就广泛使用,越是使用广泛越不容易发现其中的不严谨之处。

我最近思考“清除浮动”的一些东西,发现,“清除浮动”这个说法越想越觉得不准确。准确的说法应该是“清除浮动造成的影响”,真正的“清除浮动”是什么呢,float:none;这才是“清除浮动”的字面意思。当然,也有可能是“清除浮动”就是个简称,意思就是“清除浮动造成的影响”,只是叫了顺口,大家也都这么称呼了,大家其实都心知肚明。希望自己是想多了。

YY结束,进入本文正题,一些思考性的内容,讲讲我对overflowzoom可以清除浮动造成影响的原因的理解,都是些浅薄的认识,希望真正理解的人能够指点纠正,大大欢迎反驳,发表您自己的观点。

二、元素的包裹性

“包裹”这个名词常出现在JavaScript中,尤其jQuery之类的js库,很形象的一个词。昨天我看到这么句很有启发性的话:“视觉化思考能以独特而有效的方式,让你的心有更大的空间来解决问题。”启发性在于,这里的“视觉化思考”改为其他一些名词,例如“情感化思考”,“形象化思考”等同样受用。也就是在思考问题的时候融入一些很主观的非逻辑性的思考有助于有更广阔的空间来解决问题。

一提到“包裹”一词,我想到了就是白细胞吞噬细菌(形象化思考 – 联想),以及温暖及安心(情感化思考)。这因人遗传、成长等因素相关。为什么我要讲这些看似无关主题的东西,因为下面我要将的很多东西就是自己的感觉,“我觉得它就是这个样子的”,很多主观的东西。

白细胞 张鑫旭-鑫空间-鑫生活

CSS中,有很多的属性一提到我就会想到“包裹”这个词,像“浮动”,“绝对定位”,“inline-block”,“overflow”,“zoom”,就这些,没有其他了。

//zxx: 这里的overflow特指overflow:hidden/scroll/auto声明,不包括overflow:visible

对于浮动,我在“CSS float浮动的深入研究、详解及拓展(一)”一文中花了一大段讲浮动的包裹性,一个div,默认宽度100%显示,一旦有了浮动属性(none除外),其宽度包裹与内部的元素,浮动的包裹性显而易见。

对于absolute绝对定位,我在“absolute绝对定位的非绝对定位用法”一文中也提到过其包裹性,相信有经验的同行们应该都知道absolute元素的这个特性,即absolute元素(如果没有设置width值),其宽度自适应于内部元素,也正是这个原因,absolute属性常在jQuery插件中用来做宽度计算。所以,absolute元素也是具有包裹性的。

对于inline-block,这个可以说是包裹的祖宗了,无论是float还是absolute的包裹性都是向inline-block靠齐的,神奇而伟大的inline-block元素,它的故事可以写成一本书了,打住,不多说。

对于,浮动(float),绝对定位(position:absolute)以及inline-block的包裹性我称之为“主动包裹”,其标签宽度会收缩至内部元素大小;而overflowzoom,我称之为“被动包裹”。

对于overflow的包裹性其实不难理解,例如一个div里面仅有个浮动元素(一张美女图片),那么这个div高度会塌陷,现在这个div要应用overflow:hidden;属性,想想看,既然div高度塌陷,那么div里面的这个图片就应该在div的外部,按照overflow:hidden的功能,这个图片应该直接-“咔”-一声截掉不显示的,但是这可以吗,显然不行,怎么办,只能去包裹这个浮动的美女图片,于是设置了overflow:hidden属性的div有了高度,同时把浮动的图片封在了里面。您可能会想到IE下的overflow好像没有这么回事,事实上是这样的,IE6/7对overflow属性的理解有误,说白了是IE6/7的一个bug,IE8已经修复这个问题,也就是说IE8下overflow:hidden可以清除浮动造成的影响,您有兴趣可以自己测试一下。
(多谢dony的提醒)修正为:
IE6对overflow属性的理解有误,说白了是IE6的一个bug,IE7开始已经修复这个问题,也就是说IE7/IE8下overflow:hidden可以清除浮动造成的影响,您有兴趣可以自己测试一下。

对于zoom的包裹性…恩…还是先简单介绍下这个zoom属性吧,也很简单,就是比例缩放,跟CSS3中transform:scale作用一样(表现有些许差异),举个例子吧,看看zoom的表现,如下代码:

<div style="background:#f0f3f9; padding:20px; zoom:2;">
    <img src="mm1.jpg" border="0" />
</div>
 

结果如下图所示(由于zoom为IE私有属性,故对比IE和Firefox可见效果,左Firefox,右IE6):

firefox下效果

IE6下zoom效果 张鑫旭-鑫空间-鑫生活

可见在IE6下,zoom:2;让图片,包括外部的div放大两倍显示,IE7下也是如此,但是IE8下却有差异,在IE8(标准)下,zoom所放大的仅仅是内部元素,自身并没有放大,如下图:
IE8 zoom效果  张鑫旭-鑫空间-鑫生活

您可以狠狠地点击这里:zoom功能效果demo //zxx:这是第一次展示新demo页面,是不是比白板的要舒服些啊,O(∩_∩)O

同样是overflow美女图片的例子,现在zoom是要让元素放大或是缩小,我们可以这样想,要是没有zoom等属性,IE6和IE7下,浮动属性的图片的父div的高度塌陷,就是个痿蛋0;再假设现在有个div标签上有个zoom:2;的样式来放大父标签及里面图片2倍,肯定是从父标签开始拉伸缩放的,但是如果父标签是个塌陷高度,无论怎么拉伸,其高度依旧是那个0,也就是说拉伸根本就没有效果,这显然也不应该,于是“被动的包裹”似乎成为了必要。

对于IE8,则zoom属性无“包裹性”,正如上面IE8下截图显示,IE8 zoom放大的是内部元素,父标签不缩放,于是父标签即使是个痿蛋0,其与内部元素的缩放一点关系也没有,也就没有的包裹的必要。所以IE6/7 zoom有包裹性,IE8没有。

有人可能会质疑,明明就是zoom让IE haslayout,于是…… 我要问的是,你清楚的看得见这个haslayout吗?为什么haslayout可以清除浮动造成的影响?不急,下面我会解释为什么不用haslayout这个东西。

三、“包裹”与“清除浮动”

清除浮动造成的影响的方法有两大类,一类就是clear:both/left/right;清除,另外一类就是本文要讨论的“包裹”清除。

我在上部分提到的这些“包裹性”元素都可以清除浮动造成的影响,我们可以一个一个的来测试:

float:left
测试代码如下:

<div style="float:left; background:#f0f3f9; padding:20px;">
    <img style="float:left;" src="mm1.jpg" />
</div>

结果如下图:

清除浮动效果图

可见含有浮动属性图片的父标签的高度并没有塌陷。您可以狠狠地点击这里:float清除浮动造成的影响demo

position:absolute
测试代码如下:

<div style="position:absolute; background:#f0f3f9; padding:20px;">
    <img style="float:left;" src="mm1.jpg" />
</div>

结果与上图一模一样,不重复显示了。其他话就不多说了,您可以狠狠地点击这里:absolute清除浮动造成的影响demo

display:inline-block
测试代码如下:

<span style="display:inline-block; background:#f0f3f9; padding:20px;">
    <img style="float:left;" src="mm1.jpg" />
</span>

结果还是与浮动的效果图一样,节省篇幅,不重复显示了。其他话就不多说了,您可以狠狠地点击这里:inline-block清除浮动造成的影响demo

overflow:hidden
测试代码如下:

<div style="overflow:hidden; background:#f0f3f9; padding:20px;">
    <img style="float:left;" src="mm1.jpg" />
</div>

结果如下图:
清除浮动效果图

上图效果在Firefox,chrome,Safari以及IE8下会见到,至于IE6/7,我前面提过了,其对overflow:hidden的理解有误,另当别论。overflow:hidden属于“被动包裹”,故宽度没有包裹属性,依旧原延展性显示,高度包裹。

您可以狠狠地点击这里:overflow清除浮动造成的影响demo

zoom:1
zoom:1指的就是原大小显示,测试代码如下:

<div style="zoom:1; background:#f0f3f9; padding:20px;">
    <img style="float:left;" src="mm1.jpg" />
</div>

结果在IE6/7下与overflow:hidden在Firefox等现代浏览器下的效果一样,见下图:
清除浮动效果图

您可以狠狠地点击这里:zoom清除浮动造成的影响demo

从上面一系列的测试可以看到,“包裹”确实可以解决浮动造成的影响,或者说用“包裹”来解释为什么这些CSS属性可以修复浮动元素父标签高度塌陷的问题是可行的。

四、“包裹” – haslayout – 清除浮动造成的影响

就目前而言,就主流而言,在IE下清除浮动造成的影响是使用haslayout来解释的,确实很说的通,我也不否认其存在性。我很长一段时间也是使用haslayout来解释一些IE下的问题(清除浮动效果就是其一),但是我一旦想到Firefox等浏览器并没有haslayout的概念,为何其一些属性也能抑制浮动产生的影响呢?那么Firefox的浏览器抑制浮动副作用的原理是什么呢?有没有一个更好的概念解释所有这些浏览器下一些CSS熟悉抑制浮动副作用的原因呢?好,于是我就想到了“包裹”这个概念来解释,我发现使用“包裹”解释抑制浮动影响比haslayout更概括更有前途。

我觉得haslayout就是个要淘汰的东西,这是IE8说的。几举个例子,我们都知道IE6/7下设置width值会使元素haslayout,能够清除浮动造成的影响,例如设置width:100%;,这非常解释的通,但是IE8下呢?抱歉,IE8下设置width:100%根本就不鸟你,无法清除浮动的坏影响、我不清楚是IE8淡化了haslayout这个概念,还是width值与haslayout根本就不搭边?总之,在IE8下,使用haslayout解释一些现象(例如抑制浮动副作用)已经很吃力了,但是,使用“包裹性”来解释没有一点问题,要知道IE8下overflow:hidden可以清除浮动产生的影响,是因为overflow:hidden让IE有haslayout吗?我想应该不是吧,因为overflow:hidden具有“包裹性”。还有IE8下width值无法抑制浮动副作用,又是什么原因呢?因为width属性无“包裹性”可言,所以自然不会抑制浮动副作用。还有IE8的zoom为何不能清除浮动高度塌陷问题?因为IE8下的的zoom没有“包裹性”。

所以,对于IE下zoom清除浮动造成的高度塌陷问题,我使用了“包裹”来解释,而没有使用不知会不会淘汰的haslayout这个概念来解释。

五、最后的总结

本文首先以YY的方式将“清除浮动”这个概念用“清除浮动造成的影响”这个更准确的方式表述,然后列举一些具有包裹性的CSS属性,再通过实例证明这些具有包裹性的元素都具有抑制浮动副作用的作用,来证明使用“包裹性”这个概念可以解释为何有些元素可以消除浮动使父标签高度塌陷的问题。最后解释了为何不使用haslayout来解释清除浮动造成的影响。

希望讲的不要太乱,最后,还是老掉牙的话,都是些个人思考,有不正确之处难免,仅供参考,欢迎大力反驳,纠正等等。

(本篇完)

赞助商推荐(我也要赞助)

想学到点真东西? ×
如果你有1~3年前端开发经验,不妨 ×
想高薪入职阿里? ×
想通过真实互联网项目成长自己? ×


发表评论(目前26 条评论)

  1. n说道:

    能系统的总结hack吗 ie的

  2. 会潜水的猫说道:

    我觉得overflow:hidden清除浮动 是不是要计算内外的尺寸,所以容器就有了高度。

  3. tengteng说道:

    您好,根据http://www.w3chtml.com/css3/properties/user-interface/zoom.html中显示,zoom目前已不是IE的私有了吧

  4. 吴杨捷说道:

    用“包裹”的概念理解清除浮动很受启发

  5. 王尖儿说道:

    写得太好了

  6. 前端渣滓说道:

    IE 11和Chrome已经不能使用zoom清除浮动

  7. jara说道:

    li 里面的a元素设为float:left;后,在li 里面加上position: absolute或是overflow: hidden之类的都不好使。我在chrome里面测的。对li 不好使?

  8. 橡胶霸气说道:

    您好,我遇到了一个问题

    问题描述:我做了一个上传按钮,外层是以个相对定位的div,设置了overflow:hidden 和display:inline-block,div里面是两个按钮,一个file的,一个普通的,file的设成透明并且很大。

    出现的问题:现在至少在chrome下,是有问题,f12看这个div的高度,没有任何问题,但是包裹这个div的外层div的高度,却莫名其妙的在下方多处大约3、4像素的空白。

    实在不知道怎么回事

  9. killsos说道:

    .divv{border: 1px solid red;width: 400px; height: 400px;}
    .div1{border: 1px solid green; width: 100px; height: 100px;float: left;}
    .div2{border: 1px solid blue; width: 200px;height: 200px;overflow: hidden ;}

    为何对div2添加了overflow:hidden; div2就环绕div1?

  10. ningning110说道:

    讲的真好,豁然开朗。

  11. 一路说道:

    应该可以通过“Block Formatting Contexts”与“haslayout”结合解释更准确些,那就要看两者在什么浏览器下满足什么条件触发该属性了

  12. 54yuri说道:

    注释里面的字应该可以高亮: overflow特指overflow:hidden/scroll/auto属性,不包括overflow:visible;

    为什么不包括呢?根据 http://www.w3school.com.cn/css/pr_pos_overflow.asp
    http://www.qianduan.net/comprehensive-haslayout.html

    visible 默认值。内容不会被修剪,会呈现在元素框之外。
    hidden 内容会被修剪,并且其余内容是不可见的。
    scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
    auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。

    我的理解是:所以对于

    1)FF/chrome 等严格遵守w3c规则的来说,既然允许“ 内容可以被修剪”,那么就不允许内容跑出父元素之外了,也就是说父元素这是高度不能塌陷,它得包裹着子元素

    2)对于IE来说,overflow:非visible , 触发了haslayout, 父元素自行维护内部的布局,既然自行维护,就不会让子元素随随便便的跑出自己的外面,让自己高度塌陷

    不对地方请欢迎讨论

    • taoliujun说道:

      非常赞同你的理解:既然允许“ 内容可以被修剪”,那么就不允许内容跑出父元素之外了,也就是说父元素这是高度不能塌陷。。。

  13. x说道:

    In fact IE 8 just learnt to obey the rules…

  14. pb160说道:

    关于”zoom清除浮动造成的影响demo”。在标准浏览器下没有没有清除浮动啊!

  15. gaby说道:

    overflow的包裹性有点牵强,推理倒置,没有说出来“为什么”,而是根据现象推出应该是“包裹性”

  16. Dailey说道:

    Block Formatting Contexts
    你可以用块级上下文来理解你所称的“包裹”

  17. 赵弟栋说道:

    zoom:1; ie6 ie7 haslayout
    overflow:hidden; ie8 block formatting context

  18. Ryan说道:

    感觉主动包裹和被动包裹是在实例验证之后才得出的
    前面几段的推理不能很确切的从概念上区分出来
    或许是我的理解不够

    anyway 感谢zxx的分享 我刷新了对haslayout的认识

  19. 墨枫说道:

    zoom这个属性在chrome以及safari这两个浏览器下也能起作用,且效果跟IE6/IE7一样,外部的div也被撑大~~

  20. maooson说道:

    我对inline-block的理解:对内呈现block的特性,对外(相对于其兄弟节点,包括文本)呈现inline的特性。不知道这样讲对不对?

  21. dony说道:

    博主,overflow在ie7下是可以的哦,只有IE6不能包裹住…