- A+
定位 (positioning) 在基于DIV+CSS的网页布局中扮演重要角色, CSS中提供了三种基本的定位机制, 即普通流 (static) 、浮动 (float) 和绝对 (absolute) 定位。定位可以指定该元素相对于其正常位置, 或者相对于另一个元素、父元素、甚至浏览器窗口的位置。利用CSS中的一些属性, 可以创建列式布局, 它除了可以实现布局的一部分与另一部分重叠外, 还可以代替以前需要使用多个表格才能完成的任务。
页面元素的默认定位方式是普通流 (有时也称为文档流) 定位。在普通流定位中, 页面中的行内元素和块级元素分别按照从左到右和从上到下顺序逐个排列, 每个块级元素独占一行显示。如何让多个块级元素显示在同一行这里就引出了浮动。
1 浮动
在CSS1中首次提出了浮动的概念, 它以增加一个功能为基础。浮动设计的初衷是用来实现文字环绕效果, 通过将文章中的图片左右浮动, 使图片下方的文字自动环绕在图片周围, 这样就有效解决了图片的左边或者右边出现一大块留白的问题。后来人们发现, 浮动用来做布局效果非常不错, 甚至有时候都忘了它本是为实现文字环绕而生。
设置了浮动的元素不但可以像块元素那样设置其宽高, 并且可以做到内联排列, 它介于inline和block之间。在inline-block推出之前, 浮动在页面布局中得到了广泛的应用, 在inline-block推出来以后, 浮动的应用也随处可见。
2 浮动的效果
给元素设置了浮动定位, 浮动的框向左或向右移动, 直到它的外边缘碰到包含框或另一个浮动框的边框为止。另外, 由于浮动框脱离了文档的普通流, 所以文档里普通流中块框的表现就像浮动框不存在一样。
如果子元素都向一个方向浮动 (如左浮) , 而它们的父元素包含框不够宽, 无法容纳水平排列的这些浮动子元素时, 那么, 其他浮动块将向下移动, 直到有足够的空间,。另外, 如果浮动子元素的高度不同, 那么当它们向下移动时, 可能会出现被其他浮动元素“卡住”的现象。
3 浮动对页面的影响
浮动的元素会脱离文档的普通流, 不再占据页面空间, 所以会对其父元素高度带来一定的影响。如果一个元素中所包含的子元素都是浮动元素, 并且没有为该元素设置高度 (该元素的高度由它的内容来决定, 即父元素高度自适应) , 那么, 经常会发生父元素高度坍塌 (collapse) 的现象。父元素高度坍塌即父元素不能被子元素正常撑开, 父元素高度变成0。另外, 坍塌可能会对其周围的布局产生一定的影响, 所以清除浮动此时就显得十分重要。
本例中id为outer的div没有设置高度, 正常情况下, 它的高度会被其子元素撑开, 可是它内部的三个子元素p都设置了左浮动, 所以该div发生了高度坍塌, 上下边界重合。
4 清除浮动
清除浮动的方式有很多种, 但是实现的原理主要是依赖clear属性和触发新的BFC (Block formatting context) 。
4.1 BFC
格式化上下文 (Formatting context) 是CSS2.1规范中提出的一个概念, 它规定了其子元素将如何定位, 以及和其他元素间的关系及相互作用。最常见的格式化上下文有BFC和IFC (Inline formatting context) , 本文只探讨BFC。
BFC意译为“块级格式化上下文”, 它表示一个独立的渲染区域, 是一个隔离了的独立容器, 只有块级盒子 (block-level box) 参与, 它规定了内部的块级盒子如何布局, 与这个渲染区域外部无关[3]。只要某个元素符合成为BFC的条件之一, 该元素内部子元素的布局和定位就不受其外部元素的影响。实验表明, 当把元素的CSS属性display设置为block、list-item和table三者之一时, 就会生成块级盒子, 并且参与BFC。
4.2 BFC布局规则
⑴BFC是一个独立的渲染区域和隔离的独立容器, 容器里面的子元素不会影响到外面的元素, 反之亦然;
⑵当元素定位为absolute时, 它是可以超出它的包含块边界的。而BFC中的子元素则不会超出它的包含块, 每个子元素的左外边距 (margin-left) 与其包含块的左边界 (border-left) 相接触 (如果是从右往左格式化, 则相反) ;
⑶在BFC中, 盒子在垂直方向从包含块的顶端开始逐个排列, 相邻盒子之间的垂直间隙由他们的margin值决定;
⑷处于相同BFC的两个相邻块级盒子垂直外边距会发生重叠, 且与方向无关, 但BFC的区域不会与浮动元素的区域发生重叠;
⑸BFC是一个独立的渲染区域和隔离的独立容器, 容器里面的子元素不会影响到外面的元素, 反之亦然;
⑹浮动元素的高度参与到BFC的高度计算中。
4.3 触发BFC的条件
⑴根元素;
⑵浮动元素 (元素的float属性取none以外的值, left、right和inherit) ;
⑶元素的overflow属性取visible以外的值 (hidden、auto和scroll) ;
⑷表格单元格 (元素的display属性取值为table-cell或table-caption) ;
⑸弹性盒 (元素的display属性取值为flex或inline-flex) ;
⑹行内块 (元素的display属性取值为inline-block) ;
⑺元素的position属性取值为absolute或fixed。
5 清除浮动的几种方法
5.1 给父元素设置固定高度
父元素高度没有被里面的浮动子元素撑开, 这是因为它所有子元素都设置了浮动, 而浮动元素会脱离文档流, 而父元素本身没有高度, 所以我们看到其高度发生了坍塌。此时只需要给该父元素设置一下高度就可以, 但是父元素的高度设置多少合适呢?这种做法也脱离了本文的目的 (网页设计者总是希望外层父元素的高度由其里面的内容来决定) 。
5.2 使用额外标签
W3C标准提议在容器的末尾增加一个空元素 (如div, p等) , 并将该空元素样式设置“clear:both”, 这样做相当于强迫容器适应它的高度, 以便装下所有的浮动元素。Clear属性的作用是清除当前元素由于前面的元素浮动所带来的影响。如果在id为outer的div元素内部的末尾增加一个“clear:both”的div标签, 就可以清除浮动,?虽然这种方法能有效解决浮动引起的父元素高度坍塌的问题, 但是它存在语义不明确、容易造成HTML结构的混乱、违背HTML结构与CSS表现相分离的思想和增加后期维护难度等诸多缺点, 所以现实中这种用法并不多见。特别是在页面复杂的布局中, 可能要经常清除浮动, 用这种方式就会产生很多额外的空标签, 不利于页面结构优化。
5.3 使用float属性
将父元素float属性值设置为left/right, 可以有效清除浮动。它的优点是简单、代码量少、基本不存在结构和语义化问题, 主要缺点是对后续元素会有影响, 在页面布局中一般不采用这种方式。
5.4 使用display属性
将父元素display属性值设置为table-caption、table-cell和inline-block三者之一时, 可以有效清除浮动。由于display:inline-block会产生多余空白, 在页面布局中基本不用这种方式。为了保证兼容性, 通常用display:table来替代display:table-caption和display:table-cell。值得注意的是, 在上面列出的触发BFC的条件中没有出现display:table的身影, 事实上display:table触发BFC的原因是它会默认生成一个匿名的table-cell, 从而触发了新的BFC,#outer{zoom:1;//解决IE6/7兼容性问题,它的优点主要是没有违背HTML结构与CSS表现相分离的思想、语义化正确和代码量少, 缺点是盒模型属性发生了改变, 会引起其他问题, 因此, 这种方法在实际开发中用的也不是很多。
5.5 使用overflow属性
将父元素overflow属性值设置为hidden、auto或scroll三者之一时, 可以有效清除浮动, 但如果子元素使用了定位, 父元素清除浮动的效果将会受到影响。另外, 这种方式不能满足子元素要溢出显示的情况 (如下拉菜单) , 因为子元素离开了overflow属性值为hidden、auto或scroll的父元素所在的区域以后, 会被隐藏或者出现滚动条, 因此, 这种方式在实际应用中也不多见。
值得一提的是, 当overflow属性值为hidden时, 其语义为“溢出:隐藏”, 虽然子元素为浮动, 但其仍然处在父元素中, 可是父元素此时高度发生坍塌, 子元素就算发生溢出现象, 也应该被隐藏起来才对, 但此时父元素的高度为什么反而被撑开了呢?这是因为它触发了新的BFC, 且该BFC不会与浮动的子元素重叠, 因此父元素的高度被撑开了。
5.6 使用.clearfix
使用.clearfix来清除浮动元素对父元素的影响, 这是目前网站比较流行的清除浮动的方式。具体做法是给父元素定义一个class, 一般取值为.clearfix。下面列出三种使用.clearfix清除浮动的方式。
⑴只使用单伪元素:after。
在标准浏览器下, after伪类会在设置了.clearfix的元素后面插入一个clear:both的块元素, 因此清除了子元素浮动所带来的影响。然而IE6/7并不支持:after伪类, 为了解决IE6/7的兼容性问题, 可以在上面三种代码的后面加上.clearfix{zoom:1;//解决IE6/7兼容性问题}。因为zoom:1将触发has Layout, 使元素闭合内部的浮动。
伪元素:after与前面提到的空标签闭合浮动的方法相比, 优点是没有增加额外的空标签, 不破坏文档结构, 没有副作用;缺点是代码数量比较多。
⑵使用双伪元素:after和:before。
⑶只使用.clearfix, 既不使用伪元素after, 也不使用伪元素before。
6 结束语
浮动是网页布局常用的一种定位机制和手段, 本文通过对浮动引起的父元素高度坍塌现象进行分析, 再结合笔者的教学实践, 提出了使用clear属性和触发新的BFC两种清除浮动的方法。满足触发新的BFC的条件众多, 篇幅所限, 本文只列举了几种常用方式, 并从文档结构性、代码复杂性和结构与表现相分离等方面进行了对比分析。实际上, 使用.clearfix清除浮动, 会增加一些代码, 但在文档结构性、浏览器兼容性和结构与表现相分离等方面都表现优异。