w3c系列之CSS(四):深入理解盒模型

简介:

盒模型是一个老生常谈的话题,本身并不复杂,它描述了文档树所产生的矩形框以及根据可视化格式模型(visual formatting model)所产生的布局结构。

曾经看到一道面试题:说说CSS中的盒模型?网上的回答都是margin,border,padding,width,height之类的,尼玛都是复制粘贴的吧= =.....要是这篇文章也这么写的话就跟前面三篇没啥区别了,既然要深入理解,那就谈点高大上的东西。

1.要深入,先入门

首先还是得对盒模型做个简单而详细的介绍,想要跑,基础要打好~,盗用w3c一张图:

我们从里到外逐步分析:
  • 最里面是Content,决定Content大小的因素有很多,比如width,height属性,content内部是否还有box,是否是table等,所有的这些都将在可视化模型中详细讲到;
  • 然后是padding内边距,这个没啥好讲的;
  • 再外面是border,这个比较好玩~,虽然内外边距和边框都能单独设置四个方向的尺寸,但是CSS为border提供了更多的设置:border-color,border-style,有兴趣可以去看另外一篇写border的文章:CSS好玩的边框
  • 最外面是margin(注意他是透明的)。一个盒子没啥讲的,许多盒子在一起就有意思了。有可能会出现collapsing margins(外边距坍塌),也就是相邻的两个盒子的垂直外边距会合并(水平外边距是不会合并的)。
这就是盒模型的简单介绍了。不过盒模型可没这么简单,并不是所有元素都支持所有的margin和padding(比如内联元素,设置竖直方向的margin,padding是无效的),而且,虽然前面说了两个盒子竖直排列会发生垂直外边距坍塌,但并不是所有时候都会这样,比如下面这种情况:
	<style>
		body{background:#aaa}
		div{
			margin:50px;
			background:#0ff;
			width:50%;height:50px;
			float:left;
		}
	</style>
	<body>
		<div>
			box1	
		</div>
		<div>
			box2	
		</div>
	</body>


我擦,那到底什么时候会合并,什么时候才不会合并啊?以前看书的时候没说过这种情况啊!/*那是因为你没有去看w3c*/折叠也是有规则的:
    1. 两个或多个毗邻的普通流中的块元素垂直方向上的margin会折叠
    2. 浮动元素/inline-block的元素/绝对定位元素的margin不会和垂直方向上的其他元素的margin折叠
    3. 创建了块级格式化内容(传说中的BFC)的元素,不和它的子元素发生margin折叠
    4. 元素自身的margin-bottom和margin-top相邻时也会折叠
更加详细的折叠计算戳这里:http://bbs.csdn.net/topics/340188875,下面直接进入本文重点。

2.可视化格式模型(Visual formatting model

2.1简介

这中文名字听起来挺别扭的,其实就是浏览器如何将document tree处理成你所看到的页面的过程模型。

/*为了方便以后就叫VFM吧...*/

不过VFM也不是描述了页面处理的全部细节,比如它并未描述letter-spacing的格式算法。(又是一个坑)

在VFM中,每一个DOM元素都会创建0个或多个盒子,这些盒子的布局通常受下面一些因素的影响:

  • 盒子的尺寸和类型
  • 盒子的定位方式(普通流,浮动流,绝对定位)
  • document tree中元素之间的关系
  • 额外因素(比如viewport的大小,图片的固有尺寸等)

viewport是啥?就是你屏幕上所看到的页面区域啦,通常页面区域比viewport大,所以需要一个滚动条来查看下面的内容,就像这篇文章一样。(当然你可以用鼠标滚轮)

2.2盒子的类型

盒模型不只是padding,border,margin,他还有许多不同的类型。这通常取决于盒子的display属性。

2.2.1块级元素(block-level elements )和块框(block boxes)

如果元素的display属性为block,list-item或者table,那么该元素就会成为block-level元素。这里有几个概念要搞清:
  • containing box:包含框。一个元素的包含框就是包含它的框,比如<div><p>test</p></div>,p的包含框就是div,而div为p建造了一个包含框。
  • block-level box:块级框,块级元素所产生的框。块级元素(不包含 table),会形成仅包含块框或仅包含行内框的主块框( principal block box )。主块框会为子孙元素建立包含框,生成内容,并且也是涉及所有定位体系的框。主块框参与BFC。
  • block container box:块容器框。块容器框要么只包含块级框,要么只包含内联框(inline-level boxes)。虽然名字有“块”,但并不是所有块容器框都是块级框:non-replaced inline blocks,non-replaced table cells都是块容器框,但不是块级框。
  • block box:块框,既是块级框,也是块容器框的框。
有些时候,在上下文很明确的条件下,"block-level box", "block container box" 和"block box"都缩写为"block"。

是不是有点晕了= =,慢慢看就理解了,为了避免翻译问题,后面遇到专业术语都用英文表示吧......
这节术语真是多,又出现了一个a nonymous block boxes(匿名块框),比如像下面这种情况:
<div>
  Some text
  <p>More text</p>
</div>
假设div,p都是块级框(display:block),div中有内联文本Some text和块级文本More text,但是为了更好地生成格式化模型,会给内联文本外面加一个匿名块框。
http://www.w3.org/TR/2011/REC-CSS2-20110607/images/anon-block.png
换句话说:如果一个block container box包含了一个block-level box,那么标准会强制使里面只包含block-level的boxes(或者run-in boxes)。

2.2.2内联元素(inline-level elements)和内联框(inline boxes)

内联元素就是那些不会生成新的内容块的元素,这些内容都是分布在同一行的。当display属性为inline,inline-table,inline-block时就会生成inline-level boxes,这些boxes会参与IFC。inline box就是内容参与其内部包含的IFC的inline level box。display为inline的non-replaced element会生成inline box。但是inline-level boxes并等于inline boxes(比如inline-table elements,inline-block elements,replaced inline-level elements)。那些不属于inline boxes的inline-level boxes被称作atomic inline-level boxes,这些boxes作为单独的不透明的框参与IFC。
有匿名块框就有匿名内联框(anonymous inline boxes),比如像下面这种情况:

<pre name="code" class="html"><p>some <em>name</em>      </p>
 
 some就是匿名内联框。可以看到与匿名块框不同的是,块级框p里面包含的不是块级框了,而是内联框em,所以会产生匿名的some内联框。之所以叫他们匿名框,是因为没有相应的内联元素与之对应,但是他们的属性还是可以从p那里继承到的。 
可以看到em的后面还有很多空格,根据“white-space”的特性这些空格会被压缩,所以这里不会产生匿名内联框。
匿名块框和匿名行内框统称为匿名框。

2.2.3 display属性

可取值:  inline | block | list-item | run-in | compact | marker |table | inline-table | table-row-group | table-header-group |table-footer-group | table-row | table-column-group | table-column |table-cell | table-caption | none | inherit初始值:   inline适用于:   所有元素可否继承:   否百分比:   N/A媒介:   所有
display:run-in是CSS3中新添加的属性,添加了该属性的元素会根据上下文机智地作为块级元素或内联元素显示。(怎么个机智法?真坑...)
注意,尽管display初始值为inline,但是UA的初始值可能会覆盖它,比如div,p的display值默认为block。各个元素的默认值,在HTML4中就有告知:

2.3定位机制

CSS中有三大定位体系: normal flow(普通流),floats(浮动流),absolute positioning(绝对定位)。定位方式与postion属性有关:
可取值:   static | relative | absolute | fixed | inherit初始值:   static适用于:   all elements可否继承:   no百分比:   N/A媒体:     visual计算值:   as specified
其中,static,relative属于常规流,absolute和fixed属于绝对定位,如果元素的float属性不为none,那么他就属于浮动流。
绝对定位所谓的绝对其实是相对的,absolute元素是相对其第一个具有relative特性的祖先元素偏移的,如果祖先元素都是static的,那么就相对根元素偏移(UA一般会将根元素设为static)。而fixed是相对于屏幕内容区域定位的,比如有的网站导航栏时钟显示在网页上方,这就是用了fixed定位。
另外,绝对定位是脱离文档流的,他们的位置不会对普通流的定位产生任何影响。
常规流(普通流)中的boxes都属于formatting context(格式化上下文)。 /*格式化上下文这翻译真心让人难以理解,context有环境之意,这句话的意思应该就是说常规流中的盒子定位时们都会受到其他盒子的影响*/ 之前有说到BFC和IFC,BFC就是block formatting contexts,IFC就是inline formatting contexts,看名字就知道是常规流中的一种。relative positioning也是常规流中的一种。
有关这三大定位的单独介绍网上有很多详细的资料,这里不一一展开,这里对这三者进行一个比较。
为了说明三者间差异,我们举个例子:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
  <HEAD>
    <TITLE>Comparison of positioning schemes</TITLE>
  </HEAD>
  <BODY>
    <P>
      Beginning of body contents.
      <SPAN id="outer"> 
        Start of outer contents.
        <SPAN id="inner"> 
          Inner contents.
        </SPAN>
        End of outer contents.
      </SPAN>
      End of body contents.
    </P>
  </BODY>
</HTML>
我们为它添上如下样式:
body { display: block; font-size:12px; line-height: 200%;width: 400px; height: 400px }
p    { display: block }
span { display: inline }
首先来看普通流,为了区分我们给文字加上颜色:
#outer { color: red }
#inner { color: blue }
http://www.w3.org/TR/2011/REC-CSS2-20110607/images/flow-generic.png
上面说到了,p中只有内联元素span,所以会产生匿名内联框,p中所有的内容都会作为IFC呈现。
再看一下相对定位的情况,我们更改#outer和#inner的属性:
#outer { position: relative; top: -12px; color: red }
#inner { position: relative; top: 12px; color: blue }
http://www.w3.org/TR/2011/REC-CSS2-20110607/images/flow-relative.png
可以看到#outer和#inner都相对于原来位置产生了偏移。
然后再看看float定位是什么效果,继续更改#outer和#inner属性:
http://www.w3.org/TR/2011/REC-CSS2-20110607/images/flow-float.png

最后看下绝对定位的效果:
#outer { 
    position: absolute; 
    top: 200px; left: 200px; 
    width: 200px; 
    color: red;
}
#inner { color: blue }
http://www.w3.org/TR/2011/REC-CSS2-20110607/images/flow-absolute.png

绝对定位和relative一起用:
#outer { 
  position: relative; 
  color: red 
}
#inner { 
  position: absolute; 
  top: 200px; left: -100px; 
  height: 130px; width: 130px; 
  color: blue;
}

效果如下:
http://www.w3.org/TR/2011/REC-CSS2-20110607/images/flow-abs-rel.png

如果不把#outer设为相对定位,就会像下面这样:
http://www.w3.org/TR/2011/REC-CSS2-20110607/images/flow-static.png

如果你能理解上面这些代码产生的效果,那么你就理解了三者之间的差异。

2.4 position,display,float属性之间的关系

这三个属性与盒模型定位息息相关。三者之间的相互影响遵循下面的规则:
  1. 如果display为none,那么position和float失效。因为这种情况下不产生框(注意是不产生框!如果用visibility:hidden或者opacity:0的话那叫隐藏框,虽然你看不见框,但框就在那里...);
  2. 否则,如果display为absolute或fixed,即绝对定位,这时float会失效;
  3. 否则,如果float不为none,那么display属性会发生相应的改变,具体见下表;
  4. 否则,如果元素是根元素,那么display也会按下表相应变化;
  5. 如果以上情况都不满足,就用你在CSS里指定的那个值啦~
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
看吧,如果你想给一个inline元素设置margin-top,那么你可以让它浮动一下~

其实有关定位并不仅仅只涉及到这三个属性,还有z-index也用的比较多。(有关z-index的深入介绍,戳这里:http://readit.sinaapp.com/?p=55

3.总结

这篇坑爹的文章涉及的概念很多,不理解去网上查,或者直接去w3c:http://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html。如果文中有错误请及时指出!一切后果本人概不负责!呵呵!
本文算是对盒模型做了一个比较深入的介绍,但是对visual formatting model却只是作了一个简单的介绍,后面会对visual formatting的更多细节进行学习。(又是一个坑...)

相关文章
|
1月前
|
前端开发
CSS语言的盒模型
CSS语言的盒模型
|
3月前
|
前端开发 JavaScript Java
【面试题】面试官:说说你对 CSS 盒模型的理解
【面试题】面试官:说说你对 CSS 盒模型的理解
|
4月前
|
前端开发
【前端|CSS系列第3篇】CSS盒模型、浮动及定位
【前端|CSS系列第3篇】CSS盒模型、浮动及定位
|
2月前
|
Web App开发 存储 前端开发
【JavaEE初阶】 CSS相关属性,元素显示模式,盒模型,弹性布局,Chrome 调试工具||相关讲解
【JavaEE初阶】 CSS相关属性,元素显示模式,盒模型,弹性布局,Chrome 调试工具||相关讲解
|
2月前
|
前端开发
css3基础语法与盒模型
css3基础语法与盒模型
16 0
|
2月前
|
前端开发 JavaScript API
CSS基础框盒模型:打造炙手可热的网页布局!
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。 ———————————————— 版权声明:本文为博主原创文
|
3月前
|
前端开发 容器
CSS Flex 弹性盒模型
当元素设置了display: flex样式时,表示当前元素开启了flex布局,这个元素成为一个 flex 容器(flex container)。这个元素不会脱离文档流,元素中的内容沿着两个轴的方向进行布局。 开启了flex布局的元素就是一个伸缩容器(flex 容器),伸缩容器中所有的子元素就是伸缩项目。
|
6月前
|
前端开发 容器
Web前端 — CSS之盒模型 以及margin负值、塌陷重叠问题
Web前端 — CSS之盒模型 以及margin负值、塌陷重叠问题
31 0
|
7月前
|
前端开发
Css盒模型的概念及组成
Css盒模型的概念及组成
Css盒模型的概念及组成
|
8月前
|
前端开发 搜索推荐 BI
HTML&CSS Day04 CSS盒模型
HTML&CSS Day04 CSS盒模型
65 0