CSS 与布局 / textarea 样式化 · 一份配方的七条声明 / box-sizing 与 reset 的冲突 待审核 3 / 8
box-sizing: unset

box-sizing 与 reset 的冲突

配方的第一条带编号的声明是 box-sizing: unset,注释写着「还原成未指定的状态」。这句话需要两处澄清:还原掉的是谁写的声明,以及为什么要的是 content-box 而不是更常用的 border-box

1 · unset 撤销的是 author reset

box-sizing 不是继承属性,unset 对它等同于 initial,即 content-box。而 content-box 本就是 UA stylesheet 未改动的取值——不受任何作者样式影响的 <textarea>box-sizing 读回的正是 content-box(实测 Chrome 152,核对于 2026-09)。既然 UA 没动它,这条声明撤销的只能是 author origin 里的某条声明。

那条声明来自项目自己的 reset。近十年的主流写法是 *, *::before, *::after { box-sizing: border-box },Tailwind 的 preflight、几乎所有 CSS 框架都包含它。textarea 这个类型选择器的 specificity 是 (0,0,1)(0, 0, 1)*(0,0,0)(0, 0, 0),所以配方里的声明胜出,计算值回到 content-box

警示 · 这条声明的效力建立在「reset 用通配选择器」之上。若项目的 reset 恰好写成 textarea { box-sizing: border-box },两条声明 specificity 相同,胜负改由源码顺序决定——reset 排在配方之后就赢。此时该换成 revert-layer 或把配方放进更靠后的 cascade layer,而不是继续加 !important

2 · 为什么要 content-box

理由不在这条声明里,在后面的 min-block-size: calc(var(--textarea-rows, 5) * 1lh)。这个值要表达的是「至少五行文字」,而 1lh 度量的是一行文字本身,不含 padding 与 border。

两种盒模型下这个值的落点完全不同。以 16px 字号、line-height: 1.51lh = 24px)、padding: 1em、1px 边框为例:

  • content-boxmin-block-size 约束内容区。内容区 120px 恰好容下五行,边框盒随之长到 120+32+2=154{120} + 32 + 2 = 154px
  • border-boxmin-block-size 约束边框盒。边框盒钉死在 120px,内容区只剩 12034=86{120} - 34 = 86px,合 3.58 行

差的这一行半不是舍入误差,是把「五行」这个意图交给了错误的盒。padding 越大差得越多:padding: 1em 已经吃掉将近两行。

图 2-1 · 同一条 min-block-size 在两种盒模型下的落点。背景行带按 1lh 绘制,可调行数与 padding 观察 border-box 一侧的可见行数如何被 padding 吃掉。

3 · 另一条路与它的代价

坚持 border-box 也能得到五行,代价是把 padding 与 border 写进算式:min-block-size: calc(5lh + 2em + 2px)。这份算式与 padding: 1emborder-width: 1px 之间存在一条不被任何工具检查的隐式约定——改了 padding 而忘了改算式,控件会静悄悄地少半行,没有报错、没有警告,只有一个「看起来有点矮」的输入框。

配方选择的是另一头:让盒模型迁就单位,5lh 就是五行。代价是这个元素与项目其余部分的盒模型不一致,读代码的人看到 box-sizing: unset 需要知道它为何在此。这份注释因此不能省。