前言
盒模型是CSS中最重要最核心的概念,整个概念基本上环绕在整个CSS知识体系中,所有样式与排版都围绕着它进行。理解盒模型才能更好地排版网页与布局网页,后面遇到的排版与布局困难也能快速定位问题所在。
不要觉得简单而忽略它,往往越简单的东西蕴含的威力越大。换成人生道理就是说,不要小看一个人,TA虽然穿着短裤拖鞋,背后可能是拥有10栋出租楼的包租公或包租婆。
盒模型
盒模型又称框模型,指把文档节点看成一个盒子。它是一种网页设计思维模型。
在HTML文档解析时,每个节点都会被描述为一个盒模型,然后一个盒子套进另一个盒子中,再根据各个节点相应CSS规则渲染为一个井井有条的网页。一个完整的网页就像惊喜爆炸礼盒,层层嵌套,直到最后一层出现惊喜为止。有女友的,赶紧买一个试试!
组成
盒模型由以下属性组成,由外到内使用公式表示:box = margin + border + padding + content。除了content,其余属性都包括left、right、top和bottom等扩展属性。
- margin:边距,外部透明区域,负责隔离相邻盒子
- border:边框,内部着色区域,负责隔离边距与填充,包括
width、style、color三个扩展属性 - padding:填充,内部着色区域,负责扩展盒子内部尺寸
- content:内容,以
文本或节点存在的占用位置
padding着色随background-color而变,可用background-clip隔离,在第10章会详细讲述。content不是属性,只是作为盒模型扩展理解使用。
理解
节点由外到内一层一层深入,通过上述公式组成一个完整的盒模型,所以在理解盒模型时记住这四个属性及其从外到内的顺序即可。换另一种方式理解,可把它看作快递包裹。两个快递包裹的间距就是margin,快递包裹的纸皮就是border,打开快递包裹,填充物料就是padding,把填充物料打开看到的物品,就是content。这样理解是不是特别简单?
类型
因为历史原因,盒模型分化出两种类型,分别是标准盒模型与怪异盒模型,具体原因在第2章有提到。
CSS3中提供一个属性用于声明盒模型的类型,它就是box-sizing。
- content-box:标准盒模型(
默认) - border-box:怪异盒模型
它不具备继承性,若全局统一盒模型,那只能使用*声明box-sizing了。建议使用reset.css中的声明方式。
标准盒模型
标准盒模型是W3C标准,由margin + border + padding + content组成。与上述公式一样,节点的width/height只包括content,不包括padding/border。
节点的尺寸计算公式如下。
- 横向:
margin-[left/right]+border-[left/right]+padding-[left/right]+width - 纵向:
margin-[top/bottom]+border-[top/bottom]+padding-[top/bottom]+height
节点的宽高计算公式如下。
- 横向:
width = width - 纵向:
height = height
怪异盒模型
怪异盒模型又称IE盒子模型,是IExplore标准,由margin + content组成。与上述公式不一,节点的width/height包括border、padding和content。
节点的尺寸计算公式如下。
- 横向:
margin-[left/right]+width(包括border-[left/right]与padding-[left/right]) - 纵向:
margin-[top/bottom]+height(包括border-[top/bottom]与padding-[top/bottom])
节点的宽高计算公式如下。
- 横向:
width = border + padding + width - 纵向:
height = border + padding + height
在IExplore中,若HTML文档缺失<!doctype html>声明则会触发怪异盒模型。
两者区别
通过代码演示可能会更清晰,width/height的范围也一目了然,其实两者区别在于width/height包不包括border/padding。把上述公式记清楚,两者区别就迎刃而解了。
.content-box {
box-sizing: content-box;
margin: 100px;
padding: 50px;
border: 10px solid #66f;
width: 80px;
height: 80px;
background-color: #f66;
}
.border-box {
box-sizing: border-box;
margin: 100px;
padding: 50px;
border: 10px solid #66f;
width: 80px;
height: 80px;
background-color: #f66;
}
视觉格式化模型
上述盒模型都是平时了解的概念,若使用display对盒模型稍微加工则会进化为视觉格式化模型。
视觉格式化模型指在视觉媒体中处理与显示文档而使用的计算规则。它是一种CSS机制,由大量CSS规范组成,规定节点在网页中的排版。
块级元素
当节点的display声明为block、list-item、table、flex或grid时,该节点被标记为块级元素。块级元素默认宽度为100%,在垂直方向上按顺序放置,同时参与块格式化上下文。
每个块级元素至少生成一个块级盒或一个块容器盒,块级盒描述它与兄弟节点间的表现方式,块容器盒描述它与子节点间的表现方式。
一个块容器盒只包括其他块级盒或行内盒。可能一段代码中某个块容器盒同时包括块级盒与行内盒的情况,但实质上会产生一种新的匿名块盒解决该问题。
行内元素
当节点的display声明为inline、inline-block、inline-table、inline-flex或inline-grid时,该节点被标记为行内元素。行内元素默认宽度为auto,在水平方向上按顺序放置,同时参与行内格式化上下文。
当块级盒参与行内格式化上下文后会变成行内盒。另外还有一个称为匿名行内盒的概念,匿名行内盒与匿名块级盒的原理类似,都是浏览器自动生成的补充性盒。
以下简单使用一段代码理解匿名行内盒是如何产生的。
<p>我是<span>JowayYoung</span>,我的公众号是<span>IQ前端</span></p>
此时我是与,我的公众号是就会生成一个匿名行内盒,然后与两个<span>一起处于<p>参与行内格式化上下文后的行内盒中并保持水平排列。
两者区别
上述概念可能有些绕口,若从两者区别中理解可能更易消化。
- 互相转换
- 块级元素转换行内元素:
display:inline - 行内元素转换块级元素:
display:block
- 块级元素转换行内元素:
- 占位表现
- 块级元素默认独占一行,默认宽度为父节点的
100%,可声明边距、填充和宽高 - 行内元素默认不独占一行(
一行可多个),默认宽度随内容自动撑开,可声明水平边距或填充,不可声明垂直边距或宽高
- 块级元素默认独占一行,默认宽度为父节点的
- 包括关系
- 块级元素可包括块级元素与行内元素
- 行内元素可包括行内元素,不能包括块级元素
格式化上下文
上述多次提到格式化上下文的字眼,那格式化上下文又是何方神圣?了解格式化上下文,就能更易理解上述内容了。
格式化上下文指决定渲染区域内节点的排版、关系和互相作用的渲染规则。简而言之,网页中有一个<ul>及其多个子节点<li>,格式上下文决定这些<li>如何排版,<li>与<li>间处于何种关系,以及<li>与<li>间如何互相影响。
格式上下文由以下部分组成,其中块格式化上下文与行内格式化上下文最重要。
| 上下文 | 缩写 | 版本 | 声明 |
|---|---|---|---|
| 块格式化上下文 | BFC | 2 | 块级盒子容器 |
| 行内格式化上下文 | IFC | 2 | 行内盒子容器 |
| 弹性格式化上下文 | FFC | 3 | 弹性盒子容器 |
| 格栅格式化上下文 | GFC | 3 | 格栅盒子容器 |
读中文读起来有点拗口,干脆读英文缩写好了,有兴趣的同学自行查阅MDN了解其英文单词
为了防止有些同学对格式化上下文的概念越看越混乱,本章不会过多解说格式化上下文,但我会抽丝剥茧把格式化上下文的概念清晰化,更多的解读可自行查找相关资料深入学习。有时学习点到即止也未尝不是一件好事,过多解读反而达不到想要的效果。
块格式化上下文
BFC是网页中一个独立且隔离的渲染区域,容器中的子节点不会在布局中影响到外面的节点,反之亦然。
以下是我意译W3C标准与平时一些开发经验的总结所得,也结合一些自己对BFC的理解。
规则
- 节点在垂直方向上按顺序排列
- 节点的垂直方向距离由
margin决定,相邻节点的margin会发生重叠,以最大margin为合并值 - 节点的
margin-left/right与父节点的左边/右边相接触,即使处于浮动也如此,除非自行形成BFC BFC是一个隔离且不受外界影响的独立容器BFC不会与同级浮动区域重叠BFC在计算高度时其浮动子节点也参与计算
成因
- 根节点:
html - 非溢出可见节点:
overflow:!visible - 浮动节点:
float:left/right - 绝对定位节点:
position:absolute/fixed - 被定义为块级的非块级节点:
display:inline-block/table-cell/table-caption/flex/inline-flex/grid/inline-grid - 父节点与正常文档流的子节点(非浮动)自动形成
BFC
场景
- 清除浮动
- 已知宽度水平居中
- 防止浮动节点被覆盖
- 防止垂直
margin合并
margin塌陷在排版时稍微不注意就会出现,可用BFC的概念回答了。所谓的塌陷其实是两个BFC的相邻盒或父子盒互相作用时产生的效果,两个盒子会取相邻边最大margin作为相邻边的共用margin。
在此再补充一些margin折叠的计算问题。
- 两个盒子相邻边的
margin都为正值,取最大值 - 两个盒子相邻边的
margin都为负值,取最小值,两者会互相重合 - 两个盒子相邻边的
margin一正一负,取两者相加值,若结果为负,两者会互相重合
行内格式化上下文
IFC的高度由容器中最大高度的子节点的实际高度确定,不受垂直方向的margin/padding的影响。另外,IFC中不能存在块元素,若加入块元素则会产生相应个数的匿名块并互相隔离,即产生相应个数的IFC,每个IFC对外表现为块级元素并垂直排列。
以下是我意译W3C标准与平时一些开发经验的总结所得,也结合一些自己对IFC的理解。
规则
- 节点在水平方向上按顺序排列
- 节点无法声明宽高,其
margin/padding在水平方向有效在垂直方向无效 - 节点在垂直方向上以不同形式对齐
- 节点宽度由包括块与浮动决定,节点高度由行高决定
成因
- 声明
display:inline[-x]形成行内元素 - 声明
line-height - 声明
vertical-align - 声明
font-size
弹性格式化上下文
声明display为flex或inline-flex时,节点会生成一个FFC的独立容器,主要用于响应式布局。
格栅格式化上下文
声明display为grid或inline-grid时,节点会生成一个GFC的独立容器,主要用于响应式布局。
GFC有点像<table>,同为二维表格,但GFC有更丰富的属性控制行列、对齐以及更为精细的渲染语义与控制。不过因为兼容性不是特别好,所以也不会讲述基于GFC的格栅布局了。
文档流
文档流指节点在排版布局时默认使用从左往右从上往下的流式排列方式。窗体从上往下分成一行行且每行根据从左往右的顺序排列节点,其显著特性就是从左往右从上往下。
类型
对于一个标准的文档流,可根据其特性对节点分类。
- HTML级别
- 容器级元素:
<div>、<ul>、<li>等 - 文本级元素:
<a>、<p>、<span>等
- 容器级元素:
- CSS级别
- 块级元素:
<div>、<ul>、<li>等 - 行内元素:
<a>、<p>、<span>等
- 块级元素:
微观现象
即使是标准的文档流,也不排除存在一些小小的缺陷,以下是三种常见缺陷。
- 空白折叠:换行编写行内元素,排版会出现
5px空隙 - 高矮不齐:行内元素统一以底边垂直对齐
- 自动换行:排版若一行无法完成则换行接着排版
解决方案
空白折叠可能是最易出现的文档流微观现象。
<ul>
<li></li>
<li></li>
<li></li>
</ul>
ul {
text-align: center;
}
li {
display: inline-block;
}
此时很多浏览器就出现5px空隙,解决方案也有很多种。
第一种,必须紧密连接节点。
<ul>
<li></li><li></li><li></li>
</ul>
第二种,子节点声明margin-left:-5px。
li {
display: inline-block;
margin-left: -5px;
}
第三种,父节点使用Flex布局。
ul {
display: flex;
justify-content: center;
}
脱流文档流
脱流文档流指节点脱流正常文档流后,在正常文档流中的其他节点将忽略该节点并填补其原先空间。文档一旦脱流,计算其父节点高度时不会将其高度纳入,脱流节点不占据空间,因此声明浮动或定位后会对周围节点布局产生或多或少的影响。
文档流的脱流有两种方式。
- 浮动布局:
float:left/right - 定位布局:
position:absolute/fixed
Float方式
节点声明float脱流时会让其跳出正常文档流,其他节点会忽略该节点并填补其原先空间。该节点的文本内容可不参与脱流效果,却会认同该节点所占据的空间并围绕它布局,这就是文字环绕效果的原理。
一句话概括:节点参与浮动布局后,自身脱流但其文本不脱流。
Position方式
节点声明position脱流时(只有absolute/fixed)会让自身及其文本内容一起跳出正常文档流,其他节点会忽略该节点并填补其原先空间。absolute绝对定位是相对往上遍历第一个声明position:relative/absolute的祖先节点定位,若无此节点则相对<body>定位;fixed固定定位是相对浏览器窗口定位。
一句话概括:节点参与定位布局后,自身及其文本一起脱流。
显隐影响
在正常文档流排版时,经常会声明display:none与visibility:hidden控制节点的隐藏,display:none简称DN,visibility:hidden简称VH。上章提到DN/VH的区别,这次看看节点切入隐藏状态后,会存在何种差别。
- 节点不可见但占据空间,显隐时可过渡:
visibility:hidden - 节点不可见但占据空间,不可点击:
visibility:hidden - 节点不可见不占据空间,可访问DOM:
display:none - 节点不可见但占据空间,可点击:
opacity:0 - 节点不可见不占据空间,可点击:
position:absolute; opacity:0 - 节点不可见但占据空间,不可点击:
position:relative; z-index:-1 - 节点不可见不占据空间,不可点击:
position:absolute; z-index:-1
层叠上下文
层叠上下文指盒模型在三维空间Z轴中的表现行为。每个盒模型存在于一个三维空间中,分别是平面画布的X轴Y轴与表示层叠的Z轴。
在默认情况下,节点在网页中沿着X轴与Y轴平铺,很难察觉它们在Z轴中的层叠关系。节点一旦发生堆叠,最终表现就是节点间互相覆盖。若一个节点包括层叠上下文,那它就拥有绝对的制高点,使用一个成语贴切表示就是鹤立鸡群,最终表现就是离屏幕观察者更近。
声明position/z-index可让节点生成层叠上下文。很多同学可能一直认为z-index只是声明一个节点在Z轴的层叠顺序,值越高离屏幕观察者越近。其实这种认识不全面,还需注意以下情况。
z-index只在声明定位的节点中起效- 节点在
Z轴的层叠顺序根据z-index、层叠上下文和层叠等级共同决定
层叠等级
层叠等级又称层叠级别,指节点在三维空间Z轴中的上下顺序。在同一层叠上下文中,它描述层叠上下文节点在Z轴中的上下顺序;在普通节点中,它描述普通节点在Z轴中的上下顺序。
普通节点的层叠等级优先由其所在的层叠上下文决定,层叠等级的比较只有在当前层叠上下文中才有意义,脱离当前层叠上下文的比较就变得无意义了。
成因
很多同学认为只有声明position/z-index才能让节点生成层叠上下文,其实不仅只有这两个属性,还有一些条件也能让节点生成层叠上下文。
<html>根结点Flex布局中声明z-index不为auto的节点Grid布局中声明z-index不为auto的节点- 声明
position:relative/absolute与z-index不为auto的节点 - 声明
position:fixed/sticky的节点 - 声明
mask/mask-image/mask-border不为none的节点 - 声明
filter不为none的节点 - 声明
mix-blend-mode不为normal的节点 - 声明
opacity不为1的节点 - 声明
clip-path不为none的节点 - 声明
will-change不为initial的节点 - 声明
perspective不为none的节点 - 声明
transform不为none的节点 - 声明
isolation为isolate的节点 - 声明
-webkit-overflow-scrolling为touch的节点
层叠顺序
层叠顺序指节点发生层叠时根据指定顺序规则在Z轴中垂直显示。
脱流节点的层叠顺序
在同一层叠上下文中,节点根据z-index的大小从上到下层叠,若z-index一样则后面的节点层叠等级要大于前面的节点。脱流节点的层叠顺序看z-index的大小。
标准流节点的层叠顺序
标准流节点的层叠顺序稍微有点难记,我也未找到特别的记忆方式,只能死记硬背了。以下是层叠顺序从低到高的排列。
- 层叠上下文的
border/background z-index<0的节点- 标准流内块级非定位的节点
- 浮动非定位的节点
- 标准流内行内非定位的节点
z-index:auto/0的节点z-index>0的节点

2. 块级元素和块级格式化上下文有什么区别啊
3.匿名盒子怎么可以看到呢
4.块容器盒同时包含块级盒与行内盒,有什么问题,为什么要用匿名盒解决
这句话应该怎么理解啊?
开头讲的 横向/纵向/宽高/margin/padding这些,没有个图或者例子参考着看,对初学者不太友好,看起来像是总结。。。可以参考这篇文章一起看
「 CSS级别
块级元素:、、等
行内元素:、、等」
Title
.span1 {
display: inline-block;
background: #abcdef;
}
.span2 {
padding: 10px;
background: #aa0000;
}
.span3 {
height: 100px;
background: #00aa00;
}
.span4 {
margin: 10px;
background: #0000aa;
}
2
3
4
不懂的地方我说了,我确实是基础比较差,但我文章文章看的很仔细,看了三遍,确实看不懂,不知道怎么做。又找了其他相关的文章,才明白文章里一些地方是指什么,要怎么做,仅此而已。
对于浮动,我理解的是,子元素设置 float(会形成一个 BFC),父元素要设置 overflow: hidden(子元素脱离常规流,父子之间不会自动形成BFC,需要在父元素上显示的设置才会形成一个 BFC。此时子元素的高度会参与父元素高度的计算),这时就符合 “每个节点的margin-left/right与父节点的左边/右边相接触”。
如果这样的话,那文章中提到的这句话后半句——除非自行形成BF,指的是什么情况呢?浮动不就会形成 BFC 嘛?那也是符合左边/右边相接触的,那还有哪种情况例外呢?
“当节点的display声明为block、list-item、table、flex或grid时,该节点被标记为块级元素。块级元素默认宽度为100%,在垂直方向上按顺序放置,同时参与块格式化上下文”
这最后一句是不是还有“或弹性/格栅格式化上下文”呀?
absolute 绝对定位 即相对于除了 static 定位的最近祖先盒子相对定位下的文档流进行定位,如果没有则是相对于视口移动,一般会覆盖在其他元素上,正常的文档流不保存元素的位置
fixed 固定定位 通过指定元素相对于视口的位置来指定元素位置,当元素祖先的 transform 属性不是 none 时,相对于视口改为该祖先,一般会覆盖在其他元素上,正常的文档流不保存元素的位置
查看全部 66 条回复