当软键盘打开时获取视口高度

42

当软键盘弹出时,我想获取准确的视口大小。目前我正在使用以下代码在头部使网站具有响应性:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>

我意识到的是,当软键盘出现时,它使用设备高度作为视口高度并将其余部分向上推动-这使我认为它从width=device-width选项获取其高度。

在启动软键盘后使用以下代码:

setTimeout(function() {  
    viewport = document.querySelector("meta[name=viewport]");
    viewport.setAttribute('content', 'height=auto');
}, 300)

使用jQuery获取高度可以在Android上显示正确的结果 - 即虚拟键盘不可见时的可视视口大小,但在iOS上却不能。我得到一个随机数,我认为这源于其余的meta标签不存在,所以我得到了一个缩小版本的网站以及一个像75或100的数字(在iPhone 4s上)。

我还尝试在打开键盘后创建一个固定的元素,使其使用视口高度并具有top:0;和bottom:0;属性,但我仍然得到原始高度。

更接近的解决方案是将视口meta标签高度设置为固定值,可以通过jQuery的$(window).height()进行拾取,这意味着在启动键盘后meta标签实际上有所作用,但固定高度没有真正的价值。

我看过很多关于此的话题,但没有一个解决方案。有解决此问题的人吗?

10个回答

13

2022

现在,您可以将 window.visualViewport.height 属性(具有 非常好的兼容性)与 windowresize 监听器结合使用:

window.addEventListener('resize', () => {
  // For the rare legacy browsers that don't support it
  if (!window.visualViewport) {
    return
  }

  console.log(window.visualViewport.height)
})


1
哇,仅仅是哇。痛苦地生活了10多年,现在我了解到这一点。这个方法太棒了。 - Stephan Schinkel
在我的情况下,我不得不使用间隔来检查视口高度的变化,因为Safari不会在软键盘调用resize。 - undefined

10

2023

从2022年开始的新功能。 在Chrome和Firefox上运行良好 在您的meta标签视口中添加"interactive-widget=resizes-content"。

<meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content">

非常适合我的需求。 链接

1
非常好用!我有一个底部导航栏,当键盘打开时我想让它停留在键盘上方,这个方法解决了我的问题。 - Chun
5
这在iOS Safari上不起作用,有什么解决办法吗? - Amith B
@AmithB 有运气吗? - Charanjit Singh
@CharanjitSingh 没有运气 - undefined

7
在我想获取虚拟键盘弹出后剩余屏幕的高度时,我使用了一个绝对溢出的元素覆盖整个屏幕并利用屏幕高度使整个页面内容置于其中。结果是,虚拟键盘在覆盖元素的顶部打开,而不改变其尺寸。
为了解决这个具体问题,我所做的只是将该元素的位置更改为静态,并在虚拟键盘打开时移除其溢出。实际上,当iOS发出虚拟键盘时(将元素更改为静态位置),它会更改为此行为,这就是为什么固定元素变成静态元素的原因。
希望这可以帮到你。

2
你能否提供一个带有示例代码的“绝对溢出”解释? - Aidin
@Aidin,代码应该是 position: absolute; top: 0; right: 0; bottom: 0; left: 0;。希望能帮到你。 - scooterlord

5
视口的尺寸取决于UIWebView元素的大小。
前一个回答所述,有两种方法来适应屏幕键盘。您可以调整视图大小或调整内容插图。
在iOS上,视口的尺寸报告视图的大小,因此调整大小会调整视口。 Safari调整插图并保持视图相同大小,因此视口不会改变。
如果您假设触摸设备通常使用屏幕输入而不是外部键盘,则可以通过编程方式自行调整大小,方法是获取设备高度或宽度(取决于方向),并考虑乘数以占用屏幕键盘的一部分。
我使用视口类作为代理,以便为我提供最可能的真实视口尺寸,而不是浏览器报告的尺寸,并绑定到输入元素以跟踪输入元素的状态和方向变化,以动态修改请求视口尺寸时应用的乘数。

1
问题在于键盘高度有不同种类...如果有人越狱了他们的设备怎么办?...但我想最终我会选择“手动”方式,只需减去键盘高度。 - scooterlord
输入演示与安卓设备有根本的不同。我认为这种差异是为了实现一致的用户体验。如果在较小视口上隐藏元素会导致刚刚查看的网站在执行用户输入时完全改变布局,这将成为UX噩梦。处理跨浏览器支持有两种方法:1)尝试强制所有东西按照自己的方式。或2)提供与该设备/浏览器的标准用户体验一致的替代演示。在我看来,后者更容易处理。 - Steve Buzonas
这个答案的内容是基于iOS 8发布日期的。一旦我开始使用第三方键盘支持和Safari,我会尽量记得发布另一个答案。 - Steve Buzonas
@SteveBuzonas - 你忘了吗? - ashleedawg

3

截至2021年3月,window.innerHeight在运行IOS 14.4.1的chrome、firefox、safari浏览器中反映了iPad软键盘的存在。


2
我很兴奋看到这个,但是对我来说它没有起作用。当我在使用iOS 14.5的iPhone 12模拟器中运行window.innerHeight时,无论键盘是否显示,我都得到相同的值。 - Nathan Manousos
9
哦,但是 window.visualViewport.height 可以工作,但是当你缩放时它会改变,这可能不是想要的。 - Nathan Manousos

2
我遇到了同样的问题,经过一段时间的混合使用CSS和少量JavaScript,我找到了解决方案。
注意事项:
- 我使用了jQuery和SCSS。 - 我更喜欢隐藏元素而不是改变其位置(简单有效)。 - 如果虚拟键盘关闭但输入仍在焦点上,则会显示该元素。为此,我将CSS规则包装在一个媒体查询中@media screen and (min-aspect-ratio: 11/16)。11/16是因为它小于常见的9/16比率(虚拟键盘的存在增加了这个比率,然后应用了该规则)。
解决方案:
首先是脚本(使用jQuery):
$(document).on('focus', 'input, textarea', function(){
    $('body').addClass("fixfixed");
});

$(document).on('blur', 'input, textarea', function(){
    $('body').removeClass("fixfixed");
});

当用户专注于文本输入并打开虚拟键盘时,body元素会有一个'fixfixed'类。

然后,使用CSS(我正在使用SCSS):

.fixfixed{
  @media screen and (min-aspect-ratio: 11/16) {
    .bottomThingToHideWhenVirtualKeyboardIsShown{
      opacity: 0;
      pointer-events: none;
    }
  }
}

就是这样了!

希望对某些人有所帮助!


我能理解为什么这在纵向方向上可能有效,但我无法想象它在横向方向上能够奏效。不过,这是一个有趣的想法。 - Teodor Sandu
这是我能找到的最合理的解决方案,使用特定的JavaScript代码在iOS应用程序访问时更改CSS并在焦点/失焦时删除/添加固定属性(不适用于浏览器)。感谢您的分享! - Eduardo Sztokbant

1
我想到了这个 hack:

var storedWidth = 0;
var storedHheight = 0;

function onResize() {

  var windowWidth = $(window).width();
  var windowHeight = $(window).height();
  var screenWidth = screen.width || windowWidth;
  var screenHeight = screen.height || windowHeight;
  var width, height;

  if(screenWidth < screenHeight) {
    if(windowWidth > storedWidth) storedWidth = windowWidth;
    if(windowHeight > storedHeight) storedHeight = windowHeight;
    width = storedWidth;
    height = storedHeight;
  }else {
    width = windowWidth;
    height = windowHeight;
  }

  //use width and height from here

}

现在这个方法会有两种情况失败:
  • 不支持screen.width/screen.height;它会回退到错误的jquery尺寸。在我的情况下,软键盘使高度比宽度小,而在纵向模式下,因此jQuery尺寸导致了虚假的横向模式,从而显示“旋转您的设备”消息。

  • 页面打开时软键盘已经打开,我认为这是无用的。隐藏后,最大高度将被存储,因此之后的事情都会被解决。

注意:

  • window.innerWidth/window.innerHeight可以用来摆脱jQuery依赖

  • 上面的代码是为了解决纵向模式下的键盘问题,但同样的解决方案也可以用于横向模式


0

仅供参考,当键盘在iOS上出现时,默认情况下它不会对底层的滚动视图产生任何影响。

如果您的内容显示在自定义的UIWebView中,则由程序员决定:

  • 调整滚动视图的大小以避免在键盘下方出现无法到达的内容。

  • 调整滚动视图的内容插入(推荐)。滚动视图的大小保持不变,但底部添加了一个“边框”,使用户可以滚动到所有内容。

我不确定这两种解决方案如何影响viewport,但您可以尝试两种方法。

但是,如果您的Web内容是由Safari呈现的,则Apple会为您调整插入。


4
谢谢回复,但我说的是网站项目,而不是应用程序,因此适用于所有设备。我正在寻找一种计算剩余高度的方法——如果它是针对特定设备的应用程序,则这将非常容易,但情况并非如此。我不知道这个边框的事情,但从外观上看,所有内容都被向上移动,而不是键盘覆盖它。 - scooterlord
也许是因为在键盘出现之前,内容已经滚动到了底部? - Rivera
虽然看起来是这样,但我看到的是这样。目前使用一个与屏幕高度相同的溢出元素。因此,当我点击输入时,它会居中,当我向上滚动时,它会向上移动到一个点,之后,您必须停止滚动才能停止弹跳,然后它会重新滚动到最上面。在底部滚动到文档的末尾,因此这让我相信屏幕顶部有更多的空间,在外部等于软键盘的高度。希望我表达清楚了,有点难以解释... - scooterlord

0

6
键盘的尺寸无法确定,因此这将无法正常工作。 - Michael Heilemann
@Heilemann 你说得对,这不再是一个好的解决方案了。 - James Hafner

-1

该代码片段试图返回在iOS6用户代理下近似的window.innerWidthwindow.innerHeight值;使用jQuery进行选择器和.on()操作。不确定如何检测iOS设备键盘事件部分,请参考资源链接。

尝试:

CSS

html {
    height : 100vh;
    width : 100vw;
}

js

$(function() {    
    if (/ipad|iphone/gi.test(window.navigator.userAgent)) {
    var events = "abort blur focus input scroll submit touchstart touchmove";
    $("form, input").on(events, function(e) {
      return (function(window, elem, w, h) {
               var vh = window.getComputedStyle(elem,null).getPropertyValue(h);
               var vw = window.getComputedStyle(elem,null).getPropertyValue(w);
               var vwh = { 
                           "documentWidth": vw, 
                           "documentHeight": vh, 
                           "windowInnerWidth": window.innerWidth, 
                           "windowInnerHeight": window.innerHeight
                         };
               console.log(vwh);
               var _vwh = document.getElementById("vwh");
               _vwh.innerHTML = JSON.stringify(vwh)
               return vwh 
              }(window, document.documentElement, "width", "height"));
    }).focus();
    };
})

jsfiddle http://jsfiddle.net/guest271314/Pv3N2/

资源

https://developer.mozilla.org/en-US/docs/Web/API/Window.innerHeight

http://www.w3.org/TR/2013/CR-css3-values-20130730/#vh-unit

如何处理iPhone中的键盘事件

https://coderwall.com/p/xuawww 响应iOS上的键盘事件

http://looksok.wordpress.com/2013/02/02/ios-tutorial-hide-keyboard-after-return-done-key-press-in-uitextfield/ iOS教程:在UITextField中按下返回/完成键后隐藏键盘

https://developer.apple.com/library/safari/documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/InteractiveControl/InteractiveControl.html#//apple_ref/doc/uid/TP40008032-CH16

http://www.quirksmode.org/mobile/viewports2.html


3
如果您希望获得这个问题的赏金,请描述您正在做什么以及为什么它有效。 - Fred
@Fred 如果我理解正确,要求包括检索 windowviewport 区域?帖子中的代码应该返回一个数组或字符串,其中包括 window.innerHeightwindow.innerWidth,请参见 https://developer.mozilla.org/en-US/docs/Web/API/Window.innerHeight。在不同的视口分辨率下尝试了 Firefox,返回了(设备)视口分辨率,例如([480, 320])。在 Chromium iOS(设备)上启用后,似乎返回了相同 HTML 中的 document.height?也许可以尝试一下这段代码?谢谢。 - guest271314
我建议您编辑您的答案,包括您刚才评论的信息,并尽可能地逻辑清晰。 - Fred
问题特别针对iOS软键盘弹出后的窗口高度。 - scooterlord
1
以上所有内容都提供了有用的信息,但是没有任何我不知道的东西,也没有帮助我解决问题的方法。当软键盘打开时,我仍然无法准确测量视口高度,而网站上的meta标签中有width=device-width,并且使用了溢出滚动元素。 - scooterlord
1
这在 iOS 9.2 上显示软键盘时无法返回正确的视口高度(事实上到目前为止我找到的任何方法都不行)。 - Michael Heilemann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接