如何阻止手机键盘上推React作品集网站的UI?
React移动端scroll-snap布局遇键盘弹出上推UI的问题及解决方法
问题描述
我用React制作了一个作品集网站,包含4个高度为100vh的section,通过纵向滚动捕捉(scroll-snap)实现上下滚动,底部section为「联系我」表单。在手机端测试时发现,点击输入框弹出键盘后,键盘并非覆盖网站内容,而是将整个UI向上推挤,导致布局破坏。
截图对比
- 正常UI:

- 异常UI:

当前使用的CSS代码
单个section样式
.snap-section { height: 100vh; width: 100vw; min-height: 100vh; scroll-snap-align: start; display: flex; align-items: center; justify-content: center; }
root元素样式
#root { background: radial-gradient( circle, rgba(1, 11, 56, 1) 0%, rgba(1, 20, 110, 1) 100% ); overflow-x: hidden; width: 100vw; height: 100vh; scroll-snap-type: y mandatory; overflow-y: scroll; }
我尝试过使用position: fixed和position: absolute,但这只会显示当前可见的顶部section,无法解决问题。需要找到让键盘仅覆盖网站内容、而非上推所有内容的方法。
解决方案
1. 用100dvh替代100vh(首选方案)
移动端浏览器中,100vh会将虚拟键盘的高度纳入计算,导致键盘弹出时视口高度被压缩,触发布局上推。而100dvh(动态视口高度)会忽略虚拟键盘,始终代表屏幕的实际可用高度(不含键盘),完美解决这个问题。
修改后的CSS代码:
.snap-section { height: 100dvh; width: 100vw; min-height: 100dvh; scroll-snap-align: start; display: flex; align-items: center; justify-content: center; } #root { background: radial-gradient( circle, rgba(1, 11, 56, 1) 0%, rgba(1, 20, 110, 1) 100% ); overflow-x: hidden; width: 100vw; height: 100dvh; scroll-snap-type: y mandatory; overflow-y: scroll; }
2. 针对旧浏览器的降级处理
如果需要兼容不支持dvh的浏览器(比如部分老版本iOS Safari),可以添加降级逻辑:
/* 基础样式 */ .snap-section { height: 100vh; height: 100dvh; width: 100vw; min-height: 100vh; min-height: 100dvh; scroll-snap-align: start; display: flex; align-items: center; justify-content: center; } #root { background: radial-gradient( circle, rgba(1, 11, 56, 1) 0%, rgba(1, 20, 110, 1) 100% ); overflow-x: hidden; width: 100vw; height: 100vh; height: 100dvh; scroll-snap-type: y mandatory; overflow-y: scroll; } /* 针对iOS Safari的降级适配 */ @supports (-webkit-touch-callout: none) { .snap-section { height: -webkit-fill-available; min-height: -webkit-fill-available; } #root { height: -webkit-fill-available; } }
3. JS监听键盘状态动态调整(备选方案)
如果CSS方案不生效,可以通过JS监听视口变化,判断键盘是否弹出,然后强制固定布局高度:
React组件示例:
import { useEffect } from 'react'; function App() { useEffect(() => { const handleResize = () => { const windowHeight = window.innerHeight; const screenHeight = window.screen.height; // 当视口高度小于屏幕高度的70%时,判定为键盘弹出 const isKeyboardOpen = windowHeight < screenHeight * 0.7; const rootEl = document.getElementById('root'); if (isKeyboardOpen) { rootEl.classList.add('keyboard-open'); } else { rootEl.classList.remove('keyboard-open'); } }; window.addEventListener('resize', handleResize); // 初始化时触发一次 handleResize(); return () => window.removeEventListener('resize', handleResize); }, []); return ( {/* 你的网站内容 */} ); }
对应的CSS:
#root.keyboard-open { height: 100dvh !important; overflow-y: hidden; }
内容的提问来源于stack exchange,提问作者GDimitrov28
相关产品推荐
相关产品推荐

