必须同时满足三个高度前提:html设height:100%、body设min-height:100vh且margin:0、grid-template-rows写全auto 1fr auto三段,且header/main/footer为body直系子元素,否则页脚会悬浮。

直接用 grid-template-rows: auto 1fr auto 就能实现,但必须同时满足三个高度前提,漏一个页脚就浮在半空。
body 必须设 min-height: 100vh 且 html 要兜底
Grid 的 1fr 不会凭空算出“剩余空间”——它只按父容器当前高度分配。如果 body 高度由内容撑开(比如只有几行文字),那 1fr 分到的就只是这几行的高度,页脚自然上浮。
-
html上加height: 100%或min-height: 100%,防止某些 Safari 对百分比解析异常 -
body必须设margin: 0(清除默认外边距)和min-height: 100vh(推荐用100vh,比100%更可靠) - 生产环境可考虑
min-height: 100dvh,避免 iOS 地址栏收放导致的跳动(Chrome 105+/Safari 16.4+ 支持)
grid-template-rows 必须写全三段,不能省略 header 行
很多人写成 grid-template-rows: 1fr auto,结果页脚还是不贴底——因为这定义的是“两行”,而页面结构实际是 <header></header>、<main></main>、<footer></footer> 三个直系子元素,Grid 会把 header 塞进第一行、main 塞进第二行、footer 挤到第三行(无模板约束),导致 1fr 失效。
- 正确写法是
grid-template-rows: auto 1fr auto:第一行给header(内容高度),第二行给main(吃掉所有剩余空间),第三行给footer(内容高度) - 如果页脚高度固定(如
60px),可写成auto 1fr 60px,更精确,避免字体渲染微变带来的浮动 -
footer内不能设height: 100%或min-height,否则干扰auto行的自然计算
header/main/footer 必须是 body 的直接子元素
Grid 行高计算依赖结构与模板严格对齐。一旦把 main 或 footer 套进 <div class="container"> 里,它们就不再是 <code>body 的直系子元素,grid-row 自动分配就会断链,1fr 无法作用到真实内容块上。
- HTML 结构必须扁平:
<header>...</header><main>...</main><footer>...</footer> - 不要给
footer加position: absolute或position: fixed,它必须参与文档流,否则 Grid 容器完全无法约束它 - 检查是否有祖先元素设置了
align-items、justify-content等属性,可能意外覆盖 Grid 的默认对齐行为
页脚内容变多时怎么不撑破布局
当页脚里加了多行链接、图标或响应式文字,它自身高度变大,auto 行会跟着撑高,导致主内容区被压缩甚至消失——这不是 Grid 错,而是没控制好页脚尺寸。
- 给
footer加max-height和overflow-y: auto,让它内部滚动,不外溢 - 避免对
footer设height或min-height;若真要固定高度,就改用grid-template-rows: auto 1fr 60px,放弃自适应 - 如果
main区域内容过多,想让它内部滚动而不是拉长整页,给它加overflow-y: auto和min-height: 0(防 Grid 子项默认最小尺寸干扰)
真正容易被忽略的是:1fr 不是魔法单位,它背后依赖一整条高度传递链:从 html → body → Grid 容器,任何一环没设高或被重置,它就失效。别只盯着 Grid 本身,往上查两层样式和结构。











