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
为改变参照物(橘色框)后的效果
层级关系为:
<div ——————————— position:relative;最近的祖先定位元素,参照物 <div—————————-没有设置为定位元素,不是参照物 <div———————-没有设置为定位元素,不是参照物 <div box1 <div box2 ——–position:absolute; top:50px; left:120px; <div box3
参照物为最顶级的元素情况
层级关系为:
<div ———————————没有设置为定位元素,不是参照物 <div—————————-没有设置为定位元素,不是参照物 <div———————-没有设置为定位元素,不是参照物 <div box1 <div box2 ——–position:absolute; top:50px; left:120px; <div box3
二、使用margin属性的绝对定位
此情况,margin-bottom 和margin-right的值不再对文档流中的元素产生影响,因为该元素已经脱离了文档流。另外,不管它的祖先元素有没有定位,都是以文档流中原来所在的位置上偏移参照物。
层级关系为:
<div ——————————— position:relative; 不是参照物 <div—————————-没有设置为定位元素,不是参照物 <div———————-没有设置为定位元素,不是参照物 <div box1 <div box2 ——–position:absolute; margin-top:50px; margin-left:120px; <div box3
IE6的情况下,box2前面没有兄弟节点,则margin-left的值会出现双倍边距
层级关系为:
<div ——————————— position:relative; 不是参照物 <div—————————-没有设置为定位元素,不是参照物 <div———————-没有设置为定位元素,不是参照物 <div box1 <div box2 ——–position:absolute; margin-top:50px; margin-left:60px; <div box3