重新认知Box

回归CSS标准之Float

2015/10/27 · CSS · float

原文出处: 百度EFE   

最近因为遇到一个float相关的bug,又跑去撸了一遍css标准。然后发现,它确实比其他属性复杂好多,既不像inline-block那样单纯的完成并排显示,又不像绝对定位那样彻底的脱离文档流而不影响别的元素。它唯一单纯的就是,真的是唯一可以实现文字环绕显示的属性。

但是唯一单纯的特点却并不是很招人待见,相反,大家更习惯使用float去完成其他的功能,比如横排展示和自适应分栏布局。

很多人这样用着,只是因为一堆现成的文章告诉他们可以这样用,但是到底为什么可以,以及用的时候要注意什么问题却并不是所有人都知道,结果就是,一时的“便利”,为日后的维护埋了一堆的坑。

这篇文章打算通过将目前一些成文的浮动元素的特点与CSS规范中的具体描述对应,来加深大家对float属性原理的理解。并在后面通过一个bug实例,说明使用这个属性时要注意的问题。

BFC全称是Block Formatting Context,即块格式化上下文。它是CSS2.1规范定义的,关于CSS渲染定位的一个概念。要明白BFC到底是什么,首先来看看什么是视觉格式化模型。

CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

2016/05/10 · CSS · BFC, Box Model, Collapsing margins, IFC

本文作者: 伯乐在线 - ^-^肥仔John 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者。

前言
盒子模型作为CSS基础中的基础,曾一度以为掌握了IE和W3C标准下的块级盒子模型即可,但近日在学习行级盒子模型时发现原来当初是如此幼稚可笑。本文尝试全面叙述块级、行级盒子模型的特性。作为近日学习的记录。

何为盒子模型?
盒子模型到底何方神圣居然可以作为CSS的基础?闻名不如见面,上图了喂!
图片 1
再来张切面图吧!
图片 2
下面我们以 <div></div> 为栗子。 <div></div> 标签被浏览器解析后会生成div元素并添加到document tree中,但CSS作用的对象并不是document tree,而是根据document tree生成的render tree,而盒子模型就是render tree的节点。
* 注意:
* 1. CSS作用的是盒子(Box), 而不是元素(Element);
* 2. JS无法直接操作盒子。

盒子模型的结构
由于块级盒子在验证效果时干扰信息更少,便于理解盒子模型,因此下面将以块级盒子模型来讲解。
注意: 行级盒子模型与块级盒子模型结构一致,只是行级盒子在此基础上有自身特性而已。
从上面两幅图说明盒子模型其实就是由以下4个盒子组成:

  1. content box:必备,由content area和4条content/inner edge组成;
  2. padding box:可选,由padding和4条padding edge组成。若padding宽度设置为0,则padding edge与content edage重叠;
  3. border box:可选,由border和4条border edge组成。若border宽度设置为0,则border edge与padding edage重叠;
  4. margin box:可选,由margin和4条margin/outer edge组成。若margin宽度设置为0,则margin edge与border edage重叠。
    对于刚接触CSS的同学,经常会将”通过width/height属性设置div元素的宽/高”挂在口边,其实这句话是有误的。
  5. 首先css属性width和height作用于div元素所产生的盒子,而不是元素本身;
  6. 另外盒子模型由4个盒子组成,那width和height到底是作用于哪些盒子呢?
    这里就分为IE盒子模型和标准盒子模型了。
       IE box model    
    IE5.5(怪异模式)采用IE盒子模型,其它将使用W3C标准盒子模型。
    图片 3

JavaScript

width = content-width + padding-width + border-width height = content-height + padding-height + border-height

1
2
width = content-width + padding-width + border-width
height = content-height + padding-height + border-height

  Standard box model  
图片 4

JavaScript

width = content-width height = content-height

1
2
width = content-width
height = content-height

游走于IE box model 和 Standard box model间的通道——box-sizing属性
我们看到存在两种width/height的划分方式,到底哪种才对呢?其实两种都对,具体看如何使用而已。另外IE8开始支持CSS3属性box-sizing,让我们可以自由选择采用哪种盒子:)
box-sizing:content-box/border-box/inherit
content-box——默认值,采用Standard box model
border-box——采用IE box model
inherit——继承父元素属性值
sample:

CSS

Element{ -moz-box-sizing: border-box; // FireFox3.5+ -o-box-sizing: border-box; // Opera9.6(Presto内核) -webkit-box-sizing: border-box; // Safari3.2+ -ms-box-sizing: border-box; // IE8 box-sizing: border-box; // IE9+,Chrome10.0+,Safari5.1+,Opera10.6 }

1
2
3
4
5
6
7
Element{
  -moz-box-sizing: border-box; // FireFox3.5+
  -o-box-sizing: border-box; // Opera9.6(Presto内核)
  -webkit-box-sizing: border-box; // Safari3.2+
  -ms-box-sizing: border-box; // IE8
  box-sizing: border-box; // IE9+,Chrome10.0+,Safari5.1+,Opera10.6
}

行级盒子——怀疑人生de起点:)                  
之前我理解的盒子模型如上所述,当我看到行级盒子的种种现象时,便开始怀疑人生了:(
width/height不起作用。。。

CSS

.defined-wh{ width: 100px; height: 50px; border: solid 1px red; background: yellow; }

1
2
3
4
5
6
7
.defined-wh{
  width: 100px;
  height: 50px;
 
  border: solid 1px red;
  background: yellow;
}

对于block-level box

XHTML

<div class="defined-wh"></div>

1
<div class="defined-wh"></div>

图片 5
对于inline-level box

XHTML

<span class="defined-wh"></span>

1
<span class="defined-wh"></span>

图片 6
行级盒子的宽度怎么会是0呢?高度是有的但不是50px啊,到底什么回事啊?
原因很简单,那就是行级盒子的content box的高/宽根本就不是通过height/width来设置的。
content box/area的高由font-size决定的;
content box/area的宽等于其子行级盒子的外宽度(margin+border+padding+content width)之和。

  行级盒子被挤断了。。。

CSS

.broken{ border: solid 1px red; background: yellow; }

1
2
3
4
.broken{
  border: solid 1px red;
  background: yellow;
}

对于block-level box

XHTML

<div class="broken">一段文字一段文字一段文字一段文字一段文字一段文字</div>

1
<div class="broken">一段文字一段文字一段文字一段文字一段文字一段文字</div>

图片 7
对于inline-level box

XHTML

<span class="broken">一段文字一段文字一段文字一段文字一段文字一段文字</span>

1
<span class="broken">一段文字一段文字一段文字一段文字一段文字一段文字</span>

图片 8
行级盒子被五马分尸了,可怜兮兮的。更可怜的是我理解不了。。。
其实W3C Recommendation有说明的哦!
>The box model for inline elements in bidirectional context
>When the element’s ‘direction’ property is ‘ltr’, the left-most generated box of the first line box in which the element appears has the left margin, left border and left padding, and the right-most generated box of the last line box in which the element appears has the right padding, right border and right margin.
>When the element’s ‘direction’ property is ‘rtl’, the right-most generated box of the first line box in which the element appears has the right padding, right border and right margin, and the left-most generated box of the last line box in which the element appears has the left margin, left border and left padding.
就是说当inline-level box宽度大于父容器宽度时会被拆分成多个inline-level box,
当属性direction为ltr时,margin/border/padding-left将作用于第一个的inline-level box,margin/border/padding-right将作用于最后一个的inline-level box;若属性direction为rtl时,margin/border/padding-right将作用于第一个的inline-level box,margin/border/padding-left将作用于最后一个的inline-level box。
看到了没?行级盒子真的会被分尸的,好残忍哦:|

行级盒子怎么不占空间了?怎么刷存在感啊。。。

CSS

.existed{ margin: 20px; padding: 20px; border: solid 1px red; background: yellow; background-clip: content-box; }

1
2
3
4
5
6
7
.existed{
  margin: 20px;
  padding: 20px;
  border: solid 1px red;
  background: yellow;
  background-clip: content-box;
}

对于block-level box

XHTML

<div>before bababababababa</div> <div class="existed">babababababababababa</div> <div>after bababababababa</div>

1
2
3
<div>before bababababababa</div>
<div class="existed">babababababababababa</div>
<div>after bababababababa</div>

图片 9
对于inline-level box

XHTML

<div>before bababababababa</div> <span class="existed">babababababababababa</span> <div>after bababababababa</div>

1
2
3
<div>before bababababababa</div>
<span class="existed">babababababababababa</span>
<div>after bababababababa</div>

图片 10
看,行级盒子的margin/border/padding-top/bottom怎么均不占空间的?难道行级盒子仅有content box占空间吗?
这里已经涉及到水平和垂直方向排版的范畴了,仅以盒子模型已无法解析理解上述的问题。
(要结合)

在深入解释inline-level box的上述现象前,我们需要补充一下:

  1. 一个元素会对应0~N个box;(当设置display:none;时,则对应0个box)
  2. 根据display属性值,元素会对应不同类型的controlling box(inline/block-level box均是controlling box的子类). 就CSS2而言display:inline|inline-block|inline-table|table-cell|table-column-group的元素对应inline-level box,而display:block|list-item|table|table-caption|table-header-group|table-row|table-row-group|table-footer-group的元素则对应block-level box;
  3. box布局/排版时涉及到定位问题,而CSS中通过positioning scheme来定义,其包含normal flow、floats和absolute positioning三种定位方式.而normal flow包含block formatting、inline formatting和relative positioning,其中BFC为block formatting的上下文,IFC为inline formatting的上下文。

因此大家请注意,前方高能,前方高能!!!

和IFC一起看inline-level box
IFC(Inline Formatting Context),直译为“行内格式化上下文”,这是什么鬼的翻译啊?反正我对于名词一向采用拿来主义,理解名词背后的含义才是硬道理。
我们简单理解为每个盒子都有一个FC特性,不同的FC值代表一组盒子不同的排列方式。有的FC值表示盒子从上到下垂直排列,有的FC值表示盒子从左到右水平排列等等。而IFC则是表示盒子从左到右的水平排列方式,仅此而已(注意:一个盒子仅且仅有一个FC值)。而inline-level box的FC特性值固定为IFC
另外仅处于in-flow的盒子才具有FC特性,也就是positioning scheme必须为Normal flow的盒子才具有FC特性。
除了IFC外,对于inline-level box排版而言还有另一个重要的对象,那就是line box。line box是一个看不见摸不着的边框,但每一行所占的垂直高度其实是指line box的高度,而不是inline-level box的高度。
  line box的特点:

  1. 同一行inline-level box均属于同一个line box;
  2. line box高度的计算方式()
    >The height of each inline-level box in the line box is calculated. For replaced elements, inline-block elements, and inline-table elements, this is the height of their margin box; for inline boxes, this is their ‘line-height’.
    >The inline-level boxes are aligned vertically according to their ‘vertical-align’ property. In case they are aligned ‘top’ or ‘bottom’, they must be aligned so as to minimize the line box height. If such boxes are tall enough, there are multiple solutions and CSS 2.1 does not define the position of the line box’s baseline.
    >The line box height is the distance between the uppermost box top and the lowermost box bottom.

CSS

.parent{ line-height: 1; font-size: 14px; border: solid 1px yellow; } .child{ font-size: 30px; vertical-align: middle; border: solid 1px blue; } .inline-block{ display: inline-block; overflow: hidden; border: solid 1px red; } .other{ border: solid 1px green; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.parent{
  line-height: 1;
  font-size: 14px;
  border: solid 1px yellow;
}
.child{
  font-size: 30px;
  vertical-align: middle;
  border: solid 1px blue;
}
.inline-block{
  display: inline-block;
  overflow: hidden;
  border: solid 1px red;
}
.other{
  border: solid 1px green;
}

XHTML

<span class="parent"> <span class="child"> <span class="inline-block">display:inline-block元素</span> xp子元素的文字 </span> xp父元素的文字 </span> <div class="other">其他元素</div>

1
2
3
4
5
6
7
8
<span class="parent">
  <span class="child">
    <span class="inline-block">display:inline-block元素</span>
    xp子元素的文字
  </span>
  xp父元素的文字
</span>
<div class="other">其他元素</div>

图片 11

  1. 根据规则,span.parent所在行的line box的高度受span.parent、span.child、span.inline-block元素对应的inline-level box”高度”的影响。其中span.parent的”高度”为其line-height实际值,span.child的”高度”为其line-height实际值,而span.inline-block的”高度”为其margin box的高度。由于设置line-height:1,因此span.parent和span.child的content box高度等于line-height实际值;
    2. 根据vertical-align属性垂直对齐,造成各“高度”间并不以上边界或下边界对齐;
  2. span.inline-block红色的上边框(border top)到span.child蓝色的下边框(border bottom)的距离再减去1px即为line box的高度。(line box的下界其实是span.child的content box的下限的,你看”其他元素”的上边框不是和span.child的下边框重叠了吗?如果那是line box的下界,那怎会出现重叠呢)

这里又涉及到另一个属性vertical-align了,由于它十分复杂,还是另开文章来叙述吧!

                      行级盒子小结                          
*就盒子模型而言***

  1. inline-level box与block-level box结构一致;
  2. content box的高度仅能通过属性font-size来设置,content box的宽度则自适应其内容而无法通过属性width设置;
  3. 当inline-level box的宽度大于containing block,且达到内容换行条件时,会将inline-level拆散为多个inline-level box并分布到多行中,然后当属性direction为ltr时,margin/border/padding-left将作用于第一个的inline-level box,margin/border/padding-right将作用于最后一个的inline-level box;若属性direction为rtl时,margin/border/padding-right将作用于第一个的inline-level box,margin/border/padding-left将作用于最后一个的inline-level box。

*垂直排版特性***
inline-level box排版单位不是其本身,而是line box。重点在于line box高度的计算。

  1. 位于该行上的所有in-flow的inline-level box均参与该行line box高度的计算;(注意:是所有inline-level box,而不仅仅是子元素所生成的inline-level box)
  2. replaced elements, inline-block elements, and inline-table elements将以其对应的opaque inline-level box的margin box高度参与line box高度的计算。而其他inline-level box则以line-height的实际值参与line box高度的计算;
  3. 各inline-level box根据vertical-align属性值相对各自的父容器作垂直方向对齐;
  4. 最上方的box的上边界到最下方的下边界则是line box的高度。(表述不够清晰,请参考实例理解)

Collapsing margins                      
大家必定听过或遇过collapsing margins吧,它是in-flow的block-level box排版时的一类现象。说到排版那必须引入另一个FC特性值——BFC(Block Formatting Context)的。
BFC则是表示盒子从上到下的垂直排列方式,仅此而已(注意:一个盒子仅且仅有一个FC值)。而block-level box的FC特性值固定为BFC。
collapsing margins规则
1. 元素自身margin-top/bottom collapsing

XHTML

anonymous block-level box <div class="margins"></div> anonymous block-level box <div class="margins border"></div> anonymous block-level box

1
2
3
4
5
anonymous block-level box
<div class="margins"></div>
anonymous block-level box
<div class="margins border"></div>
anonymous block-level box

CSS

.margins{margin: 50px 0 70px;} .border{border: solid 1px red;}

1
2
.margins{margin: 50px 0 70px;}
.border{border: solid 1px red;}

图片 12
当block-level box高度为0,垂直方向的border和padding为0,并且没有in-flow的子元素。那么它垂直方向的margin将会发生重叠。

2. 父子元素margin-top/top 或 margin-bottom/bottom collapsing

XHTML

anonymous block-level box <div class="parent-margins"> <div class="margins border"></div> anonymous block-level box <div class="margins border"></div> </div> anonymous block-level box <div class="parent-margins border"> <div class="margins border"></div> anonymous block-level box <div class="margins border"></div> </div> anonymous block-level box

1
2
3
4
5
6
7
8
9
10
11
12
13
anonymous block-level box
<div class="parent-margins">
  <div class="margins border"></div>
  anonymous block-level box
  <div class="margins border"></div>
</div>
anonymous block-level box
<div class="parent-margins border">
  <div class="margins border"></div>
  anonymous block-level box
  <div class="margins border"></div>
</div>
anonymous block-level box

CSS

.parent-margins{margin: 25px 0;} .margins{margin: 50px 0 25px;} .border{border: solid 1px red;}

1
2
3
.parent-margins{margin: 25px 0;}
.margins{margin: 50px 0 25px;}
.border{border: solid 1px red;}

图片 13
当父子元素margin-top间或margin-bottom间没有padding、border阻隔时,则会margin会发生重叠。
注意空白字符会造成目标父子元素间的存在anonymous block-level box,导致margin不重叠。

XHTML

anonymous block-level box <div class="parent-margins">  <div class="margins border"></div> anonymous block-level box <div class="margins border"></div> </div> anonymous block-level box

1
2
3
4
5
6
7
anonymous block-level box
<div class="parent-margins">&nbsp;
  <div class="margins border"></div>
  anonymous block-level box
  <div class="margins border"></div>
</div>
anonymous block-level box

图片 14

3. 兄弟元素margin-bottom/top collapsing

XHTML

<div class="margins">former</div> <div class="margins">latter</div>

1
2
<div class="margins">former</div>
<div class="margins">latter</div>

CSS

.margins{margin: 50px 0 25px;}

1
.margins{margin: 50px 0 25px;}

两个相邻的in-flow block-level box的上下margin将发生重叠。

*上述为默认情况下block-level box(即display:block,其它为默认值时)的margin重叠规则***
那非默认情况下呢?相比非默认情况下的margin重叠规则,我们更关心是什么时候不会产生重叠。这时又引入了另一个概念——生成新BFC。也就是block-level box A与block-level box B的FC特性值BFC可能是不同的。
当两个相邻box的FC值不为同一个BFC时,它们的margin绝对不会重叠。
那么剩下的问题就是,到底何时会产生新的BFC?哪些block-level box会采用新的BFC?默认BFC又是谁生成的呢?
其实根元素(html)会生成默认BFC供其子孙block-level box使用。
采用floats或absolute positioning作为positioning scheme时,或display:inline-block/table-cell/table-caption/flex/inline-flex或overflow属性值不为visible时,则会产生新的BFC;而新的BFC将作为子孙block-level box的FC属性值。
注意:
    1. 产生新BFC的盒子不会与子盒子发生margin重叠;
    2. display:inline-block的盒子不与 兄弟 和 父 盒子发生margin重叠,是因为display:inline-block的盒子的FC特性值为IFC,还记得line box吗?没有margin重叠是自然不过的事了;
    3. positioning scheme为floats的盒子不与floated的兄弟盒子发生margin重叠,也不会与前一个in-flow的兄弟盒子发生margin重叠。(注意:与父盒子也不会发生margin重叠)

XHTML

<div class="margins border">sibling</div> <div class="margins border float">floats1</div> <div class="margins border float">floats2</div>

1
2
3
<div class="margins border">sibling</div>
<div class="margins border float">floats1</div>
<div class="margins border float">floats2</div>

CSS

.margins{margin: 50px 0 50px;} .border{border: solid 1px red;} .float{float:left;width:200px;}

1
2
3
.margins{margin: 50px 0 50px;}
.border{border: solid 1px red;}
.float{float:left;width:200px;}

图片 15

归纳FC、BFC和IFC                      

由于上述主要阐述inline/block-level box,因此通过“仅此而已”来简化BFC和IFC的内涵。下面我们稍微全面一点去理解BFC和IFC如何影响inline/block-level box。

FC(Formatting Context),用于初始化时设置盒子自身尺寸和排版规则。注意“初始化”,暗指positioning scheme采用的是normal flow,要知道floats和absolute positioning均不是默认/初始化值。也就是说我们在讨论FC及BFC和IFC时,均针对in-flow box而言的。
  BFC
**对于不产生新BFC的盒子**

  1. block-level boxes垂直排列,盒子的left outer edge与所在的containing block的左边相接触,默认情况下(width为auto时)right outer edge则与所在的containing block的右边相接触。即使存在floated的兄弟盒子。

XHTML

<div id="container" style="border:solid 2px red;"> <div id="left" style="float:left;width:300px;height:30px;background:yellow;opacity:0.2;"></div> <div id="right" style="height:30px;background:#999;"></div> </div>

1
2
3
4
<div id="container" style="border:solid 2px red;">
  <div id="left" style="float:left;width:300px;height:30px;background:yellow;opacity:0.2;"></div>
  <div id="right" style="height:30px;background:#999;"></div>
</div>

图片 16

虽然 div#left 浮点了,但 div#right 的left outer edge还是与 div#container 的left content edge相接触。 div#right 所在的containing block就是 div#container 的content box.

  1. block-level box高度的计算
    The element’s height is the distance from its top content edge to the first applicable of the following:
    the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
    the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child’s bottom margin does not collapse with the element’s bottom margin
    the bottom border edge of the last in-flow child whose top margin doesn’t collapse with the element’s bottom margin
    zero, otherwise
    Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored, and relatively positioned boxes are considered without their offset).

也就out-flow box不影响block-level box高度的计算。也就是解释了为何div中仅含floated元素时,div盒子高度为0的现象了。

**对于产生新BFC的盒子**
对于产生新BFC的盒子而言,除了不发生collapsing margins的情况外,还有两个与浮点相关的现象。

  1. out-flow box纳入block-level box高度的计算
    In addition, if the element has any floating descendants whose bottom margin edge is below the element’s bottom content edge, then the height is increased to include those edges. Only floats that participate in this block formatting context are taken into account, e.g., floats inside absolutely positioned descendants or other floats are not.
    也就positioning scheme为floats的box也会影响block-level box高度的计算。

  2. 誓死不与positioning scheme为floats的兄弟盒子重叠
    The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with ‘overflow’ other than ‘visible’) must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3. CSS2 does not define when a UA may put said element next to the float or by how much said element may become narrower.

产生新BFC的block-level box不与floated-box重叠,而是floated-box的margin-box与block-level box的border-box相接触。
水平方向

XHTML

<div style="float:left;width:100px;border: solid 1px red;margin-right:50px;">floated</div> <div style="width:200px;border: solid 1px blue;margin-left:100px;overflow:hidden;">gen new BFC balabala</div>

1
2
<div style="float:left;width:100px;border: solid 1px red;margin-right:50px;">floated</div>
<div style="width:200px;border: solid 1px blue;margin-left:100px;overflow:hidden;">gen new BFC balabala</div>

图片 17
垂直方向

XHTML

<div style="float:left;width:100px;border: solid 1px red;margin-bottom:50px;">floated</div> <div style="width:200px;border: solid 1px blue;margin-top:100px;overflow:hidden;">gen new BFC balabala</div>

1
2
<div style="float:left;width:100px;border: solid 1px red;margin-bottom:50px;">floated</div>
<div style="width:200px;border: solid 1px blue;margin-top:100px;overflow:hidden;">gen new BFC balabala</div>

图片 18

 

 IFC

提起IFC那就不能不说line box,而line box高度的计算方式上面已经叙述了,那line box的宽度呢?
line box默认情况下左边框与containing block的左边框接触,右边框与containing block的右边框接触。若存在floated兄弟盒子,则line box的宽度为containing block的宽度减去floated-box的outer-box的宽度。
图片 19
而inline-level box必须包含在line box中,若inline-level box的white-space:nowrap或pre外的其他值时,就会将inline-level box拆分为多个inline-level box并散落到多个line box中,从而实现文字环绕图片的效果了。
图片 20
否则inline-level box会捅破line box(即line box宽度不变)

    行——换与不    

先看看关于换行的CSS属性吧!

white-space normal: 忽略/合并空白 pre: 保留空白,如同<pre>的行为 nowrap: 忽略/合并空白,文本不会换行,直到遇到<br/> pre-wrap: 保留空白,但是会正常地进行换行 pre-line: 忽略/合并空白,但是会正常地进行换行 inherit: 从父元素继承。 word-wrap normal: 只在允许的断字点换行 break-word: 在长单词或URL地址内部进行换行 word-break normal:依照亚洲和非亚洲语言的文本规则,允许在单词内换行。 keep-all:让亚洲语言文本如同非亚洲语言文本那样不允许在任意单词内换行。 break-all:允许非亚洲语言文本行如同亚洲语言文本那样可以在任意单词内换行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
white-space
    normal: 忽略/合并空白
    pre: 保留空白,如同<pre>的行为
    nowrap: 忽略/合并空白,文本不会换行,直到遇到<br/>
    pre-wrap: 保留空白,但是会正常地进行换行
     pre-line: 忽略/合并空白,但是会正常地进行换行
    inherit: 从父元素继承。
  word-wrap
    normal: 只在允许的断字点换行
    break-word: 在长单词或URL地址内部进行换行
  word-break
    normal:依照亚洲和非亚洲语言的文本规则,允许在单词内换行。
    keep-all:让亚洲语言文本如同非亚洲语言文本那样不允许在任意单词内换行。
    break-all:允许非亚洲语言文本行如同亚洲语言文本那样可以在任意单词内换行。

具体示例可参考:css中强制换行word-break、word-wrap、white-space区别实例说明

在处理换行问题上,我们要处理的对象分为亚洲语言文本和非亚洲语言文本。对于亚洲语言文本是以字作为操作单元,而非亚洲语言文本是以单词作为操作单元。而换行是针对特定语言文本的操作单元来处理,所以默认情况下会看到一串没空格的“中文”自动换行,而一串没空格的“英文”却没有换行的现象。
对于我们(亚洲人)而言,一般采用 word-break:break-all;word-wrap:break-word; 来实现中英文自动换行效果,但英文单词本身是不能这样简单粗暴地换行的。
英语单词移行有一定规则,归纳如下:
1.移行处要用连字符号“-”,只占一个印刷符号的位置并放在该行的最后.
2.移行时一般按照音节进行,故只可在两音节之间分开,不能把一个完整的音节分写在上下两行.例如:Octo-ber(正),Octob-er(误).
3.复合词要在构成该词的两部分之间移行.如:some-thing,bed-room等.
4.如果复合词原来就有连字符号,则就在原连字符号处分行.如:good-looking等.
5.两个不同的辅音字母在一起时,移行时前后各一个.如:cap-tain,ex-pose等.
6.当两个音节间只有一个辅音字母时,如果该辅音字母前的元音字母按重读开音节的规则发音,该辅音字母移至下一行.如:fa-ther等.但如果元音按重读闭音节的规则发音,则该辅音字母保留在上一行末尾.例如:man-age等.
7.当遇到双写辅音字母时,一般把它们分成前后各一个.例如:mat-ter等.
8.当重读音节在后面时,元音字母前的辅音字母通常移到下一行.如:po-lite等.
9.单音节词不可移行.如:length,long,dance等.
10.前缀或后缀要保持完整,不可分开写.如:unfit,disappear等.
11.阿拉伯数字不分开移行书写.
12.不论音节多少,专有名词不宜分写.例如:Nancy,Russia等.
13.缩写词、略写词或某些词的缩写形式不可移行书写.例如:U.N.(联合国),P.R.C.(中华人民共和国),isn’t.
14.不能构成一个音节的词尾不分写.例如:stopped等.
15.字母组合或辅音连缀不可移行.例如:machine,meat等.

CSS简化了上述的规则,若需要换行处恰好是一个复合词,就在原连字符号处分行;其它情况则整个单词移到下一行。因此使用 word-wrap:break-word; 就OK了。

另外我们还可以通过 word-break:keep-all;white-space:nowrap; 来实现打死都不换行的效果
总结                              
洋洋洒洒总算把Box Model、BFC和IFC描述了个大概。对于BFC折腾点就是在collapsing margins那,另外还有产生新BFC这个行为上(这个跟浮动等有交集,以后再理清吧);而IFC重点在于理解line box,其实line box也像block-level box那样是垂直排列的,而inline-level box则是以line box作为容器实现水平排列罢了。到这里会发现理解IFC比BFC蛋疼多了,不过有了这篇作基础,后面理解text-align、line-height和vertical-align就轻松不少了。

本文纯个人理解,若有纰漏,望各位指正,谢谢!

感谢                              

)

)

(IFC)

[KB010: 常规流( Normal flow ) ]()
[CSS 101: Block Formatting Contexts]()

打赏支持我写出更多好文章,谢谢!

打赏作者

浮动元素的业界公认特点

float属性被设置为非none的元素:

  1. 元素被视作块级元素,相当于display设置为“block”;
  2. 元素具备包裹性,会根据它所包含的元素实现宽度、高度自适应;
  3. 浮动元素前后的块级兄弟元素忽视浮动元素的而占据它的位置,并且元素会处在浮动元素的下层(并且无法通过z-index属性改变他们的层叠位置),但它的内部文字和其他行内元素都会环绕浮动元素;
  4. 浮动元素前后的行内元素环绕浮动元素排列;
  5. 浮动元素之前的元素如果也是浮动元素,且方向相同,它会紧跟在它们后面;父元素宽度不够,换行展示;
  6. 浮动元素之间的水平间距不会重叠;
  7. 当包含元素中只有浮动元素时,包含元素将会高度塌陷;
  8. 浮动元素的父元素的非浮动兄弟元素,忽视浮动元素存在,覆盖浮动元素;
  9. 浮动元素的父元素的浮动兄弟元素,会跟随浮动元素布局,仿佛处在同一父元素中。

目前实现的很多应用都是直接对应上述特点实现的。但是很多人在看过这些描述以后,并不知道它的结论从何而来,无据可循,怎会安心?为了解决大家的疑虑,下面我会将上面的九条与CSS规范做一一的对应。

视觉格式化模型

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

图片 21 图片 22

1 赞 3 收藏 评论

CSS规范映射

视觉格式化模型(visual formatting model)是用来处理文档并将它显示在视觉媒体上的机制,它也是CSS中的一个概念。

关于作者:^-^肥仔John

图片 23

偏前端的临栈工程师 个人主页 · 我的文章 · 5 ·    

图片 24

第一条和第二条可以总体归结为“浮动对于自身的影响”。

1.元素被视作块级元素,相当于display设置为“block”;

2.元素具备包裹性,会根据它所包含的元素实现宽度、高度自适应;

标准中有关第一条是有明确指明的:

if ‘float’ has a value other than ‘none’, the box is floated and ‘display’ is set according to the table below.

Specified value Computed value
inline-table table
inline, table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, table-caption, inline-block block
others same as specified

基本上说的就是第一条。

对于第二条,这个标准中也有明确的说明

for Floating, non-replaced elements If ‘width’ is computed as ‘auto’, the used value is the “shrink-to-fit” width. Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm. Roughly: calculate the preferred width by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width, e.g., by trying all possible line breaks. CSS 2.1 does not define the exact algorithm. Thirdly, find the available width: in this case, this is the width of the containing block minus the used values of ‘margin-left’, ‘border-left-width’, ‘padding-left’, ‘padding-right’, ‘border-right-width’, ‘margin-right’, and the widths of any relevant scroll bars.

Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).

其实这段话看的时候挺绕的,主要是几个width的含义不容易理解:

首选宽度(preferred width):完全不允许折行展示情况下的内容宽度

最小首选宽度(preferred minimum width):所有折行展示可能下的最小内容宽度

可用宽度(available width):包含块宽度减去margin,padding,border,滚动条宽等所有这些以后的差值

在通常情况下,按照上面的公式,这个自适应宽度(shrink-to-fit width)就是首选宽度,而首选宽度呈现出来的感觉就是“包裹”。

但是,看到这里有没有发现一个问题?就是所谓的首选宽度到底是如何计算的,如果一个浮动元素里包含另外一个浮动元素,它是如何计算的?是否要把子孙浮动元素的宽度考虑进去?标准似乎并没有更多的考虑这种情况。而由于这点”模糊“造成的问题,后面也会提及。

而关于高度

‘Auto’ heights for block formatting context roots

In certain cases (see, e.g., sections 10.6.4 and 10.6.6 above), the height of an element that establishes a block formatting context is computed as follows:

If it only has inline-level children, the height is the distance between the top of the topmost line box and the bottom of the bottommost line box.

If it has block-level children, the height is the distance between the top margin-edge of the topmost block-level child box and the bottom margin-edge of the bottommost block-level child box.

这个比width好理解也简单些,就是实在的“包裹”。

视觉格式化模型定义了盒(Box)的生成,盒主要包括了块盒、行内盒、匿名盒(没有名字不能被选择器选中的盒)以及一些实验性的盒(未来可能添加到规范中)。盒的类型由display属性决定。

第三、四、五、六条可以总体归结为“浮动对于兄弟元素的影响”。

3.浮动元素前后的块级兄弟元素忽视浮动元素的而占据它的位置,并且元素会处在浮动元素的下层(并且无法通过z-index属性改变他们的层叠位置),但它的内部文字和其他行内元素都会环绕浮动元素;

4.浮动元素前后的行内元素环绕浮动元素排列;

5.浮动元素之前的元素如果也是浮动元素,且方向相同,它会紧跟在它们后面;父元素宽度不够,换行展示;

6.浮动元素之间的水平间距不会重叠;

标准里对float的定义是

Floats. In the float model, a box is first laid out according to the normal flow, then taken out of the flow and shifted to the left or right as far as possible. Content may flow along the side of a float.

上面这句核心思想就是说,浮动元素最大的特点就是脱离了文档流。

标准中又对“脱离文档流”的结果做了描述:

Since a float is not in the flow, non-positioned block boxes created before and after the float box flow vertically as if the float did not exist. However, the current and subsequent line boxes created next to the float are shortened as necessary to make room for the margin box of the float.

我想这句整个证明了第三条和第四条的合法性。浮动元素对于块级兄弟元素以及行内兄弟元素的处理是有区别的。如果兄弟块盒没有生成新的BFC,那它其中的行内盒也会受到浮动元素的影响,为浮动元素让出位置,缩进显示。至于对齐的位置,标准中也有描述:

A floated box is shifted to the left or right until its outer edge touches the containing block edge or the outer edge of another float. If there is a line box, the outer top of the floated box is aligned with the top of the current line box.

这两条说明,float虽然使元素脱离的文档流,但是它却依然占据着位置,这其实也是影响外部元素宽度计算的一个原因之一,也是它跟绝对定位最大的不同。

至于其中提及的,会放置在块级元素之上,这个也有考据:

The contents of floats are stacked as if floats generated new stacking contexts, except that any positioned elements and elements that actually create new stacking contexts take part in the float’s parent stacking context. A float can overlap other boxes in the normal flow (e.g., when a normal flow box next to a float has negative margins). When this happens, floats are rendered in front of non-positioned in-flow blocks, but behind in-flow inlines.

第五条,这个是浮动元素行为九准则中规定的。这里列举一下:

  1. The left outer edge of a left-floating box may not be to the left of the left edge of its containing block. An analogous rule holds for right-floating elements.
  2. If the current box is left-floating, and there are any left-floating boxes generated by elements earlier in the source document, then for each such earlier box, either the left outer edge of the current box must be to the right of the right outer edge of the earlier box, or its top must be lower than the bottom of the earlier box. Analogous rules hold for right-floating boxes.
  3. The right outer edge of a left-floating box may not be to the right of the left outer edge of any right-floating box that is next to it. Analogous rules hold for right-floating elements.
  4. A floating box’s outer top may not be higher than the top of its containing block. When the float occurs between two collapsing margins, the float is positioned as if it had an otherwise empty anonymous block parent taking part in the flow. The position of such a parent is defined by the rules in the section on margin collapsing.
  5. The outer top of a floating box may not be higher than the outer top of any block or floated box generated by an element earlier in the source document.
  6. The outer top of an element’s floating box may not be higher than the top of any line-box containing a box generated by an element earlier in the source document.
  7. A left-floating box that has another left-floating box to its left may not have its right outer edge to the right of its containing block’s right edge. (Loosely: a left float may not stick out at the right edge, unless it is already as far to the left as possible.) An analogous rule holds for right-floating elements.
  8. A floating box must be placed as high as possible.
  9. A left-floating box must be put as far to the left as possible, a right-floating box as far to the right as possible. A higher position is preferred over one that is further to the left/right.

九准则其实已经基本上把浮动元素自身的行为方式定义的比较全面了,主要的原则就是:浮动元素之间不重叠;尽可能像边缘漂浮,但不越界。

第六条,在CSS标准描述margin的时候有提及:

Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children). Margins of elements that establish new block formatting contexts (such as floats and elements with ‘overflow’ other than ‘visible’) do not collapse with their in-flow children.

因此,也可证明合理。

块盒(block box)

第七、八、九条可以总体归结为“浮动对于包含元素的影响”。浮动使用时的另一批潜在坑就出现在对几个特点的应用上。

7.当包含元素中只有浮动元素时,包含元素将会高度塌陷;

8.浮动元素的父元素的非浮动兄弟元素,忽视浮动元素存在,在浮动元素之下展示;

9.浮动元素的父元素的浮动兄弟元素,会跟随浮动元素布局,仿佛处在同一父元素中。

首先,以上三条拥有一个共同的原因:浮动元素脱离文档流。

接着去读一下标准中有关高度计算的描述:

For block-level non-replaced elements in normal flow when ‘overflow’ computes to ‘visible’

If ‘margin-top’, or ‘margin-bottom’ are ‘auto’, their used value is 0. If ‘height’ is ‘auto’, the height depends on whether the element has any block-level children and whether it has padding or borders … Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored, and relatively positioned boxes are considered without their offset). Note that the child box may be an anonymous block box.

关键看最后一段,浮动元素的高度会被忽略的,因此一旦包含块中只包含浮动元素,那么包含块就不再有参考的计算高度,自然就塌陷了。当然,如果包含元素里还包含其他元素,那么它的高度会参考非浮动元素按标准中描述的规则计算。

第七条也就成立了。

那么第八条、第九条为什么?看CSS标准中的下面的描述:

References to other elements in these rules refer only to other elements in the same block formatting context as the float.

也就是说,float对同一个BFC内的元素有效。如果父元素没有触发生成新的BFC,那么父元素的兄弟元素都算是跟父元素中的元素处于同一BFC,也就会受浮动的影响,并且行为规则与同处于同一个父元素之中的元素的规则相同:块级元素重叠;行内元素环绕;浮动元素跟随。

正是因为浮动元素的这三条特点,因此,在使用了浮动元素以后,通常都要做“清除浮动“或”闭合浮动“的操作,来避免浮动元素对其他元素的影响。

到这里,浮动元素的九个特点基本上都在标准中找到了对应,但是我说的是基本,上面提及的有一个问题我们还没有完美解决,就是浮动元素的auto宽度计算规则。我们这里先举一个实际的例子来解答这个疑惑。

块盒有以下特性:

一个栗子

先看一下代码:

CSS

.ui-label { display: inline; } .form-section { width: 700px; margin: 0 0 60px; min-width: 960px; margin-left: 168px; margin-top: 60px; } .form-field-required { font-size: 14px; margin: 30px 0; } .form-field-required:before, .form-field-required:after { display: table; content: ''; } .form-field-required:after { clear: both; } .form-field-label { float: left; zoom: 1; width: 104px; line-height: 30px; text-align: left; vertical-align: top; } .form-field-value { line-height: 30px; padding-left: 12px; float: left; } .form-field-value-required-star { float: left; color: red; width: 12px; text-align: left; } .ui-textbox { position: relative; display: inline-block; } .ui-textbox input { color: #333333; background: #ffffff; border: 1px solid #dddddd; width: 240px; height: 24px; line-height: 24px; vertical-align: middle; box-sizing: content-box; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
.ui-label {
    display: inline;
}
 
.form-section {
    width: 700px;
    margin: 0 0 60px;
    min-width: 960px;
    margin-left: 168px;
    margin-top: 60px;
}
 
.form-field-required {
    font-size: 14px;
    margin: 30px 0;
}
 
.form-field-required:before,
.form-field-required:after {
    display: table;
    content: '';
}
 
.form-field-required:after {
    clear: both;
}
 
.form-field-label {
    float: left;
    zoom: 1;
    width: 104px;
    line-height: 30px;
    text-align: left;
    vertical-align: top;
}
 
.form-field-value {
    line-height: 30px;
    padding-left: 12px;
    float: left;
}
 
.form-field-value-required-star {
    float: left;
    color: red;
    width: 12px;
    text-align: left;
}
 
.ui-textbox {
    position: relative;
    display: inline-block;
}
 
.ui-textbox input {
    color: #333333;
    background: #ffffff;
    border: 1px solid #dddddd;
    width: 240px;
    height: 24px;
    line-height: 24px;
    vertical-align: middle;
    box-sizing: content-box;
}

XHTML

<section class="form-section"> <div class="form-field-required"> <esui-label class="form-field-label ui-label" title="">姓名:</esui-label> <div class="form-field-value"> <div class="form-field-value-required-star">*</div> <div id="name" class="ui-textbox"> <input type="text" title="金额" style="width: 191px;" /> </div> </div> </div> </section>

1
2
3
4
5
6
7
8
9
10
11
<section class="form-section">
    <div class="form-field-required">
        <esui-label class="form-field-label ui-label" title="">姓名:</esui-label>
        <div class="form-field-value">
            <div class="form-field-value-required-star">*</div>
            <div id="name" class="ui-textbox">
                <input type="text" title="金额" style="width: 191px;" />
            </div>
        </div>
    </div>
</section>

这段代码算是使用float实现元素横排展示的一个比较复杂的例子(我并没有说这个实现方案是推荐的,后面我会解释为什么其实不推荐)。也最大程度的利用float的特点,并且能够解答我上面提出的那个疑惑。为了清楚的说明,我们可以从裸样式入手,一步一步随着样式的增加,跟踪展示效果:

第一步:去掉所有结构相关的代码(为了清晰展示结构,加上背景样式),展示是这样的:

图片 25第一步

“form-field-label”原来的display属性是inline,因此虽然设定了宽高,却并没有作用;“form-field-value”是块级盒,包括里面的“星号”、“输入框”、“文字描述”也都是,因此垂直展示。

第二步,为“form-field-label”和“form-field-value”增加float属性,展示效果如下:

图片 26

第二步

这个效果的出现,利用了上述浮动特点的第一条、第二条、第五条和第七条。而关于’包裹性’也有了最简单情况的示例展示:即容器的长方框恰好包住无折行条件下的容器内的元素。

第三步,为“form-field-value”中的“form-field-value-required-star”增加float属性,此时展示效果如下:

图片 27第三步

这个效果的出现,利用了上述浮动特点的第一条、第二条、第三条和第四条。 需要着重关注的,一个是兄弟元素’ui-textbox’在占据了星号位置的同时,’ui-textbox’中的行内元素input缩进环绕星号展示,也就是第四条的完美体现;另一个则是星号浮动属性的设置对于父元素宽度计算的影响。我们发现,虽然input行内元素缩进展示,但是父元素的宽度却并没有因此而随之增加,也就是,它的宽度仍然是未缩进前包含块的“首选宽度”,即input宽;但是如果把星号的宽度提高到超过input宽,那么你会发现,包含块的宽度变成了星号的宽度。这就解答了我之前的问题:如果一个浮动元素里包含另外一个浮动元素,它的auto宽度计算是会考虑进来浮动元素的,计算规则是包含块去掉所有后代浮动元素后的“首选宽度”与所有后代浮动元素宽度和的最大值。

第四步,为“ui-textbox”设置display属性值为“inline-block”,此时展示效果如下:

图片 28第四步

为什么包含块的宽度突然可以足够星号和输入框同时并排了?原因是inline-block的设置改变了原本块级元素的行为,CSS标准里有如下描述:

This value causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.

所以此时,“ui-textbox”就是作为一个行内元素整体缩进展示,而不是像前面的,本身并没有缩进,只是内部的input缩进。那么此时包含块去掉所有后代浮动元素后的“首选宽度”就是“缩进距离”与“ui-textbox”宽度的和。所以就足够星号和输入框并排展示了。

但是你觉着这样就没问题了?我们来改变一下源码:

  1. 去掉ui-textbox的静态class赋值
  2. 使用js动态分配class:
JavaScript

var nameInput = document.getElementById('name'); setTimeout(
function () { nameInput.setAttribute('class', 'ui-textbox'); }, 0 );

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a303ef91946227217-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a303ef91946227217-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6a303ef91946227217-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a303ef91946227217-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f6a303ef91946227217-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a303ef91946227217-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f6a303ef91946227217-7">
7
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a303ef91946227217-1" class="crayon-line">
var nameInput = document.getElementById('name');
</div>
<div id="crayon-5b8f6a303ef91946227217-2" class="crayon-line crayon-striped-line">
setTimeout(
</div>
<div id="crayon-5b8f6a303ef91946227217-3" class="crayon-line">
    function () {
</div>
<div id="crayon-5b8f6a303ef91946227217-4" class="crayon-line crayon-striped-line">
        nameInput.setAttribute('class', 'ui-textbox');
</div>
<div id="crayon-5b8f6a303ef91946227217-5" class="crayon-line">
    },
</div>
<div id="crayon-5b8f6a303ef91946227217-6" class="crayon-line crayon-striped-line">
    0
</div>
<div id="crayon-5b8f6a303ef91946227217-7" class="crayon-line">
);
</div>
</div></td>
</tr>
</tbody>
</table>

再运行一下,发现了什么:在几乎所有的浏览器(包括IE)效果都没有变化,但是在Chrome下却坑了,效果是酱紫滴:

包含块的宽度又不够并排了,变成了输入框的宽度。DOM样式和结构不可能变化,但是有了这样的区别,是为什么?我们看到上面代码里最诡异的也就是延迟class的赋值,从结果看,在Chrome下,这个延迟赋值显然没有生效,也就是并没有触发包含块宽度的重计算。再深层的原因还没有研究,因为Safari下也有同样的问题,所以我只当它是Webkit的bug:浮动元素中后代元素,动态设置display为inline-block,改变元素的盒属性,外部浮动元素无法感知。

那么怎么办?放弃Chrome?显然不行…… 使用其他方式,在设置完display以后强制触发宽度变化?目前还没有找到哪个属性可以,甚至设置为float,也都无效。

其实根本也不必费力寻找方式去触发宽度变化,我举这个例子,想表达的是,使用float实现并排展示,并在其中掺杂inline-block实现并排并不是明智之举,在未来会大大增加理解和维护的难度。

那么,在实际开发中,到底是用float实现并排更推荐一些还是inline-block更推荐一些,关于这个的讨论,网上也都不少。我个人的观点,两者各有利弊:

当元素的CSS属性display为block,list-item或table时,它是块级元素 block-level;

float:

好处:

  1. 天然的可以顶部上边框对齐,无需做位置微调
  2. 浮动元素之间没有空白间距

坏处:

  1. 浮动元素对元素本身,以及它的父元素,兄弟元素带来的影响非常大,使用浮动后要认真处理好‘浮动清除’等事宜
  2. 当需要引用外部创建的控件,无法有效控制DOM结构和创建时机时,容易产生不可预知的bug

视觉上呈现为块,竖直排列;

inline-block:

好处:

简单、单纯,不会对其他元素造成影响

坏处:

  1. 对齐是个问题,理想情况下,通过设置vertical-align为相同值即可对齐,但复杂的结构下,比如引入了外部控件,控件中有自己的vertical-align定位时,需要考虑的比较多
  2. inline-block包含html空白节点,如果html中一系列元素每个元素之间都换行了,当你对这些元素设置inline-block时,这些元素之间就会出现空白
  3. 低版本IE浏览器不支持,需要做额外的模拟来实现兼容(这个其实可以忽略了……)

块级盒参与(块格式化上下文);

结语

float是个复杂的属性,彻底了解它甚至需要将CSS中所有与视觉格式化模型(Visual formatting model)相关的知识都撸一遍。这篇文章只是简单的带大家了解下标准里是如何描述我们平时熟悉的那些浮动元素特点的,让大家用的时候,有疑问也有据可循。由于篇幅有限,仍然有很多更细节的内容没有解释清楚,感兴趣的各位可以自行前往W3C CSS2.1了解,主要内容在第九、十两章中。

1 赞 4 收藏 评论

图片 29

每个块级元素至少生成一个块级盒,称为主要块级盒(principal block-level box)。一些元素,比如

,生成额外的盒来放置项目符号,不过多数元素只生成一个主要块级盒。

行内盒(inline box)

当元素的CSS属性display的计算值为inline,inline-block或inline-table时,称它为行内级元素;

视觉上它将内容与其它行内级元素排列为多行;典型的如段落内容,有文本(可以有多种格式譬如着重),或图片,都是行内级元素;

行内级元素生成行内级盒(inline-level boxes),参与行内格式化上下文(inline formatting context)。同时参与生成行内格式化上下文的行内级盒称为行内盒(inline boxes)。所有display:inline的非替换元素生成的盒是行内盒;

不参与生成行内格式化上下文的行内级盒称为原子行内级盒(atomic inline-level boxes)。这些盒由可替换行内元素,或display值为inline-block或inline-table的元素生成,不能拆分成多个盒;

匿名盒(anonymous box)

匿名盒也有份匿名块盒与匿名行内盒,因为匿名盒没有名字,不能利用选择器来选择它们,所以它们的所有属性都为inherit或初始默认值;

如下面例子,会创键匿名块盒来包含毗邻的行内级盒:

XHTML

Some inline text

followed by a paragraph

followed by more inline text.

1

2

3

4

5

Some inline text

followed by a paragraph

followed by more inline text.

三个定位方案

在定位的时候,浏览器就会根据元素的盒类型和上下文对这些元素进行定位,可以说盒就是定位的基本单位。定位时,有三种定位方案,分别是常规流,浮动已经绝对定位。

常规流(Normal flow)

在常规流中,盒一个接着一个排列;

块级格式化上下文里面, 它们竖着排列;

行内格式化上下文里面, 它们横着排列;

当position为static或relative,并且float为none时会触发常规流;

对于静态定位(static positioning),position: static,盒的位置是常规流布局里的位置

对于相对定位(relative positioning),position: relative,盒偏移位置由这些属性定义top,bottom,leftandright。即使有偏移,仍然保留原有的位置,其它常规流不能占用这个位置。

浮动(Floats)

盒称为浮动盒(floating boxes);

它位于当前行的开头或末尾;

导致常规流环绕在它的周边,除非设置 clear 属性;

绝对定位(Absolute positioning)

绝对定位方案,盒从常规流中被移除,不影响常规流的布局;

它的定位相对于它的包含块,相关CSS属性:top,bottom,left及right;

如果元素的属性position为absolute或fixed,它是绝对定位元素;

对于position: absolute,元素定位将相对于最近的一个relative、fixed或absolute的父元素,如果没有则相对于body;

块格式化上下文

到这里,已经对CSS的定位有一定的了解了,从上面的信息中也可以得知,块格式上下文是页面CSS 视觉渲染的一部分,用于决定块盒子的布局及浮动相互影响范围的一个区域

BFC的创建方法

根元素或其它包含它的元素;

浮动(元素的float不为none);

绝对定位元素(元素的position为absolute或fixed);

行内块inline-blocks(元素的display: inline-block);

表格单元格(元素的display: table-cell,HTML表格单元格默认属性);

overflow的值不为visible的元素;

弹性盒 flex boxes(元素的display: flex或inline-flex);

但其中,最常见的就是overflow:hidden、float:left/right、position:absolute。也就是说,每次看到这些属性的时候,就代表了该元素以及创建了一个BFC了。

BFC的范围

BFC的范围在MDN中是这样描述的。

A block formatting context contains everything inside of

the element creating it that is not also inside a descendant element

that creates a new block formatting context.

中文的意思一个BFC包含创建该上下文元素的所有子元素,但不包括创建了新BFC的子元素的内部元素。

这段看上去有点奇怪,我是这么理解的,加入有下面代码,class名为.BFC代表创建了新的块格式化:

这段代码表示,#div_1创建了一个块格式上下文,这个上下文包括了#div_2、#div_3、#div_4、#div_5。即#div_2中的子元素也属于#div_1所创建的BFC。但由于#div_5创建了新的BFC,所以#div_6和#div_7就被排除在外层的BFC之外。

我认为,这从另一方角度说明,一个元素不能同时存在于两个BFC中

BFC的一个最重要的效果是,让处于BFC内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。这是利用BFC清除浮动所利用的特性,关于清除浮动将在后面讲述。

如果一个元素能够同时处于两个BFC中,那么就意味着这个元素能与两个BFC中的元素发生作用,就违反了BFC的隔离作用,所以这个假设就不成立了。

BFC的效果

就如刚才提到的,BFC的最显著的效果就是建立一个隔离的空间,断绝空间内外元素间相互的作用。然而,BFC还有更多的特性:

Floats, absolutely positioned elements, block containers

(such as inline-blocks, table-cells, and table-captions) that are not

block boxes, and block boxes with ‘overflow’ other than ‘visible’

(except when that value has been propagated to the viewport) establish

new block formatting contexts for their contents.

In a block formatting context, boxes are laid out one

after the other, vertically, beginning at the top of a containing block.

The vertical distance between two sibling boxes is determined by the

‘margin’ properties. Vertical margins between adjacent block-level boxes

in a block formatting context collapse.

In a block formatting context, each box’s left outer edge

touches the left edge of the containing block (for right-to-left

formatting, right edges touch). This is true even in the presence of

floats (although a box’s line boxes may shrink due to the floats),

unless the box establishes a new block formatting context (in which case

the box itself may become narrower due to the floats).

简单归纳一下:

内部的盒会在垂直方向一个接一个排列(可以看作BFC中有一个的常规流);

处于同一个BFC中的元素相互影响,可能会发生margin collapse;

每个元素的margin box的左边,与容器块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此;

BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然;

计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算;

浮动盒区域不叠加到BFC上;

这么多性质有点难以理解,但可以作如下推理来帮助理解:html的根元素就是,而根元素会创建一个BFC,创建一个新的BFC时就相当于在这个元素内部创建一个新的,子元素的定位就如同在一个新页面中那样,而这个新旧html页面之间时不会相互影响的。

上述这个理解并不是最准确的理解,甚至是将因果倒置了(因为html是根元素,因此才会有BFC的特性,而不是BFC有html的特性),但这样的推理可以帮助理解BFC这个概念。

从实际代码来分析BFC

讲了这么多,还是比较难理解,所以下面通过一些例子来加深对BFC的认识。

实例一

CSS

* {

margin: 0;

padding: 0;

}

.left{

background: #73DE80; /* 绿色 */

opacity: 0.5;

border: 3px solid #F31264;

width: 200px;

height: 200px;

float: left;

}

.right{ /* 粉色 */

background: #EF5BE2;

opacity: 0.5;

border: 3px solid #F31264;

width:400px;

min-height: 100px;

}

.box{

background:#888;

height: 100%;

margin-left: 50px;

}

*{

margin:0;

padding:0;

}

.left{

background:#73DE80;/* 绿色 */

opacity:0.5;

border:3pxsolid#F31264;

width:200px;

height:200px;

float:left;

}

.right{/* 粉色 */

background:#EF5BE2;

opacity:0.5;

border:3pxsolid#F31264;

width:400px;

min-height:100px;

}

.box{

background:#888;

height:100%;

margin-left:50px;

}

显示效果:

图片 30

绿色框(’#left’)向左浮动,它创建了一个新BFC,但暂时不讨论它所创建的BFC。由于绿色框浮动了,它脱离了原本normal

flow的位置,因此,粉色框(’#right’)就被定位到灰色父元素的左上角(特性3:元素左边与容器左边相接触),与浮动绿色框发生了重叠。

同时,由于灰色框(’#box’)并没有创建BFC,因此在计算高度的时候,并没有考虑绿色框的区域(特性6:浮动区域不叠加到BFC区域上),发生了高度坍塌,这也是常见问题之一。

实例二

现在通过设置overflow:hidden来创建BFC,再看看效果如何。

XHTML

.BFC{

overflow: hidden;

}

8.BFC{

overflow:hidden;

}

灰色框创建了一个新的BFC后,高度发生了变化,计算高度时它将绿色框区域也考虑进去了(特性5:计算BFC的高度时,浮动元素也参与计算);

而绿色框和红色框的显示效果仍然没有任何变化。

实例三

现在,现将一些小块添加到粉色框中,看看效果:

XHTML

.little{

background: #fff;

width: 50px;

height: 50px;

margin: 10px;

float: left;

}

.little{

background:#fff;

width:50px;

height:50px;

margin:10px;

float:left;

}

由于粉色框没有创建新的BFC,因此粉色框中白色块受到了绿色框的影响,被挤到了右边去了。先不管这个,看看白色块的margin。

实例四

利用同实例二中一样的方法,为粉色框创建BFC:

XHTML

一旦粉色框创建了新的BFC以后,粉色框就不与绿色浮动框发生重叠了,同时内部的白色块处于隔离的空间(特性4:BFC就是页面上的一个隔离的独立容器),白色块也不会受到绿色浮动框的挤压。

总结

以上就是BFC的分析,BFC的概念比较抽象,但通过实例分析应该能够更好地理解BFC。在实际中,利用BFC可以闭合浮动(实例二),防止与浮动元素重叠(实例四)。同时,由于BFC的隔离作用,可以利用BFC包含一个元素,防止这个元素与BFC外的元素发生margin

collapse。

本文由澳门威斯尼人平台登录发布于Web前端,转载请注明出处:重新认知Box

相关阅读