块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

时间:2023-03-08 16:19:15

CSS的可视化格式模型中具有一个非常重要地位的概念——定位方案。定位方案用以控制元素的布局,在CSS2.1中,有三种定位方案——普通流、浮动和绝对定位:

普通流:元素按照先后位置自上而下布局,inline元素水平排列,直到行被占满后换行,block元素则被渲染为完整的一行,除非指定,所有元素默认为普通流定位。

浮动:浮动布局中,元素首先按照普通流位置出现,然后根据浮动方向尽可能向左或右偏移,效果与文本环绕相似。

绝对定位:元素会脱离普通流,因此绝对定位元素不会对其兄弟元素产生影响(与float不同),元素的具体位置由坐标位置决定。

BFC是属于普通流,因此它对兄弟元素也不产生影响。

第一部分:BFC工作原理详解

一、BFC(块级格式化上下文)

BFC是W3C CSS2.1规范中的一个概念,决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。目前除了IE6-7外其他浏览器均支持BFC。在CSS3中BFC叫做Flow Root。

与普通容器相比,BFC元素可以看作是隔离了的独立容器,内部的元素不会在布局上影响外面元素。

二、如何形成BFC

满足任意下面条件的元素可形成BFC:

1. 浮动元素,float除了none外的值

2. 绝对定位元素,position:absolute/fixed

3. display为 inline-block , table-cells , table-captions之一

4. overflow为visivle之外的值(hidden,auto,scroll)

display:table本身不产生BFC,而是由它产生匿名框,包含display:table-cell的框产生BFC。

注意:BFC并不是元素,而是元素带有的一些属性,因此上面元素是产生了BFC,而他们本身并不是BFC。

三、BFC的作用

整体上看,BFC的作用是隔离了容器,具体有三个表现:

1. BFC可以包含浮动元素

这是使用overflow:hidden方法闭合浮动的原理,W3C原文:"'Auto' heights for block formatting context roots",就是BFC会根据子元素情况自动适应高度,使子元素包含浮动

<div style="border:1px solid #00F;overflow:hidden;width:300px;">
<div style="float:left;background:#939;">我的父元素是 BFC</div>
</div>
<div style="line-height:3em;">----------我是华丽分割线-----------</div>
<div style="border:1px solid gray;width:300px;">
<div style="float:left;background:#3C6;">我的父元素不是 BFC</div>
</div>

注意:IE6-7不支持BFC,需要出发hasLayout闭合浮动

2.BFC可以组织元素被浮动元素覆盖

浮动元素的块级兄弟元素会无视浮动元素的位置,尽量占满一行,这样会被浮动元素覆盖,为该兄弟元素形成BFC可以组织被覆盖。

<div style="float:left;width:150px;height:50px;background:#FF0;">
我是浮动元素
</div>
<div style="width:200px;height:80px;background:#30F;color:#fff;">
我是非浮动元素,并且没有创建 BFC
</div>
<div style="line-height:3em;">----------我是华丽分割线-----------</div>
<div style="float:left;width:150px;height:50px;background:#FF0;">
我是浮动元素
</div>
<div style="width:200px;height:80px;background:#30F;color:#fff;display:inl
ine-block;">
我是非浮动元素,创建了 BFC
</div>

3. BFC可以阻止父子元素的margin折叠

当且仅当两个块级元素毗邻并且在同一块级格式化上下文时,他们垂直方向之间的外边距才会折叠。也就是说,及时两个块级元素毗邻,当不在同一个BFC时,它们的边距不会折叠。

<div style="margin-top:20px;background:yellow;width:300px;">
<div style="margin-top:20px;">
我的上外边距是 20px,父级元素不是 BFC
</div>
</div>
<div style="margin-top:20px;background:yellow;overflow:auto;width:300px;">
<div style="margin-top:20px;">
我的上外边距是 20px,父级元素是 BFC
</div>
</div>

四、BFC与hasLayout

由于IE6-7不支持BFC,而是使用私有属性hasLayout。表现上来看hasLayout和BFC相似,触发hasLayout条件与BFC相似,另外需要为元素设置IE特有的CSS属性zoom:1; zoom用于设置或检索元素的缩放比例,值为1即使用元素实际尺寸,使用zoom既可以触发hasLayout又不会对元素产生其他影响,相对来说更加方便。

第二部分:float及清除float的工作原理详解

一、什么是float

CSS的float属性就像印刷布局里的被文字包围的图片一样,float元素从流中被移除出来,但仍然是普通流中的一部分,float是在他们前面的最后一个块级元素之后直接被显示出来,除此之外浮动与绝对定位相似。

  任何声明为float的元素自动被设置为一个"块级元素",这表示它可以具有申明的width和height属性。没有指定宽度的float应当伸缩包装到浮动内容的宽度,比如,内部带有图片的一个float将和图片一样宽,带有文本的一个浮动与该浮动内的最长文本行一样宽。

二、浮动的缺陷与清除

当一个元素设置了float,常见的缺陷是——影响它的兄弟元素的位置和父元素产生高度塌陷。

1. 影响兄弟元素的位置:块级元素会无视这个float元素,使自身尽可能与这个float元素处于一行,导致被覆盖;行内元素会尽可能围绕浮动元素。

2. 高度塌陷:浮动元素脱离了普通流,这使得包含它的父元素并不会因为这个浮动元素的存在而自动撑高,因而造成塌陷。

clear的原理:clear会为元素添加足够的空白空间,使该元素放置在它前一个浮动元素之下(CSS2.1),这与增加元素的外边距使元素占满行而强制换行效果一样(CSS1,CSS2)。

clear可以清除对于兄弟元素的影响,但不能解决塌陷的问题,因此需要更高级的清除浮动——闭合浮动。

1. 空div方法

<div class="box">
<div class="main left">我设置了左浮动 float: left</div>
<div style="clear: both;"></div>
<div class="aside">我是页脚,我的上面添加了一个设置了 clear: both 的空 div</div>
</div>

空div很方便,但是加入了没有含义的div,与结构与表现分离的原则相违背。

2. overflow方法

在浮动元素的父元素上设置overflow的值为hidden或auto,可以形成BFC,使闭合浮动。

<div class="box" style="overflow: hidden; *zoom: 1;">
<div class="main left">我设置了左浮动 float: left</div>
<div class="aside left">我是页脚,但是我也设置了左浮动。</div>
</div>

overflow相对空div更方便,但是当元素内包含超出父元素边界的子元素时,会覆盖掉有用的子元素,或是产生多余的滚动条。

3. :after伪元素方法

<style>
.clearfix {/* 触发 hasLayout */ zoom: 1; }
.clearfix:after {content: "."; display: block; height: 0; clear: both; visibility: hidden; }
</style>
<div class="box clearfix">
<div class="main left">我设置了左浮动 float: left</div>
<div class="aside left">我是页脚,但是我也设置了左浮动。</div>
</div>

结合:after伪元素和IEhack,可以完美兼容主流各大浏览器。

清除浮动方法的本质:通过上面例子,可发现清除浮动方法可分为两类:利用clear方法和触发BFC方法

第三部分:绝对定位的工作原理详解

元素的绝对定位是将该元素从普通流拖出,使用top,left,bottom,right等属性相对于最接近的一个父级参照物进行定位。其中父级参照物为相对于其最接近的一个有定位设置(relative,absolute,fix)的父级元素,若父级元素没有设置定位属性,则依据body元素作为参照物定位。

绝对定位可层叠,层叠顺序通过z-index属性控制。

一、使用left和top属性的绝对定位

层级关系为:

<div ——————————— position:relative; 不是最近的祖先定位元素,不是参照物
<div—————————-没有设置为定位元素,不是参照物
<div———————- position:relative 参照物
<div box1
<div box2 ——–position:absolute; top:50px; left:120px;
<div box3

块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

为改变参照物(橘色框)后的效果
层级关系为:

<div ——————————— position:relative;最近的祖先定位元素,参照物
<div—————————-没有设置为定位元素,不是参照物
<div———————-没有设置为定位元素,不是参照物
<div box1
<div box2 ——–position:absolute; top:50px; left:120px;
<div box3

块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

参照物为最*的元素情况
层级关系为:

<div ———————————没有设置为定位元素,不是参照物
<div—————————-没有设置为定位元素,不是参照物
<div———————-没有设置为定位元素,不是参照物
<div box1
<div box2 ——–position:absolute; top:50px; left:120px;
<div box3

块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

二、使用margin属性的绝对定位

此情况,margin-bottom 和margin-right的值不再对文档流中的元素产生影响,因为该元素已经脱离了文档流。另外,不管它的祖先元素有没有定位,都是以文档流中原来所在的位置上偏移参照物。  
层级关系为:
<div ——————————— position:relative; 不是参照物
<div—————————-没有设置为定位元素,不是参照物
<div———————-没有设置为定位元素,不是参照物
<div box1
<div box2 ——–position:absolute; margin-top:50px; margin-left:120px;
<div box3

块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

IE6的情况下,box2前面没有兄弟节点,则margin-left的值会出现双倍边距
层级关系为:
<div ——————————— position:relative; 不是参照物
<div—————————-没有设置为定位元素,不是参照物
<div———————-没有设置为定位元素,不是参照物
<div box1
<div box2 ——–position:absolute; margin-top:50px; margin-left:60px;
<div box3

块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解