我有一个带有粘性页眉和页脚元素的聊天应用程序。当移动虚拟键盘打开时,我将文档的高度设置为
window.visualViewport.height
。例如。如果浏览器的高度为 1000px,虚拟键盘为 400px,则 window.visualViewport.height
为 600px,并且 <html>
和 <body>
都设置为 600px。页眉和页脚都会在 600 像素视口中正确显示。
但是,用户仍然可以将整个页面向上滚动 400 像素,这意味着他们会在底部看到 400 像素的空白区域。如何在仍然具有粘性页眉/页脚的同时防止出现此空白空间?
我尝试过:
position: fixed
,但滚动时不粘在底部navigator.virtualKeyboard.overlaysContent
没有任何作用主要在 Android + Chrome 中测试,但在 iOS + Safari 中也出现同样的问题。
视频演示,最初的底部空白是键盘:https://i.imgur.com/OMSXAAt.mp4
编辑赏金: 我使用
window.visualViewport.addEventListener('scroll', ...)
找到了一个 hacky 解决方案。在滚动时,我会在页面顶部添加一些等于 window.visualViewport.offsetTop
的填充。但是,存在一些滞后,因此用户可以滚动一点,然后滚动处理程序就会运行。在 iOS Safari 上,延迟可能会超过 1 秒。有更好的解决办法吗?
如果键盘出现时位置没问题,我建议使用 virtualkeyboard 事件并使父 div 在活动时隐藏滚动,并在它再次消失时使其可滚动:
代码片段:
if ("virtualKeyboard" in navigator) {
navigator.virtualKeyboard.addEventListener("geometrychange", (event) => {
const { x, y, width, height } = event.target.boundingRect;
// Test if the keyboard is open, you will have to write this yourself
// But just for an example:
let keyboardOpen = height > 0;
if (keyboardOpen) {
// Make the parent element stop scrolling by making the overflow hidden
document.getElementById("parent-div").style.overflow = "hidden";
} else {
// Make the parent element scrollable again
document.getElementById("parent-div").style.overflow = "scroll";
}
});
}
只需确保将正确的 div ID 插入到文档查询中,并在其 HTML 标记中为该 div 提供一个 ID。
参考资料:
你在这里。多种技术的组合似乎是最有效的。
来源:软键盘打开时获取视口高度
JSBin代码:https://jsbin.com/nayigetido/1/edit?html,css,js,output
JSBin 输出:https://output.jsbin.com/nayigetido/1
HTML:
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content">
</head>
<body>
<div id="chat">
<div class="messages">Messages</div>
<input type="text"/>
</div>
</body>
CSS:
#chat{
height:100%;
width:100%;
display:flex;
flex-direction:column;
padding:3em;
box-sizing:border-box;
}
.messages{
height:100%;
flex:1 1 auto;
}
input{
width:100%;
}
html,body{
margin:0;
height:100%;
}
JS:
window.addEventListener('resize', () => {
const chat = document.getElementById('chat');
chat.style.height = window.visualViewport.height + 'px';
});
当您的聊天应用程序中使用粘性页眉和页脚元素打开移动虚拟键盘时,您似乎面临着防止显示空白空间的一些挑战。您发现使用
window.visualViewport.addEventListener('scroll', ...)
和一些填充的 hacky 解决方案是正确的,但可能需要一些改进来减少延迟。让我们探索一些潜在的解决方案:
resize
和 scroll
事件侦听器来处理视口大小和滚动位置的更改。当虚拟键盘打开时,会触发 resize
事件,当用户开始滚动时,会触发 scroll
事件。let prevVisualViewportHeight = window.visualViewport.height;
function handleResize() {
const currentVisualViewportHeight = window.visualViewport.height;
const offsetDiff = prevVisualViewportHeight - currentVisualViewportHeight;
document.body.style.paddingBottom = `${offsetDiff}px`;
prevVisualViewportHeight = currentVisualViewportHeight;
}
function handleScroll() {
const currentVisualScrollTop = window.visualViewport.scrollTop;
if (currentVisualScrollTop !== 0) {
window.visualViewport.scroll(0, 0); // Reset scroll position to prevent further scrolling
}
}
window.visualViewport.addEventListener('resize', handleResize);
window.visualViewport.addEventListener('scroll', handleScroll);
html, body {
height: 100%;
overflow: hidden;
}
body.keyboard-open {
padding-bottom: env(safe-area-inset-bottom);
overflow: auto;
}
使用此 CSS,您可以在虚拟键盘打开或关闭时向 body 元素添加或删除
keyboard-open
类。
function handleKeyboardOpen() {
document.body.classList.add('keyboard-open');
}
function handleKeyboardClose() {
document.body.classList.remove('keyboard-open');
}
// Add event listeners to detect keyboard open/close events
// You can use the methods that work best for your application.
focusout
事件:
当虚拟键盘关闭时,会触发 focusout
事件。您可以使用此事件删除填充并重置滚动位置。function handleFocusOut() {
document.body.style.paddingBottom = '0';
window.visualViewport.scroll(0, 0); // Reset scroll position
}
// Add event listener to detect focusout event
// You can use the methods that work best for your application.
请记住选择最适合您的特定用例和目标平台的方法组合。每种方法都有其优点和局限性,但这些方法的组合可以提供更强大的解决方案。此外,您可能需要在各种设备和浏览器上测试这些解决方案以确保兼容性。