神刀安全网

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

前言

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

何为盒子模型?  

盒子模型到底何方神圣居然可以作为CSS的基础?闻名不如见面,上图了喂!

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

再来张切面图吧!

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

下面我们以  <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元素的宽/高"挂在口边,其实这句话是有误的。

1. 首先css属性width和height作用于div元素所产生的盒子,而不是元素本身;

2. 另外盒子模型由4个盒子组成,那width和height到底是作用于哪些盒子呢?

这里就分为IE盒子模型和标准盒子模型了。

   IE box model    

IE5.5(怪异模式)采用IE盒子模型,其它将使用W3C标准盒子模型。

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

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

  Standard box model  

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

 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:

 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不起作用。。。

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

对于block-level box

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

CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins 对于inline-level box

 <span class="defined-wh"></span> 
CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

行级盒子的宽度怎么会是0呢?高度是有的但不是50px啊,到底什么回事啊?

原因很简单,那就是行级盒子的content box的高/宽根本就不是通过height/width来设置的。

content box/area的高由font-size决定的;

content box/area的宽等于其子行级盒子的外宽度(margin+border+padding+content width)之和。

  行级盒子被挤断了。。。

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

对于block-level box

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

CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins 对于inline-level box

 <span class="broken">一段文字一段文字一段文字一段文字一段文字一段文字</span> 
CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

行级盒子被五马分尸了,可怜兮兮的。更可怜的是我理解不了。。。

其实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。

看到了没?行级盒子真的会被分尸的,好残忍哦:|

 

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

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

对于block-level box

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

CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins 对于inline-level box

 <div>before bababababababa</div> <span class="existed">babababababababababa</span> <div>after bababababababa</div> 
CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

看,行级盒子的margin/border/padding-top/bottom怎么均不占空间的?难道行级盒子仅有content box占空间吗?

这里已经涉及到水平和垂直方向排版的范畴了,仅以盒子模型已无法解析理解上述的问题。

(要结合https://www.w3.org/TR/CSS2/box.html和https://www.w3.org/TR/CSS21/visuren.html、https://www.w3.org/TR/CSS21/visudet.html来理解了!)

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

和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高度的计算方式( https://www.w3.org/TR/CSS21/visudet.html#line-height )

>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.

 .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; } 
 <span class="parent">   <span class="child">     <span class="inline-block">display:inline-block元素</span>     xp子元素的文字   </span>   xp父元素的文字 </span> <div class="other">其他元素</div> 
CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

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属性垂直对齐,造成各“高度”间并不以上边界或下边界对齐;

3. 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

 anonymous block-level box <div class="margins"></div> anonymous block-level box <div class="margins border"></div> anonymous block-level box 
 .margins{margin: 50px 0 70px;} .border{border: solid 1px red;} 
CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

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

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

 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 
 .parent-margins{margin: 25px 0;} .margins{margin: 50px 0 25px;} .border{border: solid 1px red;} 
CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

当父子元素margin-top间或margin-bottom间没有padding、border阻隔时,则会margin会发生重叠。

注意空白字符会造成目标父子元素间的存在anonymous block-level box,导致margin不重叠。

 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 

CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins 3. 兄弟元素margin-bottom/top collapsing

 <div class="margins">former</div> <div class="margins">latter</div> 
 .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或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的盒子与in-flow或floated的兄弟盒子均不会发生margin重叠。

 <div class="margins border">sibling</div> <div class="margins border float">floats1</div> <div class="margins border float">floats2</div> 
 .margins{margin: 50px 0 50px;} .border{border: solid 1px red;} .float{float:left;width:200px;} 

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

总结

若有纰漏,望各位指正,谢谢!

尊重原创,转载请注明来自: http://www.cnblogs.com/fsjohnhuang/p/5259121.html 肥子John^_^

感谢

http://div.io/topic/834?page=1#3261(BFC)

http://www.cnblogs.com/giggle/p/5236982.html(BFC)

https://segmentfault.com/a/1190000003043991 (IFC)

http://www.cnblogs.com/winter-cn/archive/2013/05/11/3072929.html(BFC/IFC)

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮