先记住这个答案
总宽度是 250px。默认的 box-sizing 是 content-box,这时 width 指的只是内容区的宽度。padding 和 border 画在内容区外面,要另外加:左右 padding 共 40px,左右 border 共 10px,200 + 40 + 10 = 250。margin 不算在里面,它是元素外面的留白。如果改成 box-sizing: border-box,width: 200px 就是最终宽度,内容区会被压缩成 150px。
content-box下width只算内容区- 内容盒外还要加边框和内边距
margin不算进元素宽度,但会占布局空间border-box下内容区会被挤小
两种 box-sizing 的算法对比
同样的三行声明,只差一个 box-sizing,结果差了 50px。
.a {
width: 200px;
padding: 20px;
border: 5px solid #333;
/* 默认 box-sizing: content-box */
/* 内容区 200,总宽 200 + 20*2 + 5*2 = 250px */
}
.b {
width: 200px;
padding: 20px;
border: 5px solid #333;
box-sizing: border-box;
/* 总宽固定 200,内容区 = 200 - 40 - 10 = 150px */
}打开 DevTools 的 Computed 面板,下面那张盒模型图会分层标出每一层的数值,.a 中间的内容区是 200,.b 中间是 150。
可以把 content-box 想成「先定照片尺寸,再往外加相框」,相框越宽整体越大;border-box 是「先定整体尺寸,相框往里占」,照片被挤小。前者是 CSS 最初的规定,后者更符合设计稿的直觉,所以现在几乎所有项目都会全局改成 border-box。
- 项目里的通用写法
- 一般在全局样式里写
*, *::before, *::after { box-sizing: border-box; }。这样设计稿标多宽就写多宽,后面再调padding也不会把布局撑破。Tailwind、Bootstrap 的基础样式里都有这一条。
在 JS 里量出来是多少
面试官经常顺着问「JS 读到的宽度是多少」,这时要分清每个属性量的是哪一层。
- 各个宽度属性对应哪一层
- 对上面的
.a,offsetWidth是250,它量的是border外沿,包含内容、padding、border。clientWidth是240,只含内容和padding,不含border,有滚动条时还要减去滚动条宽度。getBoundingClientRect().width在没有transform时也是250,但它返回的是变换后的实际渲染尺寸,而且可以是小数。getComputedStyle(el).width返回的是'200px',也就是 CSS 里那个width的计算值。
容易答错的地方
- 把 margin 也加进去
- 有人会答「再加上
margin」。margin是元素之外的空白,决定它和相邻元素的距离,不属于元素自己的宽度。只是在排版时,它占用的横向空间是250px加左右margin。 - 以为 padding: 20px 只加一边
padding: 20px是上下左右四个方向都是20px,宽度要加两次,border同理。只加一次会算成225px。- 以为 border-box 下内容区不会变小
border-box保证的是总宽度不变,代价是内容区变小。如果padding和border加起来超过了width,内容区只会缩到 0,总宽度会被撑到padding加border的和,不会出现负数。
面试官还会怎么问?
怪异模式下的盒模型是怎么回事?
页面没有写 <!DOCTYPE html> 时,浏览器进入怪异模式,老 IE 的盒模型就是 width 包含 padding 和 border,效果和 border-box 一样。box-sizing: border-box 可以理解成把这种算法标准化了。所以页面第一行一定要写 DOCTYPE。
width: 100% 再加 padding 为什么会出现横向滚动条?
content-box 下 100% 只是内容区等于父元素宽度,再加上左右 padding 和 border,总宽就超过父元素了。改成 border-box,或者干脆不写 width,让块级元素自动填满父元素,就不会溢出。
box-sizing 会影响 min-width 和 max-width 吗?
会。min-width、max-width、min-height、max-height 都按 box-sizing 的规则来解释。border-box 下 max-width: 300px 限制的是包含 padding 和 border 的总宽度。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。