必须将html和body设为min-height: 100vh并清除margin,body还需display: flex和flex-direction: column;main需flex: 1(非flex-shrink-0);footer须为body直接子元素且无height/position;移动端需注意100vh动态变化问题。

body 必须设为 flex 容器且 min-height: 100vh
Bootstrap 4 默认不给 body 设 display: flex,所以直接加 mt-auto 或 flex-fill 没用。必须手动补全基础布局约束:html 和 body 都要清除默认 margin,并设 min-height: 100vh(不是 height: 100%,后者在嵌套场景下易失效);body 还得显式声明 display: flex 和 flex-direction: column。
常见错误是只给 body 加 class="d-flex flex-column" 却漏了 min-vh-100(Bootstrap 4 中对应 min-height: 100vh 的工具类),结果内容少时 footer 仍浮在半空。
main 必须用 flex-fill 或等效 flex: 1
main(或你用来包裹主体内容的容器)必须参与 flex 分配,否则 footer 没有“剩余空间”可沉底。Bootstrap 4 没有 flex-fill 类(那是 Bootstrap 5 才加的),得手写 flex: 1 或用 flex-grow: 1。
- 别用
flex-shrink-0—— 它会阻止 main 收缩,导致内容超长时页面整体溢出 - 别给
main设固定height或min-height,会破坏响应式 - 如果不用
<main></main>标签,就给实际的内容容器(比如.content)加style="flex: 1"
footer 必须是 body 的直接子元素且不设 height/position
Bootstrap 4 的 mt-auto 依赖 flex 推动,前提是 footer 是 flex 容器(即 body)的**直接子元素**。如果它被包在 .container 或 .row 里,mt-auto 就只作用于那个父容器内部,无法推到视口底。
立即学习“前端免费学习笔记(深入)”;
同时必须避免:
- 给
footer加position: absolute或fixed—— 会脱离 flex 流,且遮挡内容 - 设
height后再加mt-auto—— Safari 旧版本会误算剩余空间,导致main高度塌缩 - 设
flex-shrink: 0—— 多余,mt-auto已足够保证它不被压缩
移动端键盘弹出或地址栏缩放会导致 100vh 失效
min-height: 100vh 在 iOS Safari 和部分 Android 浏览器中,遇到软键盘弹出或地址栏自动隐藏时,vh 值会动态变化,造成 footer 上浮或页面留白。这不是 CSS 写错了,而是视口单位本身的局限。
临时缓解方式:
- 用
min-height: 100dvh替代(仅支持 Chrome 105+/Safari 16.4+,2026 年已较稳妥,但需降级回退) - 监听
resize事件,用 JS 动态重设body.style.minHeight(慎用,可能触发重排) - 对关键页面(如登录页)改用
height: 100svh+overflow: hidden强制锁定
真正难处理的是异步加载内容后高度突变——flex 布局不会自动 reflow,得靠 main 内容渲染完成后再手动触发一次 body 的重绘(例如改个 class 名再切回来)。


















