先记住这个答案
常规流里的块级元素,width 默认就是 auto。auto 的算法是先拿父容器的内容宽度,扣掉元素自己左右的 margin、border、padding,剩下的给内容,所以整个盒子连同外边距刚好填满父容器。width: 100% 是另一回事,它把内容宽度直接设成父容器的内容宽度,内边距、边框、外边距再往外加,只要其中一项不为 0 就会撑破父容器。box-sizing: border-box 能让 100% 把内边距和边框算进去,但外边距还是会溢出。
auto让外边距盒刚好填满父容器100%只管内容宽度,加上padding就溢出border-box不包含外边距- 块级元素默认就是
auto,多数时候不用写100%
同一个父容器里的对比
父容器宽 400px,两个子元素都带 20px 内边距和 10px 外边距。
auto 和 100% 放在一起看HTML<style>
.parent { width: 400px; }
.child { padding: 0 20px; margin: 0 10px; border: 1px solid; }
.a { width: auto; } /* 内容宽 400-10*2-1*2-20*2=338px,整体刚好 400px */
.b { width: 100%; } /* 内容宽 400px,整体 400+40+2+20=462px,溢出 62px */
</style>
<div class="parent">
<div class="child a">width: auto</div>
<div class="child b">width: 100%</div>
</div>.a 的内容宽度是算出来的,浏览器保证 margin + border + padding + width 正好等于父容器宽度。.b 的 width 被写死成 400px,左右内边距 40px、边框 2px、外边距 20px 都只能往外加,右边伸出父容器 62px。
box-sizing: border-box 能解决多少
很多项目全局写了 *, *::before, *::after { box-sizing: border-box; }。这时 width 指的是边框盒的宽度,内边距和边框算在里面。上面的 .b 内容宽变成 400 - 40 - 2 = 358px,边框盒正好 400px。
- 外边距还是会溢出
border-box不管margin。.b左右各10px外边距还在外面,整体仍然是420px,右边伸出20px。这就是「明明设了border-box,加个margin又出滚动条」的原因。这种情况要么去掉width: 100%回到auto,要么用calc(100% - 20px)手动扣掉。
什么时候 auto 不再填满
auto 填满父容器只是常规流块级元素的规则。换个布局环境,auto 的含义就变了。
元素浮动、绝对定位或者设成 inline-block 时,auto 变成收缩适应,也就是按内容多宽就多宽,最多不超过可用空间。这时想让它填满,就真的需要写 width: 100%,或者给绝对定位元素写 left: 0; right: 0。
在 Flex 容器里,子项的 width: auto 也是按内容算的,填满要靠 flex: 1 或者父容器 flex-direction: column 时的默认拉伸。
容易答错的地方
- 以为块级元素要写
width: 100%才能占满 - 块级元素默认
auto就是占满,写100%反而多了溢出的风险。很多撑破布局的问题,删掉这一行就好了。 - 以为
border-box之后100%永远安全 border-box只把内边距和边框收进来,外边距还在外面。100%加外边距照样溢出。- 以为百分比永远相对父元素
width的百分比相对的是包含块的宽度。绝对定位元素的包含块是最近的定位祖先的内边距盒,不一定是直接父元素,100%可能比父元素宽得多。
面试官还会怎么问?
height: auto 和 height: 100% 也是这个关系吗?
不一样。块级元素的 height: auto 是由内容撑开,不是填满父容器。height: 100% 要求父元素有明确的高度,父元素高度也是 auto 时,百分比高度会被当成 auto,这也是「height: 100% 不生效」的常见原因。
为什么 margin: 0 auto 能居中?
块级元素有明确 width 时,左右 margin 都写 auto,浏览器会把剩余空间平分给两边,于是元素水平居中。如果 width 也是 auto,剩余空间先给宽度,外边距的 auto 就算成 0,看不出居中效果。
width: 100% 和 width: stretch 有什么区别?
stretch 是新的关键字,意思是让外边距盒填满包含块,效果接近常规流里块级元素的 auto,可以用在浮动、绝对定位这些 auto 会收缩的场景。部分浏览器还需要加前缀,比如 -webkit-fill-available,用之前要确认兼容性。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。