盒模型
在CSS规范中这样描述盒模型:CSS盒模型描述为文档树中的元素生成的矩形框,并根据视觉格式化模型进行布局
包含块
包含块贯穿于整个布局模型,包括:常规流、浮动和绝对定位
所有的布局、尺寸计算都是基于包含块的,即包含块就是元素的“布局上下文”
在格式化文档中,内容都是由一个个长方形的块组成,块是抽象的概念,块是由元素生成,元素是具体存在的
包含块就是这些块中的一部分,包含块也是相对的,是相对于子元素来说的
盒模型
一个完整的盒模型指的是块级盒子
盒子也分为宿主盒子、具名盒子和匿名盒子(继承包含块的部分属性,无法被选择器选中)
盒子由:内容区域、内边距、边框和外边距四部分组成
视觉格式化模型
CSS 的视觉格式化模型用来描述用户代理(通常指浏览器),如何获取文档树,以及如何处理和显示文档树,是一系列的计算规则
视觉格式化模型根据盒模型,将文档树中的元素根据其显示属性(display)转换成一个个对应类型的盒子,最终这些盒子参与到块级格式化的创建
以块级元素为例:元素的 display 属性决定了该元素为块级元素,然后生成块级盒子,块级盒子参与到块级格式化的创建,最终渲染出来
盒子的布局受以下因素影响:
- 盒子的尺寸和类型;
- 定位方案(包括常规流、浮动和绝对定位);
- 文档树中元素之间的关系;
- 其他外部因素(如:视口的大小、图像大小等)。
水平格式化
水平格式化的一个简单而且重要的规则:常规流中的块级元素框的水平部分的总和等于其包含块的宽度(一般为父盒子)
水平格式化中有七个属性:width、padding-left、padding-right、border-left、border-right、margin-left、margin-right
其中 width、margin-left、margin-right 三个属性可以设置 auto 值
在计算中,通过这三个属性的 auto 值可以弥补实际值与所需总和的差距
在从左向右(direction: ltr)阅读的语言中优先 计算 width > margin-left > margin-right
如下例01中:当 width 和 margin-right 固定,margin-left 无值时,margin-left 被默认为 0,margin-right 被重置为 auto(即 200px)
如下例02中:当 width 为 auto 或者无值,margin-rigth 固定,margin-left 无值时,width 设置为 auto 计算剩余的空间 即 250px
如下例03中:包含块的 width 为 300px,子元素的 width 为 100px, 左外边距为 auto,右外边距为 50px,其余的都是 0,用户代理将左外边距的 auto 计算为 150px = 300px - 100px - 50px
过渡受限
当这三个属性都设置为 非 auto 的固定值时,并且水平总和不等于包含块的宽度时,就是属性过渡受限
- 当属性过渡受限时,在从左向右阅读的语言中,会把
margin-right强制重置为auto
如下例中:子元素的width为100px,margin-left和margin-right均为50px,最终在水平格式化中用户代理会把margin-right强制重置为auto(即150px),以满足水平部分的总和等于包含块的宽度
- 替换元素的
width为auto或无值时 会使用替换元素的原始值作为width的计算值
- 水平格式化中外边距永远不会合并
- 如果给水平属性设置百分数,则都是基于其包含块的宽度值计算的
负外边距
当外边距为负值时依然适用:水平部分的总和等于包含块的宽度
如下例中:包含块的宽度为 300px,mergin-right: -20px,此时 width 和 margin-left 均未知,根据计算优先原则 先计算 width 的值,margin-left 被默认为 0
最后等式为:300px = width - 20px; 即 width = 320px
为什么 margin: 0 auto 可以使盒子居中?margin: 0 auto 将其属性分解:
0其实在居中中没起作用auto即margin-left: auto; margin-right: auto;
还有一个重要的前提:width 的值为一个固定值
在水平部分的总和等于包含块的宽度的规则下,width 的值为固定值,margin-left 和 margin-right 为 auto 则会平分剩余的空间,即实现了盒子的居中
水平外边距同样适用于行内元素
垂直格式化
垂直格式化中的盒子的高度由其内容决定,包含块的高度由其内部元素决定
垂直格式化中有七个属性:height、padding-top、padding-bottom、border-top、border-bottom、margin-top、margin-bottom
其中 height、margin-top、margin-bottom 三个属性可以设置 auto 值
在计算中,通过这三个属性的 auto 值可以弥补实际值与所需总和的差距
计算优先级 height > margin-top > margin-bottom
块元素的 margin-top 和 margin-bottom 设置为 auto 时,用户代理会自动将其计算为 0
百分数高度
给高度设置百分数是基于包含块的高度计算的,如果没有给包含块显式的声明高度则百分数的高度会被强制重置为 auto
合并垂直外边距
目前还没找到一篇关于W3C工作组为什么会定义这个规则???
- 垂直格式化另一个比较重要的一点:垂直相邻外边距的合并
边框和内边距会阻止垂直外边距合并
负外边距
盒子上移
影响垂直外边距的合并
同号取大(绝对值最大),异号求和
垂直格式化中的内边距、外边距的百分数基于包含块的宽度计算
基于宽度的等比缩放盒子
垂直格式化中的内边距、外边距的百分数为什么是基于包含块的宽度而不是高度计算???
下面的解释摘自《CSS 权威指南 第三版》221页
正常流中的大多数元素都会足够高以包含其后代元素(包括其外边距)。 如果一个元素的上下外边距是父元素 height 的一个百分数,就可能导致一个无限循环, 父元素的 height 会增加,以适应后代元素上下外边距的增加,而相应的,上下外边距又必须增加,以适应新的父元素 height,如此继续
行内格式化
在行内格式化中,要比块级格式化复杂的多,其中《CSS 权威指南 第三版》186页讲的也比较详细
行内水平格式化
见上面 水平外边距同样适用于行内元素
行内垂直格式化
- 第1个为对照,所以的字体大小继承了body的初始化大小
14px - 第2个说明
margin-top、margin-bottom会被忽略 - 第3个说明
padding同样不会影响包含块的高度,即不影响行框的高度 - 第3、4:非替换元素的内边距、边框和外边距对行内元素或其生成的框没有垂直效果,即不会影响行内框的高度,同样也不会影响行框的高度
- 第4个说明
line-height会影响包含块的高度,line-height决定了行内框的高度,进而影响行框的高度 - 5、6、7 对照
包含块的高度受本身字体大小的影响原因是:字体决定了em框,进而影响了行内框和行框 - 7、8 基线对齐
导致行内元素在包含块中上下产生了空隙原因是:line-height决定了行内框的高度,影响了行框的高度(行框包含了该行中出现的最高点和最低点),基线对齐只是影响元素的对齐方式,进而使行内框的垂直位置发生改变
参考文档
- https://www.w3.org/TR/2011/REC-CSS2-20110607/box.html#img-boxdim
- https://developer.mozilla.org/en-US/docs/Web/CSS/Visual_formatting_model
- https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Visual_formatting_model
- https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Box_Model
- https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/The_box_model
