移动端布局的坑:100vh在手机上为何不靠谱?
做前端开发的朋友应该都遇到过这种情况。写了一个全屏的页面模块,用了下面这行代码:
.hero {
height: 100vh;
}在电脑浏览器上看,一切正常。可一拿到手机上测试,问题就全冒出来了。页面布局乱跳,底部内容被截掉一半,滑动起来也不顺畅。很多人第一反应是怀疑自己代码写错了,反复检查flex布局、padding、margin,可问题依旧存在。
其实,这真不是你的技术问题。问题出在100vh这个单位上。在移动端浏览器里,100vh并不等于屏幕可视区域的高度。
为什么100vh在手机上会出问题?
手机浏览器和电脑浏览器不一样。手机屏幕上有一些固定元素:
当你上下滑动页面时,这些元素会隐藏或显示。这就导致了一个问题:浏览器其实有两个高度。
一个是可视区域高度,就是你现在实际能看到的部分。另一个是完整高度,包括了工具栏背后隐藏的空间。
问题在于,100vh取的是完整高度,而不是可视高度。这就意味着,你设置height:100vh的元素,实际高度比用户看到的屏幕还要高出一截。底部自然就被切掉了一块。
三个真实场景,看100vh如何毁掉页面
场景一:首屏内容被截断
你做了一个落地页,大标题、副标题、按钮都在一个全屏模块里居中显示。在电脑上看着特别完美。可到了手机上,按钮不见了,或者只露出半个。用户想点按钮都点不到。
场景二:输入框弹出后布局错乱
登录页面设置了100vh。用户点输入框,手机键盘弹出来。视口高度瞬间变小,整个页面开始疯狂跳动,布局缩成一团,用户体验极差。
场景三:全屏弹窗不全屏
写了一个模态框,用fixed定位,高度设100vh。在iOS Safari上,模态框比屏幕大了一点,底部出现滚动条,关闭按钮跑到看不见的位置。
三个新的css单位解决问题
CSS新出了三个视口单位,专门解决这些问题。
svh:小视口高度
这个单位取的是最小可视高度。不管浏览器的工具栏怎么变化,它都使用那个不会被挡住的高度。适合用在首屏大图、落地页这些绝对不能出错的场景。
dvh:动态视口高度
这个单位会随着浏览器工具栏的显示隐藏实时变化。当地址栏出现或消失,它会自动调整高度。适合做全屏应用、聊天界面这些需要填满屏幕的布局。
lvh:大视口高度
这个取的是最大高度,包括工具栏背后的空间。这个单位用得很少,大多数场景都不适合。
实际开发中怎么用
首屏模块这样写
.hero {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: 20px;
}用min-height而不是height,是为了防止内容太多时被截断。写两行是为了兼容老浏览器,不认识的会使用100vh,认识的用100svh覆盖。
全屏应用这样写
.app {
height: 100dvh;
overflow: auto;
}工具栏显示隐藏时,应用高度会自动调整,始终填满屏幕。
弹窗这样写
.modal {
position: fixed;
inset: 0;
height: 100dvh;
overflow: auto;
}这样弹窗用起来就像原生应用一样顺滑。
常见问题解答
是不是以后不能用100vh了?
不是。100vh在电脑上完全没问题,问题主要出在移动端浏览器。
三个新单位怎么选?
记住这个原则:落地页首屏用svh,追求稳定;应用类布局用dvh,追求实时适配;lvh基本用不上。
能不能全部用dvh?
不太建议。因为浏览器工具栏显示隐藏时,dvh会不断变化,导致页面频繁重绘。对于首屏来说,我们需要的是稳定,不是动态变化。
总结
以后在手机上做全屏布局,别再死磕100vh了。用100svh做落地页,100dvh做应用界面。你的页面会稳如泰山,再也不会出现布局乱跳、内容被截的尴尬情况。代码简单,效果靠谱,用户看着舒服,自己也省心。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!