How to make the mobile keyboard appearance bump the div rather than absolutely position itself over it?

后端 未结 1 1104
既然无缘
既然无缘 2021-01-07 03:07

I\'m developing a simple chat component and I\'m having an issue where, on mobile, if I click the textbox to send a message, rather than bumping up the messages list above i

相关标签:
1条回答
  • 2021-01-07 04:00

    Fortunately, there is. The problem here is you are not handling the scroll position of the .messages when the .send-message div expands (i.e. gets more margin). I presume you want to adjust it so that the scroll position takes the last visible message as its pivot (i.e. the last visible message before the div expands has to appear after the div expands, and vice-versa). To adjust said scroll position, here's a minimal working example (I changed your HTML content a little so that you can indicate what the last message is and I adjusted your JS code):

    function test() {
      let messageBox = document.querySelector('.messages')
      let beforeMessageBoxHeight = messageBox.clientHeight
      let afterMessageBoxHeight
      let messageBoxHeightDifference
      let beforeScrollTop = messageBox.scrollTop
      let afterScrollTop
      document.querySelector(".send-message").classList.toggle("some-margin")
      afterMessageBoxHeight = messageBox.clientHeight
      messageBoxHeightDifference = beforeMessageBoxHeight - afterMessageBoxHeight
      afterScrollTop = beforeScrollTop + messageBoxHeightDifference
      messageBox.scrollTop = afterScrollTop
    }
    .container {
      width: 400px;
      height: 300px;
      border: 1px solid #333;
      display: flex;
      flex-direction: column;
    }
    
    .messages {
      overflow-y: auto;
      height: 100%;
    }
    
    .send-message {
      width: 100%;
      display: flex;
      flex-direction: column;
    }
    
    .some-margin {
      margin-bottom: 100px;
    }
    <div class="container">
      <div class="messages">
        <div class="message">hello1</div>
        <div class="message">hello2</div>
        <div class="message">hello3</div>
        <div class="message">hello4</div>
        <div class="message">hello5</div>
        <div class="message">hello6</div>
        <div class="message">hello7</div>
        <div class="message">hello8</div>
        <div class="message">hello9</div>
        <div class="message">hello1</div>
        <div class="message">hello2</div>
        <div class="message">hello3</div>
        <div class="message">hello4</div>
        <div class="message">hello5</div>
        <div class="message">hello6</div>
        <div class="message">hello7</div>
        <div class="message">hello8</div>
        <div class="message">hello9</div>
        <div class="message">hello1</div>
        <div class="message">hello2</div>
      </div>
      <div class="send-message">
        <input />
      </div>
    </div>
    
    <button onclick="test()">add margin</button>

    The idea is:

    • Get the clientHeight (visible height, read MDN Docs for more details) before the div expands
    • Get the scrollTop value (how many pixels measured from the topmost visible/invisible element to the topmost visible element)
    • When the div (.send-message) expands, the visible height (clientHeight) automatically reduces in size. The scrollTop value is still the same, which means that the topmost visible element before the div expands will still be visible. However, that is not what we want: we want the bottommost visible element before the div expands to remain visible
    • We measure the height difference after the div expands and before the div expands. Logically, the height difference is what is making the bottom parts of the visible messages (before the div expands) to appear invisible (due to overflow).
    • To address that issue, add the height difference to the previous scrollTop value so that it scrolls nicely to the bottommost visible message before the div expands.
    • Voila, it works. You can apply the same logic when the div retracts.
    0 讨论(0)
提交回复
热议问题