必须同时声明 *, *::before, *::after { box-sizing: border-box; },缺一不可,否则伪元素继承 content-box 导致尺寸错乱、定位偏移;需置于 css 最顶部,避免被第三方库覆盖,并对特定元素如 input[type="search"] 等手动回退为 content-box。

必须用 *、*::before、*::after 三者联合声明,缺一不可;只写 * 会漏掉伪元素,导致图标、tooltip 箭头、装饰边框等尺寸错乱。
为什么 * { box-sizing: border-box; } 不够用
伪元素(如 ::before 和 ::after)不继承父级 box-sizing,浏览器默认仍是 content-box。你用它们画个下拉箭头或加个阴影遮罩,实际宽度就悄悄多出 padding + border,轻则换行,重则定位偏移。
- DevTools 的 “Computed” 面板里,选中任意伪元素,看
box-sizing值是不是border-box—— 不是,就是没生效 - 某些 UI 库(比如 Element Plus 的
el-tooltip)内部生成的伪元素,不受单个*规则影响 - Safari ≤12.1 和部分 Android WebView 中,
*::before可能根本匹配不到,必须显式写出
推荐写法:放在 CSS 最顶部,顺序不能错
这条规则必须出现在所有自定义样式、@import、第三方库样式之前,否则会被覆盖。尤其注意 Ant Design、MUI 等库自带重置,后加载就会把你冲掉。
- 正确写法:
*, *::before, *::after { box-sizing: border-box; } - 更稳妥的替代方案(兼容老 Safari):
html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; } - 别塞进 Vue 的
<style scoped></style>里——作用域隔离,伪元素照样跑出去用默认值
哪些地方要手动切回 content-box
不是所有东西都适合 border-box。强行统一反而破坏原生行为,尤其在 WebKit 内核下:
-
<input type="search">的清除按钮位置偏移 -
<textarea></textarea>拉伸后最后一行文字被截断 -
<canvas></canvas>或<svg></svg>容器要求 width 严格等于绘图区域(比如width: 500px就得是内容区宽) - 某些图表库(如 ECharts)的容器依赖原始 content 尺寸做缩放计算
回退方式很简单:
.echarts-container,
input[type="search"],
textarea {
box-sizing: content-box;
}
和 Flex/Grid 混用时容易忽略的点
box-sizing 不改变 Flex/Grid 的分配逻辑,但会影响 flex-basis 和 min-width 的计算基准。两个 width: 50% 的子项右边多出 1–2px 缝隙?大概率是其中一个用了 content-box,padding 没被算进宽度里。
- Flex 项设了
flex: 1后,width被忽略,但flex-basis仍受box-sizing影响 - Grid 里
grid-template-columns: 1fr 200px的200px是轨道宽,但单元格内元素若为content-box,仍可能撑破轨道 - 真正关键的是“一致性”:父容器和所有子项必须同用一种盒模型,否则布局信号就乱了
最麻烦的不是写错,而是写对了却没生效——检查伪元素的 computed box-sizing,确认是否真被覆盖;再盯一眼第三方库样式加载顺序,别让自己的规则躺在最后面吃灰。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











