转自:http://blog.163.com/tang_howell/blog/static/3144675020116102543221/
在学习页面布局的过程中,涉及到了清除浮动的问题,其中提到了在不增加结构化标签的情况下清除浮动的方法,但原文都是英文,为方便理解,DD浩决定花点时间翻译这篇好文章。原文标题是:《How To Clear Floats Without Structural Markup》。针对文章中出现的陌生词汇,DD浩在翻译中作了相关的拓展说明。
Clearing Floats The Old Fashioned Way
When a float is contained within a container box that has a visible border or background, that float does not automatically force the container's bottom edge down as the float is made taller. Instead the float is ignored by the container and will hang down out of the container bottom like a flag. Those familiar only with Explorer for Windows may scratch their heads and say "That's not right!" True, IE/Win does enclose a float within a container 'automatically', but only if the container element happens to possess the MS-only quality called hasLayout.
当包含浮动层的容器有一个边框或者有背景时,浮动层不会因为更高的浮动自动强制迫使容器的底部边缘撑开。相反,浮动会被容器忽略,会像方块一样超出容器底部的边缘范围。那些在windows下用IE的人员可能产生疑问,并说 “那样不正确“。的确,IE能自动适应高度以包围浮动,但这样的容器元素仅发生在激活微软专有属性“haslayout”的情况下。
DD拓展:关于haslayout
“haslayout”是指获得布局的特性,只要给容器确定个任意尺寸就激活了。当一个元素的 hasLayout属性值为true时,我们说这个元素有一个布局(layout),它负责对自己和可能的子孙元素进行尺寸计算和定位。一个“layout元素”可以是一个默认就拥有 layout 的元素或者是一个通过设置某些 CSS 属性得到 layout的元素。如果某个HTML元素拥有 haslayout 属性,那么这个元素的 haslayout 的值一定只有 true,haslayout为只读属性,一旦被触发,就不可逆转。通过 IE Developer Toolbar 可以查看 IE 下 HTML元素是否拥有haslayout,在 IE Developer Toolbar 下,拥有 haslayout的元素,通常显示为“haslayout = -1”。
负责组织自身内容的元素将默认有一个布局,主要包括以下元素(不完全列表):
* body and html
* table, tr, th, td
* img
* hr
* input, button, file, select, textarea, fieldset
* marquee
* frameset, frame, iframe
* objects, applets, embed
大部分的 IE 显示错误,都可以通过激发元素的 haslayout 属性来修正。可以通过设置 css 尺寸属性(width/height)等来激发元素的 haslayout,使其“拥有布局”。如下所示,通过设置以下 css 属性即可:
* display: inline-block
* height: (任何值除了auto)
* float: (left 或 right)
* position: absolute
* width: (任何值除了auto)
* writing-mode: tb-rl
* zoom: (除 normal 外任意值)
Internet Explorer 7 还有一些额外的属性(不完全列表)
* min-height: (任意值)
* max-height: (除 none 外任意值)
* min-width: (任意值)
* max-width: (除 none 外任意值)
* overflow: (除 visible 外任意值)
* overflow-x: (除 visible 外任意值)
* overflow-y: (除 visible 外任意值)
* position: fixed
其中 overflow-x 和 overflow-y 是 css3 盒模型中的属性,目前还未被浏览器广泛支持。
对于内联元素(默认即为内联的元素,如 span,或 display:inline; 的元素), width 和 height 只在 IE5.x 下和 IE6 或更新版本的quirks 模式下触发 hasLayout 。而对于IE6,如果浏览器运行于标准兼容模式下,内联元素会忽略 width 或 height 属性,所以设置 width 或 height不能在此种情况下令该元素具有 layout。 zoom 总是可以触发 hasLayout,但是在 IE5.0 中不支持。
具有“layout”的元素如果同时 display: inline ,那么它的行为就和标准中所说的 inline-block很类似了:在段落中和普通文字一样在水平方向连续排列,受vertical-align影响,并且大小可以根据内容自适应调整。这也可以解释为什么单单在 IE/Win 中内联元素可以包含块级元素而少出问题,因为在别的浏览器中display: inline 就是内联,不像 IE/Win 一旦内联元素拥有layout还会变成 inline-block。
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
IE6 及更低版本的双空白边浮动 bug
修复: display:inline;
IE5-6/win 的 3 像素偏移 bug
修复: _height:1%;
IE6 的躲躲猫(peek-a-boo) bug
修复: _height:1%;
The W3C suggests placing a "cleared" element last in the container box, which is then recognized by the container height, forcing the container to enclose the float above that cleared element too. It's described more fully our articleFloat: The Theory:
“..let's say you give that following box the clear property, {clear: both;} . What this does is extend the margin on the top of the cleared box, pushing it down until it "clears" the bottom of the float. In other words, the top margin on the cleared box (no matter what it may have been set to), is increased by the browser, to whatever length is necessary to keep the cleared box below the float.”
W3C建议在容器的末尾增加一个“clear:both"的元素,强迫容器适应它的高度以便装下所有的float。正如下面所描述的:
“你给随后的盒子添加清除浮动特性,这样做是扩展cleared盒子的顶部边距,推动它直到浮动层的底部。换句话说,cleared盒子的顶部边距在浏览器中是增加的,其顶部边距的增加长度,必须使cleared盒子在浮动层之下。”
So in effect, such a cleared box cannot be at the same horizontal level as a preceding float. It must appear just below that level. The image shows how this might look, with a red border representing the container element:
这样的“clear:both;”容器不可能跟它前面一个float元素处于同一个水平高度。它必须正好出现float元素的下方。下面的一个图描述了具体情况,红色的框框代表外围容器:
The standard method of making an outer container appear to "enclose" a nested float is to place a complete "cleared" element last in the container, which has the effect of 'dragging' the lower edge of the containing box lower than the float. Thus the float appears to be enclosed within the container even tho it really isn't. The code for a cleared box usually looks something like this:
使外围容器自动适应高度以便包容下所有的float元素的标准方法是在外围容器最末尾放置一个“clear:both"元素,它的作用就是使外围容器的底部比float元素的底部更低,这样就包容下了所有的float元素。代码是像这个样子的:
<div> <!-- float container --> <div style="float:left; width:30%;"><p>Some content</p></div> <p>Text not inside the float</p> <div style="clear:both;"></div> </div>
Since that div is not floated, the container must recognize it and enclose it, and because of that top margin (added by the browser because of the "clear" property), the div "pulls" the bottom edge of the container down below the bottom edge of the float.
因为这个清除浮动的DIV没有浮动,容器必须识别它并把它包围。又因为顶部边距(被浏览器添加,因为CLEAR特性),这个DIV就推动着容器的底部边缘,使之低于浮动的底部边缘。
First and foremost, this clearing method is not at all intuitive, requiring an extra element be added to the markup. One of the major premises of CSS is that it helps reduce the bloated HTML markup found it the average site these days. So having to re-bloat the markup just so floats can be kept within their containers is not an ideal arrangement.
Besides that, some browsers can have trouble with certain kinds of clearing elements in some situations. Mozilla is particularly sensitive to clearing problems.
Up 'til now there was no other way to do this, but no more! Thanks to the efforts of Tony Aslett, creator and operator of csscreator.com, we can now use advanced CSS to "clear" a float container in non-IE browsers and just let IE keep wrongly clearing itself. The upshot is that we now have the option to avoid adding that pesky clearing element to the HTML markup. Woohoo!
这段文字,是说明使用添加标记这种方法会导致一些问题。不再翻译了。接下来是新的解决办法。
In the new method, no clearing element is used. This does not affect IE/Win which simply keeps enclosing the float as always (assuming the container has a stated dimension), but non-IE browsers will need a substitute for that element. Here's how it's done.
在新的方法中,不用添加多于的元素,这个方法仅对非window下的IE有效,针对windows下的IE的补救方法等下会提到。下面说明是怎么做到的.
This CSS 2 property allows extra content to be added at the end of an element via the CSS. That means no actual markup is needed in the HTML. The content is specified from within the CSS stylesheet, and appears in the page as would a real HTML element that had been inserted following all the normal content of the target element. Such :after generated content cannot receive some CSS properties, including 'position', 'float', list properties, and table properties. However, the 'clear' property is allowed. Do you see where we are going here?
Imagine that we use :after to insert a simple character like a 'period', and then give that generated element {clear: both;} . That's all you really need to do the job, but no one wants a line space messing up the end of their clean container box, so we also use {height: 0;} and {visibility: hidden;} to keep our period from showing.
这个css2的属性允许额外的contant通过css加入到元素尾部。这就意味着没有多余的标记添加到容器中。这个contant在css中被解析,然后以正确的html代码插入到容器尾部,这个:after产生的contant不能接受某些属性,包括'position','float',列表属性,表格属性,但是clear属性可以被接受。你明白了我们将做什么吗?
想象一下我们用:after插入一个简单的字符比如小点号,然后使其产生这样的元素 {clear:both}。这就是所有你要做的,但是没有人想要容器的最底部有一条小横线,是吧?所以我们用{height:0}和{visibility:hidden},是我们的小点号不被显示。
恩,看起来应该是这个样子的:
.clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
Notice that {display: block;} is also applied to the :after element, because if it isn't then that element defaults to "inline", and cannot receive the "clear" property. Also, Tony's method originally used "overflow: hidden;" to hide the period, but sadly the latest FireFox versions will display the period if this is done.
注意这个{display:block;}也被加入到:after中,因为默认情况下产生的那个元素的display属性值为inline,而display为inline的元素不能接受clear属性。
Since IE7 does not support the :after pseudoclass yet, we must rely on the same"auto-clearing" effect used for IE6, and that behavior happens when the float-containing element gets hasLayout applied to it. A simple declaration of "zoom: 1;" will perform this trick in IE5.5 and up, but it's proprietary and needs to be hidden in order to validate.
由于IE/win没有:after特性,我们必须依赖于他的"auto-clearing"特性,但是这个特性仅仅出现在容器已经被赋予了一个尺寸的条件下。简单的方法是设置zoom:1;但它只对IE5.5及以上的版本有效,而且需要设置validate为hidden。
在很多情况下我们都不想用width或者height,但是令人高兴的是Holly找到了一种方法。这个方法要让 IE/win(并且仅仅IE/win)下的容器的高度为1%,这有什么用呢?well,IE/win有一个特殊的特性,只要给容器一个尺寸,它能使容器自动扩展以便适应它所包含的内容,即便给它的尺寸非常小,所以1%的height在任何情况都是扩展高度适应它的内容,因为你的内容再小也不可能比1%还小吧!!很酷,是吧 ?
/* Hides from IE-mac \*/ * html .clearfix {height: 1%;} /* End hide from IE-mac */
第一行是一条css注释,在注释的关闭标签(*/)前面正好有一个\符号,这就是精华所在,由于有这个反斜杠,IE/mac会忽略后面的关闭标签(*/),认为后面的仍然是注释(第2行被认为是注释),直到遇到一个*/为止,所以在IE/mac下上面的代码整个都被忽略了,而在 IE/win下不会,仅仅只把第 1 3行看作是注释,第2行看作是正常的css代码。
.clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } .clearfix {display: inline-block;} /* for IE/Mac ,Basically the fix is just a matter of applying a display: inline-block; to the .clearfix class, and hiding that property from all other browsers. That's it! We can easily do this with our existing code, slightly modified. */ /* Hides from IE-mac \*/ * html .clearfix {height: 1%;} /* End hide from IE-mac */
Simple Clearing of Floats
Solutions:
a) The Markup Method: The first and W3C-recommended approach is a little ugly – extra markup. At the very end of your content, toss in a cleared element – typically something like
<br style="clear:both"/>
. It’s the HTML equivalent of wedging matchsticks into your window frame to jam a window open. This works, but ‘dirties your page’ with stuff that only exist so it renders properly.
b) The Aslett/PIE Method: Less than 12 months ago Tony Aslett working with PositionIsEverything.com came out with a new method so diabolically clever that they had to have been sitting in a fake island volcano, stroking a large white cat and laughing fiendishly when they thought of it.
You’ll need to read the tutorial to get the full story, but, in short, they use a little-known, rarely-used pseudo class (:after) to place a hidden, cleared full-stop after the content. Combined with a sprinkling of hacks, this works beautifully – but gives me a headache over my left eye when I think about it.
c) The Ordered List Method: Last October Steve Smith from Orderlist.com published a slightly simpler method. Again, read his tutorial to get the low-down, but in short, his method involves ‘Floating nearly Everything’ (FnE), which naturally enough includes the outer DIV. This can have a considerable effect on the way your design stacks and as Steve says ‘it takes a little more tweaking’ but in general this method seems a little more robust to me.
d) That was my ‘current state of play’ until last week when SitePoint Forum’s own CSS Guru, Paul O’Brien, nonchalantly pointed out that adding a ‘overflow:auto’ to the outer DIV did the trick.
Half an hour of testing later, I was amazed to find Paul was 100% correct – as this example shows. It seems that reminding the outer DIV that it’s overflow is set to ‘auto’, forces it to think “oh yeah.. I’m wrapping that thing, aren’t I?”.
This fact is so boringly simple that it’s hard to know if thousands of developers are well aware of it, but never thought to mention it. I know I showed the example page to four CSS-savvy SitePoint colleagues and all shock their heads, blinked slowly and said “Whaa…?” (or something similar).
From my testing, it seems to work identically in virtually every browser. Even IE4 seems to love it – only NS4 freaks out, and I’m not totally convinced a few hacks couldn’t get that working.
We haven’t had time yet to thoroughly test this method under rigorous match conditions, but so far there don’t seem to be any major drawbacks.
Certain combinations of margin and padding can force internal scrollbars. If you can’t ‘massage’ them away, we found ‘overflow:hidden’ has virtually the same effect without the scrollbars. The only drawback of ‘hidden’ seems to be the cropping of some images if they’re placed lower in the page.
DD拓展:三种实用CSS清除浮动方法总结
一、使用空标签清除浮动
我用了很久的一种方法,空标签可以是div标签,也可以是P标签。我习惯用<div>,够简短,也有很多人用<hr>,只是需要另外为其清除边框,但理论上可以是任何标签。这种方式是在需要清除浮动的父级元素内部的所有浮动元素后添加这样一个标签清楚浮动,并为其定义CSS代码:clear:both。此方法的弊端在于增加了无意义的结构元素。
二、使用overflow属性
此方法有效地解决了通过空标签元素清除浮动而不得不增加无意代码的弊端。使用该方法是只需在需要清除浮动的元素中定义CSS属性:overflow:auto,即可!"zoom:1"用于兼容IE6。
三、使用after伪对象清楚浮动
该方法只适用于非IE浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须为需要清除浮动元素的伪对象中设置height:0,否则该元素会比实际高出若干像素;二、content属性是必须的。
总结下第二种方法:清除浮动可以用 overflow:hidden 或 overflow:auto ,在比较标准的浏览器里没有问题,但 IE6 没有效果,为了兼容 IE6 ,可以为父元素:
1、设置一个合适的宽度,但“合适的宽度”有的时候不好掌握;
2、加上 height:1% ,什么都不用管,加上就有效,还没有发现缺点;
3、加上 zoom:1 ,不能通过W3C验证。
为了兼容 IE6 的这三种方法根据自己的实际情况和个人喜好选择吧。