关键在于用 viewport 元标签、重置默认样式、优先使用 100dvh 并降级、结合 JS 动态补偿,才能让 vw/vh 真正贴合移动端可视区域。

用 vw 和 vh 构建移动端全屏视觉,关键不是“写上 100vw/100vh 就完事”,而是让元素真正贴合用户当前看到的屏幕区域——尤其要应对 iOS Safari 地址栏收起、滚动条占位、缩放变化等真实场景。
必须加 viewport 元标签
没有它,所有 vw/vh 都不可信。移动端浏览器会把包含地址栏的“布局视口”当基准,导致高度算小、宽度溢出。
-
标准写法:
<meta name="viewport" content="width=device-width, initial-scale=1.0"> - 若产品允许缩放,至少保留
initial-scale=1.0;如需强控制(如大屏展示),可加maximum-scale=1.0, user-scalable=no - 漏掉这行,后面所有 CSS 调整大概率失效
清空默认样式 + 统一盒模型
浏览器给 body 默认加了 8px margin,box-sizing 默认是 content-box,这两点会让“100vh”实际少掉空间或意外溢出。
- 强制重置根级尺寸:
html, body { margin: 0; padding: 0; height: 100%; } - 全局启用边框盒模型:
* { box-sizing: border-box; },避免 padding/border 撑破容器 - 目标元素不要只写
height: 100vh,而应继承自已设好高度的父容器
优先用 100dvh,降级到 100vh
dvh(dynamic viewport height)是现代解法:iOS Safari 16.4+、Chrome 105+ 支持,能实时响应地址栏显隐,不会闪白或留空。
立即学习“前端免费学习笔记(深入)”;
- 推荐写法:
min-height: 100vh;后叠加@supports (min-height: 100dvh) { .fullscreen { min-height: 100dvh; } } - 别用
@supports (height: 100dvh)—— Safari 16.3 会误判支持,导致降级失败 - 不用
height: 100dvh直接赋值,否则内容超长时会被裁剪;min-height更安全
内容超长或 WebGL/Canvas 场景需 JS 补偿
即使用了 100dvh,某些初始化时机(如页面刚加载、地址栏状态未稳)或特殊渲染需求(如 Canvas 像素级匹配)仍需 JS 动态同步。
- 监听
resize、scroll、orientationchange三个事件(iOS 地址栏变化不一定触发 resize) - 节流执行:
el.style.height = window.innerHeight + 'px'; - 避免在
DOMContentLoaded中直接设置高度——此时window.innerHeight可能还是初始值



















