【问题标题】:Mobile safari - on screen keyboard hiding some elementsMobile safari - 在屏幕键盘上隐藏一些元素
【发布时间】:2022-06-24 06:23:08
【问题描述】:

我正在使用 flexbox 为 HTML 聊天应用程序构建一个非常简单的 POC。这个想法是让聊天消息从消息窗口的底部开始。典型的东西。

我通过使用嵌套的 flexbox 来做到这一点,其中内部 div 设置为 flex-direction: column,外部 div 设置为 flex-direction: column-reverse 和 overflow-y: auto:

<div class="outer">
    <div id="messages" class="inner">
        <div class="message">hello</div>
    </div>
</div>
.outer {
    flex-grow: 1;
    display: flex;
    flex-direction: column-reverse;
    overflow-y: auto;
}

.inner {
    display: flex;
    flex-direction: column;
}

它适用于桌面浏览器:

它在 iOS safari 上也可以正常工作,最多可以收到一定数量的消息。但是在某些时候,新消息会隐藏在屏幕键盘后面,查看它们的唯一方法是手动向下滚动或关闭屏幕键盘。注意:再次打开键盘将不再隐藏消息,关闭键盘似乎重置滚动。

打开 Safari 开发工具会发现一些有趣的东西。 When selecting an html element Safari thinks it is where it should be, in fact the preceding element is shown:

注意我是如何选择最后一个元素“二”的,但开发工具会突出显示消息“一”

我注意到的其他事情。将外部 div 的 overflow-y 更改为 hidden 可以解决问题,但显然我无法再滚动浏览消息了。

我猜这个问题与有两组滚动条有关,一组用于 div,另一组用于由键盘移动的页面本身。

有谁知道为什么会发生这种情况以及如何预防?

我创建了一个fiddle,并将页面托管在S3

在我的手机上,添加大约 12/13 条消息足以让他们开始“隐藏”在键盘后面。

【问题讨论】:

    标签: javascript html css mobile-safari


    【解决方案1】:

    这种 iOS 行为可能是需要的,因为它可以防止打开键盘时突然跳转,但如果您想覆盖它,请尝试添加到您的代码中:

    const outer = document.querySelector(".outer")
    
    const scrollToBottom = () => {
      outer.scrollTop = 0
    }
    
    input.addEventListener("focus", scrollToBottom)
    

    const messages = document.getElementById("messages");
    const input = document.getElementById("messageInput");
    const target = document.getElementById("send");
    const template = document.getElementById("messageTemplate");
    
    const pushMessage = () => {
      const clone = template.content.cloneNode(true);
      clone.querySelector("div.message").innerText = input.value;
      messages.appendChild(clone);
    }
    
    const keyUpHandler = (e) => {
      if (e.key === 'Enter') pushMessage()
    }
    
    target.addEventListener("click", pushMessage)
    input.addEventListener("keyup", keyUpHandler)
    
    const outer = document.querySelector('.outer');
    
    const scrollToBottom = () => {
      outer.scrollTop = 0;
    }
    
    input.addEventListener("focus", scrollToBottom)
    .page {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      display: flex;
      flex-direction: column;
      height: 100%;
    }
    
    .header,
    .footer {
      padding: 1rem;
      background-color: lightgrey;
      display: flex;
      flex-direction: row;
    }
    
    .outer {
      flex-grow: 1;
      display: flex;
      flex-direction: column-reverse;
      overflow-y: auto;
      /*overflow-y: hidden;*/
    }
    
    .inner {
      display: flex;
      flex-direction: column;
    }
    
    .message {
      padding: 1rem;
    }
    <div class="page">
      <div class="header">
        header
      </div>
    
      <div class="outer">
        <div id="messages" class="inner">
          <div class="message">hello</div>
        </div>
      </div>
    
      <div class="footer">
        <input id="messageInput" type="text" placeholder="Enter your message" />
        <button id="send">send</button>
      </div>
    </div>
    
    <template id="messageTemplate">
      <div class="message"></div>
    </template>

    【讨论】:

      【解决方案2】:

      我通常做的是围绕整个页面创建一个 div。该元素的高度为 100vh,宽度为 100vw,并且具有相对位置。

      这样你就有了一个可滚动的元素,你可以在焦点上滚动到底部。

      此外,例如,如果您尝试将某些东西粘贴(绝对定位)到页面底部,它实际上会位于键盘上方。

      【讨论】:

        【解决方案3】:

        我遇到了这个确切的问题(也构建了一个聊天 UI)并设法最终找到了解决方案

        在 Safari 控制台玩过之后,我意识到如果我将 scrollTop 设置为 0 它会正确地将我跳到线程的底部,但是如果我随后发送另一条消息, em> 消息会隐藏在输入后面。

        有趣的是,如果我将它设置为类似的值(如-1),它会再次将我跳到底部。

        有了这个见解,我尝试将它结合起来,并找到了一个可行的解决方案!

        这就是我最终的结果:

         scrollNewMessage() {
          const scrollTop = this.$refs["message-thread-wrapper"].scrollTop
        
          // iOS Safari refuses to update scrollTop if the given value is the same as its
          // current value. That would be fine, except that the current value is _incorrect_
          // when the keyboard is open
          // This was resulting in messages hiding behind the message compose box
          // Ensuring the value is always different fixes it
          this.$refs["message-thread-wrapper"].scrollTop = scrollTop === 0 ? -1 : 0
        },
        

        【讨论】:

          猜你喜欢
          • 2014-03-24
          • 1970-01-01
          • 1970-01-01
          • 2015-10-26
          • 2018-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-26
          相关资源
          最近更新 更多