先记住这个答案
标准写法是 max-width 加 margin: 0 auto。块级元素默认宽度是 auto,会铺满父元素;加了 max-width 以后,只有父元素比上限还宽时宽度才被截住,多出来的空间由左右 auto 外边距平分,于是就居中了。窄屏两侧的留白用 padding-inline 做,并把 box-sizing 设成 border-box,让内边距算在上限里面。
max-width限宽,自动边距居中- 块级元素宽度默认就铺满,
width: 100%多余 min-width高于上限时优先min()可合并流体宽与上限
一个能直接用的容器
大部分官网、后台的主体区域都是这个结构:大屏上内容最多 1200px 宽,居中;手机上铺满,两边留 16px。
.container {
box-sizing: border-box; /* 内边距算进 max-width 里 */
max-width: 1200px; /* 只封顶,不固定宽度 */
margin-inline: auto; /* 左右平分剩余空间 = 居中 */
padding-inline: 16px; /* 窄屏时内容不贴边 */
}
/* 等价的一行写法:宽度取两者中较小的那个 */
.container-v2 {
width: min(100% - 32px, 1200px);
margin-inline: auto;
}视口 1440px 时,.container 宽 1200px,左右各空 120px;视口 375px 时,它宽 375px,内容区是 343px。整个过程不需要写一个媒体查询。
min() 那种写法把留白直接从宽度里扣掉,不用 padding,适合内部还要放满宽背景条的场景。两种写法任选一种,团队里统一就行。
width、max-width、min-width 谁说了算
这三个同时出现时,浏览器先算 width,再用 max-width 截上限,最后用 min-width 托下限。所以如果 min-width 比 max-width 还大,最终听 min-width 的。
比如写了 width: 1400px; max-width: 1200px,结果是 1200px,max-width 比 width 优先级高。这也是为什么图片自适应都写 img { max-width: 100%; height: auto; }:图片本身有固有宽度,max-width: 100% 保证它不会撑破父容器,又不会把小图强行拉大。
- 百分比是相对谁的
max-width: 80%里的百分比相对的是包含块的宽度,一般就是父元素的内容区。父元素宽度如果反过来取决于子元素,比如父元素是浮动或者inline-block,就成了循环依赖:浏览器算父元素宽度时先不管这个百分比上限,父元素宽度定下来以后再按它截子元素。结果往往是父元素被长内容撑宽,子元素的 80% 看上去没起作用。遇到这种情况,先看父元素的宽度是不是确定的。
在 flex 和绝对定位里要多注意一步
限宽容器放在普通文档流里最省心。一旦它成了 flex 子项或者绝对定位元素,width: auto 的含义就变了。
flex 子项默认宽度是内容宽度,不会自动铺满,这时只写 max-width 容器会缩成内容那么宽。要么给它 width: 100%,要么让父元素 flex-direction: column 且子项 align-self: stretch。绝对定位元素同理,auto 宽度是收缩到内容,需要写 left: 0; right: 0 或明确的宽度,margin: 0 auto 才能居中。
容易答错的地方
- 以为要写
width: 100%才能铺满 - 普通块级元素的
auto宽度本来就铺满父元素,而且会自动扣掉自己的外边距、边框和内边距。写成width: 100%反而有风险:在默认content-box下再加padding,元素就比父元素宽,出现横向滚动条。 - 用固定
width加媒体查询实现响应式 width: 1200px配一堆断点改宽度,窗口宽度只要落在两个断点之间就会被截断或者留出大块空白。max-width天然是连续变化的,断点只用来改布局,不用来改容器宽度。- 居中不生效就怀疑
margin: auto margin: 0 auto只对处在普通流里、宽度又被width或max-width限制得比父元素窄的块级元素起作用。行内元素、auto宽度的浮动元素用它都没反应,这时要检查的是元素的display,而不是换个居中方案。
面试官还会怎么问?
为什么推荐 margin-inline 和 max-inline-size 这类逻辑属性?
它们按书写方向而不是物理方向生效。页面切换成阿拉伯语这类从右到左的语言,或者改成竖排时,margin-inline 依然表示「行方向两侧」,不用再写一套覆盖样式。只做中文横排站点时,两种写法效果一样。
容器里有一个背景条想铺满整屏,但文字还要对齐容器,怎么写?
外层放一个不限宽的块负责背景,里面再套一层 .container 负责限宽。另一种做法是在限宽容器里用 margin-inline: calc(50% - 50vw) 把背景条拉满视口,但 100vw 包含滚动条宽度,有滚动条的系统上会多出一点横向溢出,所以一般优先用嵌套结构。
容器查询和这个限宽容器有什么关系?
没有冲突。限宽容器决定内容区有多宽,容器查询(@container)让里面的组件根据这个宽度调整自己的布局。给 .container 加上 container-type: inline-size,里面的卡片就能按容器宽度而不是视口宽度切换排版。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。