Search code examples
htmlioscss

IOS Safari: unwanted scroll when keyboard is opened and body scroll is disabled


There is a known technique to disable page scroll when modal window is opened.

CSS:

html {
  height: 100%;
}

body.disable-scroll {
  position: fixed;
  height: 100%;
  overflow: hidden;
}

HTML:

<!DOCTYPE html>
<html>

<head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
    <meta content="width=device-width, initial-scale=1.0, user-scalable=no" name="viewport">
</head>

<body class="disable-scroll">
    <div class="page-content">
        <input type="text">
        ... content ...
    </div>
</body>

</html>

But on IOS Safari scroll becomes enabled after virtual keyboard is opened. And it scrolls more than even window.innerHeight + window.scrollX. Some blank gap appears at bottom of the page. enter image description here

Editor's url
https://codesandbox.io/s/condescending-snow-skuo5?fontsize=14

Fullscreen url to check on IPhone
https://skuo5.codesandbox.io/
Just open on IPhone or in XCode with IOS 12+ try to scroll and then focus on Input and try to scroll again.


Solution

  • Just went through tedious searching and seems that's an issue with iPhone as you have pointed in following article : https://blog.opendigerati.com/the-eccentric-ways-of-ios-safari-with-the-keyboard-b5aa3f34228d

    So there is no way you can do it with css for sure.

    But that doesn't stops you from using JQuery and Javascript >:)

    Here is an untidy work around for your scenario. Have tested with multiple text boxes too on iPhone only:

    document.getElementById("app").innerHTML = `
    <div class="page-content">
    <input type="text" 
    onfocus="disableScrolling(this)" 
    onfocusout="enableScrolling(this)">
      <p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p>
      <input type="text" 
      id="text2"
    onfocus="disableScrolling(this)" 
    onfocusout="enableScrolling(this)">
      <p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p><p>Page content</p>
    </div>`;
    
    var currentElem;	
    
    function stopScroll() 
    {
        if(currentElem)
        {
            var top = $("input:focus").offset().top;
            $('html, body').stop().animate({
                scrollTop: top
            }, 500, function(){});
        }
    }
    
    function disableScrolling(elem) 
    {
        currentElem = elem;
        document.addEventListener("touchend", stopScroll);
        setTimeout(function()
        {
            stopScroll();
        },10);
    }
    
    function enableScrolling() 
    {
        currentElem = undefined;
        document.removeEventListener("touchend", stopScroll);
    }
    html {
      height: 100%;
      scroll-behavior: smooth;
    }
    
    body.disable-scroll {
      position: fixed;
      height: 100%;
      overflow: hidden;
    }
    
    .page-content {
      background: #ccc;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <body class="disable-scroll">
      <div id="app"></div>
      <div>End of body</div>
    </body>
    To explain in short what I did.

    Problem : User can scroll away while focusing on textbox

    Assuming that,

    Solution : Allow user to scroll where ever he want and once he is done bring him back smoothly to where you want him to be; input:focused :p

    Note : I have used JQuery to make things simpler. If you want to use pure javascript, you can find the replacement for the specific codes.