如何使用 CSS 或 JS 防止 iOS 键盘将视图推离屏幕

Posted

技术标签:

【中文标题】如何使用 CSS 或 JS 防止 iOS 键盘将视图推离屏幕【英文标题】:How to prevent iOS keyboard from pushing the view off screen with CSS or JS 【发布时间】:2016-12-01 20:46:34 【问题描述】:

我有一个响应式网页,当您点击按钮时会打开一个模式。当模态框打开时,它被设置为使用固定定位占据页面的整个宽度和高度。模态中还有一个输入字段。

ios 设备上,当输入字段获得焦点时,键盘会打开。但是,当它打开时,它实际上会将整个文档向上推,这样我的页面的一半就超出了视口的顶部。我可以确认实际的html 标签本身已被向上推以补偿键盘,并且它没有通过 CSS 或 javascript 发生。

以前有没有人见过这种情况,如果有,有没有办法阻止它,或者在键盘打开后重新定位?这是一个问题,因为我需要用户能够在模式顶部看到内容,同时我想自动聚焦输入字段。

【问题讨论】:

你看到了吗:***.com/questions/13820088/… @Iceman 不,我没有。我尝试搜索类似的问题,但没有找到。我试试看。 @rescuecreative 。我不确定这是否会有所帮助,因为此解决方案适用于 IOS8,因为我在 IOS8 和 Safari 上遇到了类似的问题。 @Iceman 我的环境不是phonegap,只是一个普通的网站。所以我不确定phonegap是否有什么不同,但这对我不起作用。 @rescuecreative 可能是新版本的问题。我会删除我的答案。 【参考方案1】:

第一

<script type="text/javascript">
 $(document).ready(function() 
     document.ontouchmove = function(e)
          e.preventDefault();
          
 );

然后这个

input.onfocus = function () 
    window.scrollTo(0, 0);
    document.body.scrollTop = 0;

【讨论】:

谢谢!它完美地工作。顺便说一句,我只用document.body.scrollTop = 0; 我试图解决一个问题 4 小时,直到我遇到你的答案。太感谢了。虽然只有input.onfocus = function () window.scrollTo(0, 0); document.body.scrollTop = 0; 是必需的。第一部分冻结页面。【参考方案2】:

对于在 React 中遇到这个问题的任何人,我已经设法修复它,并采用这样的 @ankurJos 解决方案:

const inputElement = useRef(null);

useEffect(() => 
  inputElement.current.onfocus = () => 
    window.scrollTo(0, 0);
    document.body.scrollTop = 0;
  ;
);

<input ref=inputElement />

【讨论】:

【参考方案3】:

我为此苦苦挣扎了一段时间,找不到适合我的东西。

我最终做了一些 JavaScript 骇客来让它工作。

我发现如果输入元素位于屏幕的上半部分,Safari 不会推送视口。这就是我的小技巧的关键:

我拦截了输入对象上的焦点事件,而是将焦点重定向到一个不可见的对象(transform: translateX(-9999px))。然后,一旦键盘出现在屏幕上(通常是 200 毫秒左右),我就会在原始元素上触发焦点事件,该元素已经在屏幕上显示动画。

这是一种复杂的交互,但效果很好。

function ensureOffScreenInput() 
  let elem = document.querySelector("#__fake_input");
  if (!elem) 
    elem = document.createElement("input");
    elem.style.position = "fixed";
    elem.style.top = "0px";
    elem.style.opacity = "0.1";
    elem.style.width = "10px";
    elem.style.height = "10px";
    elem.style.transform = "translateX(-1000px)";
    elem.type = "text";
    elem.id = "__fake_input";
    document.body.appendChild(elem);
  
  return elem;


var node = document.querySelector('#real-input')
var fakeInput = ensureOffScreenInput();

function handleFocus(event) 
  fakeInput.focus();

  let last = event.target.getBoundingClientRect().top;

  setTimeout(() => 
    function detectMovement() 
      const now = event.target.getBoundingClientRect().top;
      const dist = Math.abs(last - now);

      // Once any animations have stabilized, do your thing
      if (dist > 0.01) 
        requestAnimationFrame(detectMovement);
        last = now;
       else 
        event.target.focus();
        event.target.addEventListener("focus", handleFocus,  once: true );
      
    
    requestAnimationFrame(detectMovement);
  , 50);


node.addEventListener("focus", handleFocus,  once: true );

我个人在 Svelte 操作中使用此代码,它在我的 Apple Maps 的 Svelte PWA 克隆中运行良好。

Video of it working in a PWA clone of Apple Maps

您会在视频中注意到,在输入到视口上半部分的动画稳定后,自动完成功能会发生变化。这就是焦点切换的发生。

此 hack 的唯一缺点是原始实现上的焦点处理程序将运行两次,但有一些方法可以通过元数据来解决这一问题。

【讨论】:

这是唯一对我有用的东西。谢谢【参考方案4】:

如果你不想滚动到顶部(0, 0),你也可以这样做

window.scrollBy(0, 0)

【讨论】:

【参考方案5】:

在某些情况下,可以通过重新调整输入元素的焦点来缓解此问题。

input.onfocus = function () 
  this.blur();
  this.focus();

【讨论】:

这种方式会挂掉设备。想象一下在无限时间内模糊和重新聚焦同一个元素。【参考方案6】:

IOS8 和 Safari 浏览器在页面加载后发生的 input.focus() 行为相同。他们都缩放到元素并调出键盘。(不太确定这是否会有所帮助,但您是否尝试过使用类似的东西?)

HTML 是

<input autofocus>

JS 是

for (var i = 0; i < 5; i++) 
document.write("<br><button onclick='alert(this.innerHTML)'>" + i + "</button>");


//document.querySelector('input').focus();

CSS

button 
width: 300px;
height: 40px;

此外,您还必须使用用户代理解决方法,您可以将其用于所有 IOS 版本

if (!/iPad|iPhone|iPod/g.test(navigator.userAgent)) 
element.focus();

【讨论】:

对不起,也许我不明白。按钮和警报有什么帮助? @rescuecreative 我想我理解错了。我在想,也许您正试图在页面触摸后显示虚拟键盘和滚动。 啊,我明白了。不,我试图阻止虚拟键盘将 DOM 推到视口之外 @rescuecreative 只是一个建议您是否尝试过使用下面提到的这两个选项?

以上是关于如何使用 CSS 或 JS 防止 iOS 键盘将视图推离屏幕的主要内容,如果未能解决你的问题,请参考以下文章

使用 phonegap 防止键盘在 iOS 应用程序中向上推 webview

javascript 防止JS或CSS文件

如何防止 Android Firefox 浏览器在打开软键盘时调整窗口大小

如何防止键盘覆盖我的 UI 而不是调整它的大小?

如何更改或添加点击功能 js/css 以供移动使用

自定义 webview 键盘问题