如果不是 body 元素,Android 无法正确滚动输入焦点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23757345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android does not correctly scroll on input focus if not body element
提问by Dominic
When a mobile browser brings up a keyboard it tries to move the scrollbars so that the input is still in view.
当移动浏览器打开键盘时,它会尝试移动滚动条,以便输入仍然可见。
On iOS Safari it seems to do this properly by finding the nearestscrolling parent.
在 iOS Safari 上,它似乎通过找到最近的滚动父项来正确执行此操作。
On Android native or Chrome mobile browser it seems to just try the body element and then gives up, so the focused input is hidden beneath the keyboard.
在 Android 原生或 Chrome 移动浏览器上,它似乎只是尝试使用 body 元素然后放弃,因此焦点输入隐藏在键盘下方。
?How to break it
?如何破解
Set overflow-y: hidden
on the body element. Create a scrollable container and put a form in there.
设置overflow-y: hidden
在 body 元素上。创建一个可滚动的容器并在其中放置一个表单。
When you select an element near the bottom of your screen it will be obscured by the keyboard.
当您选择屏幕底部附近的元素时,它会被键盘遮挡。
Demo
演示
http://dominictobias.com/android-scroll-bug/
http://dominictobias.com/android-scroll-bug/
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"/>
<title>Android scroll/focus bug</title>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
.scroll {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow-y: scroll;
}
input {
margin-bottom: 20px;
width: 100%;
}
</style>
</head>
<body>
<div class="scroll">
<input type="text" value="Input 1">
<input type="text" value="Input 2">
<input type="text" value="Input 3">
<input type="text" value="Input 4">
<input type="text" value="Input 5">
<input type="text" value="Input 6">
<input type="text" value="Input 7">
<input type="text" value="Input 8">
<input type="text" value="Input 9">
<input type="text" value="Input 10">
<input type="text" value="Input 11">
<input type="text" value="Input 12">
<input type="text" value="Input 13">
<input type="text" value="Input 14">
<input type="text" value="Input 15">
<input type="text" value="Input 16">
<input type="text" value="Input 17">
<input type="text" value="Input 18">
<input type="text" value="Input 19">
<input type="text" value="Input 20">
</div>
</body>
</html>
Any ideas how to fix this? Will it require some browser detection and messy hacks?
任何想法如何解决这一问题?它是否需要一些浏览器检测和凌乱的黑客攻击?
回答by Serge
This is a bug in the Android native browser. By the way, the input scrolls into the view after a character is typed on the soft keyboard.
这是 Android 原生浏览器中的一个错误。顺便说一下,在软键盘上输入一个字符后,输入会滚动到视图中。
The following code snippet placed somewhere in the page should help:
放置在页面某处的以下代码片段应该会有所帮助:
if(/Android 4\.[0-3]/.test(navigator.appVersion)){
window.addEventListener("resize", function(){
if(document.activeElement.tagName=="INPUT"){
window.setTimeout(function(){
document.activeElement.scrollIntoViewIfNeeded();
},0);
}
})
}
回答by Zack Huston
The answer from Serge is great but I had a few modifications that improved it for me.
Serge 的回答很好,但我做了一些修改,为我改进了它。
The problem appeared on Android 6 for me as well so I added it to the check and I needed the fix to work for textareas as well as inputs.
这个问题也出现在我的 Android 6 上,所以我将它添加到检查中,我需要修复程序来处理 textareas 和输入。
if(/Android [4-6]/.test(navigator.appVersion)) {
window.addEventListener("resize", function() {
if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA") {
window.setTimeout(function() {
document.activeElement.scrollIntoViewIfNeeded();
},0);
}
})
}
If anyone needs the fix in Angular 1, here is what I used there.
如果有人需要 Angular 1 中的修复,这就是我在那里使用的。
angular.module('<module name>').run(function ($window, $timeout) {
if(/Android [4-6]/.test($window.navigator.appVersion)){
$window.addEventListener("resize", function(){
if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA"){
$timeout(function() {
document.activeElement.scrollIntoViewIfNeeded();
});
}
});
}
});
回答by Derek Mueller
Offering slight revision if it saves anyone some time:
如果可以节省任何人的时间,则提供轻微的修改:
- No need to specify an Android version # (less likely to break when your user gets Android 7.0+)
- No need to wrap in a setTimeOut
MDN advises against
.scrollIntoViewIfNeeded
bc of browser incompatibility =>.scrollIntoView
is a workable substitute with slightly more browser compatibilityif(/Android/.test(navigator.appVersion)) { window.addEventListener("resize", function() { if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA") { document.activeElement.scrollIntoView(); } }) }
- 无需指定 Android 版本 #(当您的用户使用 Android 7.0+ 时不太可能中断)
- 无需包装在 setTimeOut 中
MDN 建议不要
.scrollIntoViewIfNeeded
浏览器不兼容的 bc =>.scrollIntoView
是一个可行的替代品,浏览器兼容性稍高if(/Android/.test(navigator.appVersion)) { window.addEventListener("resize", function() { if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA") { document.activeElement.scrollIntoView(); } }) }
回答by Ben Trewern
Looking at this slightly differently the bug seems to be caused by the Suggestions feature of the browser. As I don't really want the suggestions anyway I've used:
从稍微不同的角度来看,该错误似乎是由浏览器的“建议”功能引起的。因为我真的不想要这些建议,所以我已经使用过:
if(/Android/.test(navigator.appVersion)){
$('input[type="text"]').attr('autocomplete', "off");
}
which gives a much smoother experience.
这提供了更流畅的体验。