盒模型概念
CSS 盒模型由四部分组成:margin、border、padding、content
每一种边界所包裹的区域对应一种 box。例如 content edge 所包裹的区域就成为 content-box,另外三种分别是:padding-box、border-box、margin-box。这四种 box 在位置大小上依次是包含关系
盒模型的应用
1. 改变盒子的大小
属性 box-sizing 目前支持两种盒模型:content-box(默认)、border-box。(max-、min-)width、(max-、min-)height 根据 box-sizing 的取值分别对应上图相应 edge 所包裹的地方。
2. 改变背景图像(background-image)绘制区域
属性 background-origin 规定 background-position 相对于什么位置来定位,它的取值有三种:content-box、padding-box、border-box。但是背景颜色不受此影响,总是从 boder 开始渲染。
3. 改变背景裁剪区域
属性 background-clip 的取值与 background-rogin 一样,表示背景裁剪区域范围
盒模型外边距
1. 外边距可以是负数
在 CSS 盒模型中,margin 比较复杂,其他三种属性只能大于等于 0 的数值,而 margin 可以是负数。正数表示推开其他盒子,那么负数就是拉拢。
2. 百分比取值
无论是 margin-left 还是 margin-top,其百分比数值是根据父盒子的逻辑宽度计算的,这里宽度不一定是屏幕宽度,与 writing-mode 有关系。如果是水平书写,宽度就是物理上的宽度;如果是垂直书写方式,宽度就是高度。
3. 垂直方向合并
垂直相邻的两个 margin 数值符号相同,合并后的外边距取绝对值较大的数,并带上符号。符号不同,则合并后的外边距是两数相加的结果。
两个垂直相邻外边距发生合并,必须满足以下几个条件:
- 正常文档流中处于同一个块格式化上下文的块级盒子
- 中间没有其他东西遮挡,比如:行内盒子、清除浮动、padding、border
- 且满足以下任意一个条件:
- 父盒子与正常流中第一个子盒子的 top margin
- 正常流中相邻的两个块级盒子的 bottom margin 和 top margin
- 正常流中最后一个子盒子与父盒子的 bottom margin,且父盒子是自动计算高度
- 同一个块盒子只有top margin 和 bottom margin,高度为 0
有两种例外是不会发生外边距合并的:
- 根元素的外边距
- 清除浮动的元素,其自身上下外边距发生合并后,不会再与父盒子的 bottom margin 发生合并(外边距是可以多重合并的)
4. 外边距合并示例
4.1 最常见的上下合并
* {
margin: 0;
padding: 0;
}
html {
background-color: rgb(200, 228, 146);
}
div {
height: 100px;
width: 400px;
}
#first {
background-color: red;
margin-bottom: 20px;
}
#second {
background-color: blue;
margin-top: 20px;
}
<body>
<div id="first"></div>
<div id="second"></div>
</body>
上下两个
div 的 maring-bottom 和 margin-top 都是 20px,两个数相加是 40px,而实际渲染出来的只有 20px。
4.2 父与子的 margin-top 合并
#parent {
margin-top: 10px;
height: 200px;
}
#first-child {
background-color: red;
margin-top: 20px;
height: 150px;
}
<body>
<div id="parent">
<div id="first-child"></div>
</div>
</body>
从上面的截图可以看出,可以发现 .first-child 元素设置的 margin-top 直接使 .parent 与顶部拉开了 20px 的距离(但是没有在父与子元素之间撑开),这个距离是两个 div margin-top 合并后的值。以前经常有开发人员遇到这样的情况,明明没有给上边框设置 margin-top,却产生了一小片空白。
4.3 自身上下外边距合并
图中
div 高度为 0,它上下外边距会发生了合并,两个 p 元素之间只隔了 20px。
4.4 最后一个子元素与父元素 bottom margin 合并情况
第一种:最后一个子元素与父元素 bottom margin 合并
* {
margin: 0;
padding: 0;
}
html {
background-color: rgb(200, 228, 146);
}
.parent {
margin-bottom: 10px;
background-color: red;
}
.parent > :last-child {
margin-bottom: 40px;
}
<div class="parent">
<p>假装有内容</p>
<p>假装有内容</p>
<p>假装有内容</p>
<p>假装有内容</p>
<div>我离木头人的距离是40px</div>
</div>
<p>木头人</p>
将【木头人】往下推了40px
第二种:最后一个子元素自身上下外边距合并,再与父元素 bottom margin 合并
.parent {
margin-bottom: 10px;
background-color: red;
}
.parent > :last-child {
margin-top: 40px;
margin-bottom: 40px;
}
<div class="parent">
<p>假装有内容</p>
<p>假装有内容</p>
<p>假装有内容</p>
<p>假装有内容</p>
<div></div>
</div>
<p>木头人</p>
同样将【木头人】往下推了40px,但没有在父元素底部内撑开。
第三种: 上下外边距合并(没有 border、padding、content),并且有清除浮动,则合并后外边距不再与父元素 margin-bottom 不合并
* {
margin: 0;
padding: 0;
}
html {
background-color: rgb(200, 228, 146);
}
.parent {
margin-bottom: 10px;
background-color: red;
}
.parent > :last-child {
margin-bottom: 40px;
clear: left;
}
<body>
<div class="parent">
<p>假装有内容</p>
<p>假装有内容</p>
<p>假装有内容</p>
<p style="float:left">下面的div外边距没有和父元素合并</p>
<div></div>
</div>
<p>木头人</p>
</body>
父元素底部被撑开了 40px,并且父元素还推开了【木头人】10px,说明父元素的下外边距没有合并
总结
CSS 盒模型中垂直方向外边距合并情况较为复杂,发生合并有两个重要条件,一是相同的块格式化上下文,二是元素在正常文档流中。行内盒子垂直方向外边距没有效果,并且width、height 设置也无效。