skip to Main Content

I have a layout that is similar to a console where there is a menu bar on top, an input line in the bottom, and in the middle there is a scrolling div with text that gets added as you type.

let pre = $("pre")
for (let i = 0; i < 200; i++) {
    pre.append("<span class='line'>line " + i + "</span>")
}
function bottom() {
    pre.scrollTop(pre.prop("scrollHeight"));
}
$("#commandline").on('keyup', function (e) {
  if(e.which == 13){
    pre.append("<span class='line'>" + $("#commandline").val() + "</span>");
    bottom();
    $("#commandline").val("");
  }
});
bottom();
html, body {
  top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    overflow: hidden;
    position: absolute;
}


#container {
      position: absolute;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

#toprow, #bottomrow {
  flex: none;
  background-color: red;
}

#midrow {
  flex: 1;
    display: flex;
    position: relative;
}

pre {
  overflow-y: scroll;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: 0;
  box-sizing: border-box;
}

.line {
  display: block;
}

#commandline {
  position: relative;
  width: 100%;
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
  <body>
    <div id="container">
      <div id="toprow">
        Menubar
      </div>
      <div id="midrow">
        <pre>
          <span>ton of lines</span>
        </pre>
      </div>
      <div  id="bottomrow">
        <input type="text" id="commandline">
      </div>
    </div>
  </body>
</html>

It all works fine in a normal browser. And it also renders fine in a mobile browser as long as you don’t focus into the input box. When you do that the onscreen keyboard pops up and shifts the top of the ui outside of the remaining viewport instead of adjusting the height of the window to fill the remaining space.

You can see how that can break everything because there is a scrolling div in the middle, so you cannot scroll up to get to the menubar anymore until you scroll the whole middle pre up to the top.

I need this layout to always fill the remaining space on the screen, not shift up when the keyboard appears.

I tried in the Chrome dev tools by emulating th device Nexus 5, and there it seems to work, but when trying to test this on a Samsung S20 in mobile Chrome it doesn’t.

Can somebody help to figure out a layout that works responsively with the on screen keyboard on a mobile?

Here is the JsFiddle: https://jsfiddle.net/cpzqf9vo/1/

Bonus point: is there a way to remove the adressbar from the mobile browser?

2

Answers


  1. The Problem

    As I can see, you are using a new version of Chrome mobile; that is, Chrome v108+. A few days ago, another guy had a similar problem right here…
    Fixed elements disappear when keyboard opens in Chrome Mobile

    To make things clear, Google made an announcement, you can read it here, that this behavior was problematic to many layouts and that a change is coming. This behavior was well-known in Safari browsers, and probably on Chrome for iOS (CriOS). On other mobile browsers (Opera, Firefox, …etc.) your code will work just fine.

    Possible Solutions

    In Chrome (Android) you can add the following code to your meta tags…

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

    Probably, your code have a viewport meta tag, so you will only need to add interactive-widget=resizes-content to the end of it. This way, it will work on the Android version of Chrome. About CriOS or Safari on iOS, I don’t actually know a viable solution as I haven’t tested any of them. Yet, below are some links that may help you out!

    Useful Links

    https://css-tricks.com/a-couple-changes-coming-in-chrome-108/

    https://css-tricks.com/css-fix-for-100vh-in-mobile-webkit/

    Is there any fix to iOS, safari and chrome fixed position for when keyboard shows up?

    Iphone safari not resizing viewport on keyboard open

    screen styling when virtual keyboard is active

    Login or Signup to reply.
  2. Solution

    Use flex-grow (only for the middle element) property instead of flex.

    ⚠️ Warning
    My solution is not 100%, but it is certain that thanks to flex-grow, your list gets automatic resizing.

    In mobile browsers where the header disappears upon scrolling down, I encounter a small issue in detecting the resizing, but this is likely due to the browsers. I don’t know yet how to improve this.

    However, for the original problem, the solution seems effective: if the keyboard appears, flex-grow resizes the list.

    As an extra, I fixed your overflowing input field. The border should be included in the 100% width as well!

    let pre = $("pre");
    
    for (let i = 0; i < 200; i++) {
      pre.append("<span class='line'>line " + i + "</span>");
    }
    
    function bottom() {
      pre.scrollTop(pre.prop("scrollHeight"));
    }
    
    $("#commandline").on('keyup', function (e) {
      if(e.which == 13){
        pre.append("<span class='line'>" + $("#commandline").val() + "</span>");
        bottom();
        $("#commandline").val("");
      }
    });
    
    bottom();
    #container {
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }
    
    #toprow, #midrow, #bottomrow {
      position: relative;
    }
    
    #toprow, #bottomrow {
      /* flex: none; Not needed */
      background-color: red;
    }
    
    #midrow {
      /* flex: 1; Not needed */
      flex-grow: 1; /* Fill the remaining space in the flex container (that we left between the top and bottom) */
      display: flex;
    }
    
    pre {
      overflow-y: scroll;
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      margin: 0;
    }
    
    .line {
      display: block;
    }
    
    #commandline {
      position: relative;
      width: 100%;
      border: 1px solid red;
      box-sizing: border-box; /* So that the outline is within 100% --> this way, the input field doesn't stick out */
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <div id="container">
      <div id="toprow">
        Menubar
      </div>
      <div id="midrow">
        <pre>
          <span>ton of lines</span>
        </pre>
      </div>
      <div id="bottomrow">
        <input type="text" id="commandline">
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search