clear属性能把父元素自动撑高,其背后的实现原理是什么?

    <div id="container" style="border:1px dotted #CCCCCC">
        <div id="floatLeft" style="float: left;width:20em;height:10em;border:1px solid #c72d2d;background-color: beige">float:left</div>
        <div id="clearBoth" style="background-color: #00a23f;border:1px solid #c72d2d;clear:both;width:50em;height:1em">clear both </div>
    </div>

针对上面的代码有几个问题,请教大家:
1。div#container(height=auto)的高度将被自动计算,包含div#floatLeft和div#clearBoth,其背后的实现规范是什么呢?
2.clear属性的规范有云

The floats that are relevant to be cleared are the earlier floats
within the same block formatting context.

这个怎么理解呢?
3.按规范所述 div#container 加上 overflow:hidden属性后将形成一个BFC,那么这个BFC和div#floatLeft形成了BFC有什么关系么?有包含关系?
4.根元素也能形成一个BFC,那么是不是可以这样理解:div#floatLeft在这个BFC里?

谢谢~

阅读 4.7k
1 个回答

谢邀。

如果不想看分析,我先把自己的结论放这里:

  1. 实现规范参照 CSS2.1 的 10.6.3 节

  2. 清除的浮动是在前面的那些,后面的浮动不考虑

  3. 没关系

  4. 不在

其实这些问题在 CSS2.1 的规范里都有说明。整理下题主的问题,我重新从以下三点作答下:

高度计算

本案例中,根据 #container 是否有 overflow: visible 分两种情形:

  • overflow 计算为 visible 时的文档流内块级不可替换元素

  • 块格式化上下文根

默认地,#containeroverflow 取默认值 visible,故根据 CSS2.1 规范 10.6.3 的描述,计算方式是:

如果 heightauto,则该高度取决于该元素是否有块级子元素以及该元素是否有内边距或者边框:
该元素的高度是从其上内容边缘到如下第一个符合情形的距离:

  1. 其最后一个行盒的下边缘,如果该盒建立了一个包含一行或多行的行内格式化上下文

  2. 其最后一个文档流内子元素的下(可能折叠)外边距的下边缘,如果该子元素的下外边距没有同该元素的下外边距折叠

  3. 其最后一个文档流内子元素的下边框边缘,如果该子元素的上外边距没有同该元素的上外边距折叠

  4. 否则零

只有文档流内的子元素才在考虑范围之内(如,浮动盒和绝对定位盒要被忽略,相对定位盒则不考虑其位移)。注意子盒可能是个匿名块盒。

本案例中的情形是第2种,即从 #container 的上内容盒边缘到 #clearBoth 的下边框边缘,#floatLeft 本身是被忽略的(但由于清除浮动的原因,#clearBoth 下挪了,故最后的高度包含了 #floatLeft)。

而如果有了 overflow: hidden,则 #container 建立了块格式化上下文,则应当遵循 10.6.7 规定:

如果该元素有块级子元素,其高度为最上块级子盒的上外边距边缘到最下块级子盒的下外边距边缘的距离。

此外,如果该元素有下外边距边缘低于该元素下内容边缘的浮动子元素,那么高度将增大来包含那些边缘。只有参与本块格式化上下文的浮动才考虑在内,比如,在绝对定位后代中的或者其他浮动中的浮动就不考虑。

故此时,如果没有清除浮动,#container 的高度也得高到能把 #floatLeft 的高度包含进去,这也是清除浮动的办法之一。

盒与格式化上下文、以及格式化上下文之间的相互关系

首先要明确下块格式化上下文的概念,根据 9.4 和 9.4.1:

常规流中的盒子都属于某个格式化上下文,要么块格式化上下文,要么行内格式化上下文,总之不能二者得兼。块级盒参与块格式化上下文,行内级盒参与行内格式化上下文。

浮动、绝对定位元素、非块盒的块容器(如:行内块、表格单元格以及表格标题)以及 overflow 属性不为 visible 的块盒(除了该值被传播到视口的情况)将为其内容创建一个新的块级格式化上下文。

从以上两点,我认为:

  1. 块格式化上下文探讨的是块容器盒和块盒同它们的常规流中子块级盒的关系,上下文之间的相互关系很少被提到

  2. 块格式化上下文内部元素(或盒)是在文档流内的,浮动元素或绝对定位元素脱离文档流,故不参与块格式化上下文。所以根元素虽然建立块格式化上下文,但 #floatLeft 并不在其中

  3. 不参与块格式化上下文不意味着不能建立块格式化上下文(通俗理解就是我不当你的臣子,我自己当皇帝),所以尽管 #floatLeft 不在任何块格式化上下文内,但它自己可以为自己的子块级盒建立块格式化上下文

清除浮动的位置影响

直接看代码:

<body>
<div id="right" style="float: right; width: 30px; height: 30px; background: blue;"></div>
<div id="clear" style="height: 30px; background: red;"></div>
</body>

通俗理解下,#right 先报到,占了第一排,但没有占满;#clear 来的时候看到 #right 已经占坑了,但其 clear: none(默认),#clear 就不介意和 #right 一排,跑去填满剩下的空间,二者并列

<body>
<div id="right" style="float: right; width: 30px; height: 30px; background: blue;"></div>
<div id="clear" style="clear: right; height: 30px; background: red;"></div>
</body>

假如 clear 属性不为 none#clear 就喜欢自己占一行去,不跟 #right 挨着,越过它自己占第二排。

<body>
<div id="clear" style="clear: right; height: 40px; background: red;"></div>
<div id="right" style="float: right; width: 30px; height: 30px; background: blue;"></div>
</body>

而如果交换下二者顺序,如上,情况变成了:#clear 先来,前面没有任何浮动占空间,那自己占满一排,自己都占好了后来的家伙怎么占都无所谓;#right 后来,第一排都被占完了,乖乖占第二排去。

所以其实就是清除浮动只考虑前面的,后面的管不着。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏