`
yiminghe
  • 浏览: 1434209 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

转载:闭合浮动元素

阅读更多

updated : 2010-11-08


Web前端标准在各浏览器中的实现差异

 

按照CSS规范,浮动元素(floats)会被移出文档流,不会影响到块状盒子的布局而只会影响内联盒子(通常是文本)的排列。因此当其高度超出包含容器时,一般父容器不会自动伸长以闭合浮动元素。但是有时我们却需要这种自动闭合行为,具体如何处理呢?

  有一种做法 就是在父容器内再插入一个额外的标签,并令其清除浮动(clear)以撑大父容器。这种方法浏览器兼容性好,没有什么问题,缺点就是需要额外的(而且通常是无语义的)标签,所以我个人不大喜欢。

  后来 又 有了一种新的方式,使用 :after 伪类动态的嵌入一个用于清除浮动的元素,这种方法和上一种原理一样,不同的只是把这个额外的内容用 CSS 生 成,但考虑到 IE 不支持 :after 不得不做了不少的 hack。这种方法兼容性一般,但经过各种 hack 也可以应付不同浏览器了,同时又可 以保证 html 比较干净,所以用得还是比较多的。

  再后来 又有人发现将父容器 的 overflow 设为除 visible 之外的值就可以在标准兼容浏览器中闭合浮动元素,IE自然又是不支持的,所以这种方法和上一种方法一样都 对 IE 做了不同处理(具体就是触发layout ),不同的就是overflow 没有 :after 伪类那么麻烦了,缺点也 有,overflow 可能会产生一些小冲突。

  在使用 overflow 之前 还有过一种使 用 float 的方法,就是让父容器也浮动,这利用到了浮动元素的一个特性——浮动元素会闭合浮动元素。这种方式在 IE/Win 和标准兼容浏览器中 都有较好的效果,但缺点也很明显——父容器未必想浮动就浮动的了,毕竟浮动是一种比较特殊的行为,有时布局不允许其浮动也很正常。使用 float 虽然 在 IE 和标准兼容浏览器中都能闭合浮动元素,但原理却是不同的,IE/Win 中 float 触发了 layout 因而闭合了浮动,而在标准兼容 浏览器中,float 其实和上一种方法中的 overflow 原理一样,产生了一个“块级格式化范围”——这是CSS 规范中提到的一种现象,它往往 具有某种独立性,特性之一就是会自动闭合内部的浮动元素。

  按照规范,以下类型的元素会产生一个块级格式化范围:

ww.52css.com]
  ● 浮动元素,left 或者 right 皆可。
  ● 绝对定位的元素。
  ● inline-block 元素,不过这个 gecko目前不支持。
  ● table-cell 类型元素,其实 table, table-head-group, table-row 什么的也都可以,还有inline-table(gecko不支持)也同样,因为他们都会间接产生一个匿名的 table-cell。
  ● overflow 取值非 visible 的元素。


  所以,原来在标准兼容浏览器中我们也可以有这么多的方法闭合一个浮动元素,而且只需要 CSS,无需其他。顺带说一下以上除了overflow,其余都有一个附加效果就是自动收缩父容器宽度。

  而对于 IE/Win,它有一套自己的体系,就是 layout,具有 layout 的元素会自动闭合浮动元素,再来看看触发 layout 的 CSS 属性,会发现和上面的块级格式化范围有很多类似之处:

.52css.com]
  ● 浮动元素
  ● 绝对定位元素
  ● display:inline-block
  ● zoom
  ● width/height
  ● overflow/overflow-x/overflow-y [IE7 新增]
  ● max/min-width/height [IE7 新增]


  以上来看 IE 中闭合浮动元素的方法也不少,自然也都有其局限性,要么有附带效果,要么使用的是非标准属性(无法通过验证)。

   还要提一点的是 display:inline-block,这个属性对 IE 而言本身没什么用,实际效果只是给一个元素暗地添加了 layout, 但是标准兼容浏览器是认得这个属性的,所以要不影响这些浏览器,需要将 display 设回默认。这里 IE 有一个 bug,如果先定义 了 display:inline-block,然后再将 display 设回 block(这两个 display 要先后放在两个 CSS 声明中 才有效果),那么 layout 不会消失,同时也不会影响其他浏览器,所以目前来说,这也算一个不错的触发 layout 的方法:

.52css.com]
.gainlayout{display:inline-block;}
.gainlayout{display:block;}


  所以要跨浏览器闭合浮动元素,可以选择的方式还是很多的,如何搭配使用这些 CSS 属性就要具体情况具体分析了,灵活应用条件注释也很有必要,要是实在不行我们回过头来还有 clear 可以用嘛。


How To Clear Floats Without Structural Markup

Clearing Floats The Old Fashioned Way

当一个有边框或者有背景的容器包含float时,float不会自动强制迫使容器的高度自动增加以便适应将所有的float包含进去。相反,容器会忽略 float,这样float会超出容器的范围(底部)。那些之用windows下的IE的人员会强烈反抗“那不正确“。的确,IE会根据float自动适 应高度,但那只限于容器有个确定的尺寸,在很多情况下并没有想象的那么好,而且用IE的用户仅仅占一部分。

W3C建议在容器的末尾增加一个“clear:both"的元素,强迫容器适应它的高度以便装下所有的float。正如下面所描述的:

“..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.”

所以这样的”clear:both"容器不可能跟它前面一个float元素处于同一个水平高度。它必须正好出现float元素的下方。下面的一个图描述了具体情况,红色的框框代表外围容器:


使外围容器自动适应高度以便包容下所有的float元素的标准方法是在外围容器最末尾放置一个“clear:both"元素,它的作用就是使外围容器的底部比float元素的底部更低,这样就包容下了所有的float元素。代码是像 这个样子的:

 

<!--  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 >

 

Problems With The Method


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!

"Clearing", 21st Century Style

在新的方法中,不用添加多于的元素,这个方法仅对非window下的IE有效,针对windows下的IE的补救方法等下会提到。下面说明是怎么做到的.

Using :after

这个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 ;
}
 


注意这个{display:block;}也被加入到:after中,因为默认情况下产生的那个元素的display属性值为inline,而display为inline的元素不能接受clear属性。

But what about IE?


由于IE/win没有实现css2,也就没有:after特性,我们必须依赖于他的"auto-clearing"特性,但是这个特性仅仅出现在 容器已经被赋予了一个尺寸的条件下。在很多情况下我们都不想用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代码。

Putting It Together

.clearfix:after  {
    content :  "." ;  
    display :  block ;  
    height :  0 ;  
    clear :  both ;  
    visibility :  hidden ;
}

/*  Hides from IE-mac \ */
* html .clearfix  { height :  1% ; }
/*  End hide from IE-mac  */ 
 

 


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 .

This float-enclosing behavior in IE can also be 'toggled' off again just by hovering of links within the container, if that hovering alters either the link background or one of several other CSS properties. Quite a mess, and we'll cover it farther along in the article, in the "Toggle Trouble" section.

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 article Float: 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.”

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:

Shows how a box may clear below a 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:

<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.

Problems With The Method

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!

"Clearing", 21st Century Style

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.

Using :after

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.

.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.

But what about IE?

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.

As a side benefit, hasLayout on float-enclosing elements also prevents several other major IE/Win float bugs. However, should this container box be placed following a previous external float, the IE height fix will trigger Microsoft's proprietary and illegal Float Model , so watch out for that, okay?

Toggle Trouble

It so happens that IE has, well, a little problem with this auto-enclosing behavior. You saw that coming, didn't you. Yes, IE bugs come in big bunches. This one results when that container element has links inside, following the float. When this happens and certain links are hovered, the auto-enclosing behavior is toggled or "switched off", causing the lower edge of the container box to suddenly jump up to the bottom of the non-floated content. Hovering other links restores the behavior. This interesting effect is of course called the IE/Win Guillotine Bug Those of you viewing in IE/Win may play around with the following live demos, and for a more complete explanation see the IE/Win Guillotine Bug demo page .

The toggling only occurs when a:hover is used to change the link background or many other styling changes, such as padding , margin , or any font styling on the link. Strangely, having the text color not toggle the bug. change on hover does

The containers are grey with green borders, and the floats are dark brown with yellow borders. Notice how the third and fourth links ouside the floats toggle the Guillotine Bug, and the first two un-toggle it. This seems to be related to the actual text lines themselves, so any links after the first two lines will toggle the effect. Links in the float will all un-toggle the effect. Just more weird IE bug behaviors, folks, nothing "unusual".


Screenshot

 

The second demo has been "fixed" by placing those links in a paragraph, which then gets the zoom fix applied to it. Any block element will do just as well here. Yes, this means another element is needed, but unlike a clearing div, this paragraph is a "semantic" element. Text content really ought to be wrapped in semantic containers anyway, and since we forward-thinking coders always have our content thusly contained, it's easy to apply the same .clearfix class to one more element.

A Word About Floats In Floats

Observant readers will have noticed that the above demos have "enclosed" floats, even in Opera 7 and Mozilla! This is because the demos themselves are floats, and all modern browsers (including IE, luckily) always let floats enclose other floats. Of course there has to be an outer float, and it still threatens to break out of its container...

Putting It Together

First, this code gets added to the CSS stylesheet:

 

<style type="text/css">

  .clearfix:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
    }

</style><!-- main stylesheet ends, CC with new stylesheet below... -->

<!--[if IE]>
<style type="text/css">
  .clearfix {
    zoom: 1;     /* triggers hasLayout */
    }  /* Only IE can see inside the conditional comment
    and read this CSS rule. Don't ever use a normal HTML
    comment inside the CC or it will close prematurely. */
</style>
<![endif]-->

For the HTML, just add a class of .clearfix to any element containing a float needing to be cleared, plus any Guillotine-Bug-fixing block elements within the container. That's it! It's not perfect, but it's a whole lot better than adding an entire extra 'dummy' element. Check out this live demo of the fix in action:

IE/Mac Strikes Back

All this is wonderful, but unfortunately IE for the Mac does not "auto-clear" floats, and also does not support :after , and so is left out of the clearing party. What's to be done?

You might callously abandon IE/Mac, but consider that many people who use older Macs can't run Safari, or several other modern browsers. Thankfully this browser has been dropped by Microsoft, and at some future time the numbers of such IE/Mac users will become miniscule. Remember that even if a float appears to stick out of a container, no content will actually be obscured. It just won't look as pretty for those few viewers, that's all. Each author will have to decide on this issue according to their specific needs.

This page once described a Javascript method to force compliance in IE/Mac, but now thanks to Mark Hadley and Matt Keogh it's now possible to dispense with that ugly Javascript and go with a straight CSS fix. Woohoo!

Taming the IE/Mac Float Problem

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.

 

<style type="text/css">

  .clearfix:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
    }

.clearfix {display: inline-block;}  /* for IE/Mac */




</style><!-- main stylesheet ends, CC with new stylesheet below... -->

<!--[if IE]>
<style type="text/css">
  .clearfix {
    zoom: 1;     /* triggers hasLayout */
    display: block;     /* resets display for IE/Win */



    }  /* Only IE can see inside the conditional comment
    and read this CSS rule. Don't ever use a normal HTML
    comment inside the CC or it will close prematurely. */
</style>
<![endif]-->
 

The .clearfix {display: inline-block;} is seen by all browsers, and fixes IE/Mac. Then, inside the rule set that is hidden from IE/Mac, the display is reset to block . That's all she wrote! Simply stick the above code into your CSS, and use .clearfix on any box that has to contain a sizable float. Ain't that cool? Just watch out for previous external floats triggering the IE Float Model , as mentioned earlier.

Kudos to Alex Robinson for finding that inline-block is superior to the older inline-table fix for IE/Mac.

A Word Of Warning (this is important!)

The W3C float specification requires that a cleared element shall stay below all previous floats . There are no exceptions to this requirement! "Previous" in this case means any float that comes earlier in the source document.

Up until November of 2004, Firefox was still incorrectly clearing only the floats that were vertically above the clearing element, rather than all previous floats. This meant that in those earlier Gecko browsers you could place a floated column down one side of the screen, and inside another column (possibly another floated column) you could clear a smaller interior float, without that cleared element dropping below the previous floated column . Since only Gecko had this problem, it was obvious that something was wrong every time this happened to a page. Normally Gecko is the good browser, but in this one case it was the culprit. See, IE is not always the bad guy!

However, this easy clearing method has muddled the issue quite a bit, since now Explorer is not actually being cleared at all, while Gecko browsers have finally been corrected so they do clear all previous floats.


...Oh no! Do you see what will now happen in our hypothetical float page? IE, seeing no real clearing elements, will look great. Meanwhile, in newer Gecko browsers and Opera 7, the CSS generated clearing element in the first easycleared box will drag the height of that box waaaay down the page, until that invisible clearer is vertically below the bottom of the previous float column (assuming there is a bottom!). This can "generate" a huge empty space inside that once-small easycleared box, depending on the actual height of the neighboring float column.

Of course Opera 7 has always correctly implimented the clearing specs just like IE does (aside from bugs), and the Mac browsers are not involved either. If you are wondering how this issue can be fixed, well, it can't. Gecko and Opera are now both following the float clearing specs correctly, and IE only fails because of the faked "clearing" we are forcing upon it.

Preventing External Clearing

If you have the above described problem, one way to prevent the clearer from clearing the adjacent float column is to make the container a float itself. Of course once you float the container you no longer need easyclearing, sigh...

Note that when all the main elements in a column setup are floats, the worst IE float bugs simply do not happen. Thus using an all-float approach to column design can actually be easier to accomplish, at least within a rigid-width layout.

Them That Done It

Thanks to Tony Aslett for showing us the way. His site, csscreator.com is a killer CSS forum where newbies and gurus alike hang out and exchange CSS know-how. Tony's original demo page for this method can be found here , and the relevant forum thread is here .

Kudos also to Doug for pointing out the "period problem" in FireFox, and to Mark Hadley for that elegant IE/Mac fix, and to Matt Keogh for showing how "inline-table" also fixes IE/Mac while using an already-approved CSS property. Once more the CSS community comes thru for us all! :-)

 

  • 大小: 9.2 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics