CSS魔法堂:说说Float那个被埋没的志向

688 查看

前言

定位系统中第一难理解就是Normal flow,而第二就非Float莫属了,而Float难理解的原因有俩,1. 一开头我们就用错了;2. 它跟Normal flow靠得太近了。本文尝试理清Float的特性和行为特征,若有纰漏望各位指正。

被埋没的志向——文字环绕

回忆一下我们一般什么时候会想用浮动呢?是多列布局还是多列布局呢:)?其实它向往的却是这个

它想干的就是这个——文字环绕,而且CSS2中除了浮动外没有其他属性可实现上述的效果。
那到底如何理解它的实现原理呢?下面我们采取分步剖析的方式来深入探讨吧!

切断关联看Float

‘float’
Value: left | right | none | inherit
Initial: none
Applies to: all
Inherited: no
当设置float:left后,元素对应的margin left edge会尽可能向所属的containing block的左边框靠近,若同一行中存在位于左侧的元素设置了float:left,则即会尽可能向该兄弟元素的margin right edge靠近.


(由于float:left突出不了效果,因此采用float:right作例子。其中蓝色区域就是containing block范围,绿和红色块采用向右浮动)
当设置浮动后,display:inline的实际值将被改写为display:block,因此不要再为display:inline;height:100px;line-height:0;float:left导致盒子content height为100px感到惊讶了。也不要为即使剩余空间不足以存放整个display:inline;float:left盒子,导致整个盒子下移到下一行排版而惊讶了.(若为Normal flow则会根据white-spacing、word-wrap和word-break决定盒子内部分内容换行,而不是整个盒子换行)简单来说并不是float:left让盒子具有不为五斗米折腰的气质,而是display:block的功劳,又由于浮动的盒子会以水平方向排版,因此我们可以以display:inline-block来理解浮动定位的水平排版和换行行为。


当设置浮动后,虽然display的实际值为block但就width:auto而言,我认为display更像是采用inline-block,宽度由子元素决定。这就是包裹性了!
(float:right同理,只是方向不同而已)
注意:在仅考虑浮动元素本身的前提下,float:left的效果与display:inline-block而父容器direction:ltr的效果是一样的,不同的是浮动元素不纳入父容器高度的计算当中

头痛的开始——基于Normal flow看Float

用割裂的方式理解float并不难,难就难在结合Normal flow看Float。下面我们一起来探讨吧!警告,前方高能,前方高能!!

以Normal flow为基础

不管是Absolute positioning还是Float均以Normal flow作为定位基础,也就是说先假设有一个虚拟盒子以Normal flow进行定位,然后在这个基础上添加Float的特性并影响其他盒子的布局。而浮动定位对于盒子自身而言仅影响其在水平方向上的定位,因此对于inline-level box而言其垂直方向上的定位并没有发生变化,而对于block-level box而言因Collapsing margins的失效有可能会引起垂直方向上的移动。

值得注意的是,浮动定位的虚拟盒子实际上是不占空间的。因此才有后续的浮动闭合和清除浮动的事。

压榨line box


文字环绕很明显就是活生生地把文字向两边挤,为”大哥”留下个位置,而且小弟们不要走太远,必须时刻拥护着大哥。那大哥是如何圈住小弟们的呢?那得借助外力——line box。文字是以字形(glyph)的形式渲染,和它同一行的inline-level boxes均位于同一个line box中。而line box可谓是夹在containing block和浮动盒子之间勉强生存。

若line box的宽度不足以容纳glyph和inline-level boxes时,会在下方产生N个新的line boxes并在必要时拆分inline-level boxes,然后将glyph和inline-level boxes分布到各行的line boxes当中。

脚踩block-level box

相对line box,block-level box就显得不屈不挠了。width:auto时其宽度始终保持占满containing block宽度的态度。但位于同一个stacking context中的浮动定位的盒子虽然和常规流中的盒子拥有相同的z-index(都是auto),但浮动定位的盒子拥有额外的优先级,导致它总位于常规流中的盒子之上。(关于分层显示的内容可参考《CSS魔法堂:你真的理解z-index吗?》

通过创建BFC翻身做主人

同样是盒子,为啥你就可以在我上面呢?你有Float罩着,我也找弄个新的BFC来跟你抗衡。我们知道通过float:left|rightposition:absolute|fixeddisplay:inline-block|table-cell|table|table-captionoverflow:auto|scroll|hidden均可让盒子产生新的BFC。而产生BFC的盒子间天生排斥彼此。(但可通过后天的努力position:relative让他们又互有交集^_^)
那现在的问题是采用Normal flow定位模式的会产生新的BFC的盒子到底是紧跟在Float定位盒子的后面,还是另起一行呢?答案是两者都有可能,具体看剩余的宽度是否足以容纳该盒子。其实就是如同设置父容器产生BFC,而该盒子采用Float定位模式。不信,你看

是”浮动闭合”还是”清除浮动”?

我想各位都看过各种版本的clearfix实现,而最简单粗暴的方式就是添加一个<div style="clear:both"></div>来清除浮动。我还听过另一个名称——”浮动闭合”,那到底两者有什么区别呢?在作区分之前我们先要明确问题的本身。
对于height:auto的容器而言,我们希望它能恰好包裹着所有子元素,但不幸的是采用浮动定位模式的子元素将不纳入父容器的高度计算当中,那就会出现子元素戳穿父容器的风险。
从之前的内容我们了解到文字和inline-level boxes会环绕Float定位的盒子,而block-level box则ݞFloat莫属了,而Float难理解的原因有俩,1. 一开头我们就用错了;2. 它跟Normal flow靠得太近了。本文尝试理清Float的特性和行为特征,若有纰漏望各位指正。

被埋没的志向——文字环绕

回忆一下我们一般什么时候会想用浮动呢?是多列布局还是多列布局呢:)?其实它向往的却是这个

它想干的就是这个——文字环绕,而且CSS2中除了浮动外没有其他属性可实现上述的效果。
那到底如何理解它的实现原理呢?下面我们采取分步剖析的方式来深入探讨吧!

切断关联看Float

‘float’
Value: left | right | none | inherit
Initial: none
Applies to: all
Inherited: no
当设置float:left后,元素对应的margin left edge会尽可能向所属的containing block的左边框靠近,若同一行中存在位于左侧的元素设置了float:left,则即会尽可能向该兄弟元素的margin right edge靠近.


(由于float:left突出不了效果,因此采用float:right作例子。其中蓝色区域就是containing block范围,绿和红色块采用向右浮动)
当设置浮动后,display:inline的实际值将被改写为display:block,因此不要再为display:inline;height:100px;line-height:0;float:left导致盒子content height为100px感到惊讶了。也不要为即使剩余空间不足以存放整个display:inline;float:left盒子,导致整个盒子下移到下一行排版而惊讶了.(若为Normal flow则会根据white-spacing、word-wrap和word-break决定盒子内部分内容换行,而不是整个盒子换行)简单来说并不是float:left让盒子具有不为五斗米折腰的气质,而是display:block的功劳,又由于浮动的盒子会以水平方向排版,因此我们可以以display:inline-block来理解浮动定位的水平排版和换行行为。


当设置浮动后,虽然display的实际值为block但就width:auto而言,我认为display更像是采用inline-block,宽度由子元素决定。这就是包裹性了!
(float:right同理,只是方向不同而已)
注意:在仅考虑浮动元素本身的前提下,float:left的效果与display:inline-block而父容器direction:ltr的效果是一样的,不同的是浮动元素不纳入父容器高度的计算当中

头痛的开始——基于Normal flow看Float

用割裂的方式理解float并不难,难就难在结合Normal flow看Float。下面我们一起来探讨吧!警告,前方高能,前方高能!!

以Normal flow为基础

不管是Absolute positioning还是Float均以Normal flow作为定位基础,也就是说先假设有一个虚拟盒子以Normal flow进行定位,然后在这个基础上添加Float的特性并影响其他盒子的布局。而浮动定位对于盒子自身而言仅影响其在水平方向上的定位,因此对于inline-level box而言其垂直方向上的定位并没有发生变化,而对于block-level box而言因Collapsing margins的失效有可能会引起垂直方向上的移动。

值得注意的是,浮动定位的虚拟盒子实际上是不占空间的。因此才有后续的浮动闭合和清除浮动的事。

压榨line box


文字环绕很明显就是活生生地把文字向两边挤,为”大哥”留下个位置,而且小弟们不要走太远,必须时刻拥护着大哥。那大哥是如何圈住小弟们的呢?那得借助外力——line box。文字是以字形(glyph)的形式渲染,和它同一行的inline-level boxes均位于同一个line box中。而line box可谓是夹在containing block和浮动盒子之间勉强生存。

若line box的宽度不足以容纳glyph和inline-level boxes时,会在下方产生N个新的line boxes并在必要时拆分inline-level boxes,然后将glyph和inline-level boxes分布到各行的line boxes当中。

脚踩block-level box

相对line box,block-level box就显得不屈不挠了。width:auto时其宽度始终保持占满containing block宽度的态度。但位于同一个stacking context中的浮动定位的盒子虽然和常规流中的盒子拥有相同的z-index(都是auto),但浮动定位的盒子拥有额外的优先级,导致它总位于常规流中的盒子之上。(关于分层显示的内容可参考《CSS魔法堂:你真的理解z-index吗?》

通过创建BFC翻身做主人

同样是盒子,为啥你就可以在我上面呢?你有Float罩着,我也找弄个新的BFC来跟你抗衡。我们知道通过float:left|rightposition:absolute|fixeddisplay:inline-block|table-cell|table|table-captionoverflow:auto|scroll|hidden均可让盒子产生新的BFC。而产生BFC的盒子间天生排斥彼此。(但可通过后天的努力position:relative让他们又互有交集^_^)
那现在的问题是采用Normal flow定位模式的会产生新的BFC的盒子到底是紧跟在Float定位盒子的后面,还是另起一行呢?答案是两者都有可能,具体看剩余的宽度是否足以容纳该盒子。其实就是如同设置父容器产生BFC,而该盒子采用Float定位模式。不信,你看

是”浮动闭合”还是”清除浮动”?

我想各位都看过各种版本的clearfix实现,而最简单粗暴的方式就是添加一个<div style="clear:both"></div>来清除浮动。我还听过另一个名称——”浮动闭合”,那到底两者有什么区别呢?在作区分之前我们先要明确问题的本身。