33

Tested in Safari and Chrome - the same result, so I think it's iOS issue.

This happens only if there's an input inside the modal and I tap that input. In the same moment that input got focus and native iOS keyboard become visible.

Page below modal in the same moment is automatically scrolled to 50% of its height. This behaviour is totally unwanted and I have no clue how to prevent this default iOS "feature".

Demo:

enter image description here

Limon Monte
  • 52,539
  • 45
  • 182
  • 213
  • Use DOMListener for Chrome to get log of DOM changes. I got 59 changes on opening modal and adding 1 media query style. Also check resize handlers. Posiiotn fixed or overflow hidden also can be the issue. – Alex May 20 '16 at 08:49
  • Thank you @Pinal for reply! I tried to add dynamically `overflow: hidden` to body, but it doesn't help in this case. Probably `position: fixed` is the issue. Can you please explain a little bit more about why it can be issue and how can I fix it. – Limon Monte May 20 '16 at 09:15
  • 1
    Just noticed that `position:fixed` has some problems in iOS CoreGraphics render. In your case I recomend you to change all `position: fixed` to absolute and test again. Also you can look for solution on github (as example - https://github.com/scottjehl/Device-Bugs/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen++fixed++ios+) – Alex May 20 '16 at 09:36
  • i noticed that this function close(i, expectedNumberOfNonCommentArgs) impacts this thing, when you try to comment it there's no bg scroll in Safari. – GL.awog May 27 '16 at 14:22

8 Answers8

12

Just adding an answer here in case people stumble upon this question (rather than your other question, which has a great demo to illustrate this issue)

We are facing a similar issue at work. As you mentioned, the offset is always ~50% of the height of the page, which happens regardless of where your initial offset is.

In the past, when I observed a similar "jumping" with earlier iOS versions (albeit, much less dramatic jumping), I have usually worked around this by applying position: fixed (or relative) to the body (which allows overflow: hidden to properly work).

However, this has the unintended consequence of jumping the user back to the top of the page, if they've scrolled down.

So, if you're open to addressing this issue with some JavaScript, here's a fix/hack I've thrown together:

// Tapping into swal events
onOpen: function () {
  var offset = document.body.scrollTop;
  document.body.style.top = (offset * -1) + 'px';
  document.body.classList.add('modal--opened');
},
onClose: function () {
  var offset = parseInt(document.body.style.top, 10);
  document.body.classList.remove('modal--opened');
  document.body.scrollTop = (offset * -1);
}

And what the CSS looks like:

.modal--opened {
  position: fixed;
  left: 0;
  right: 0;
}

Here's a fork of your demo page (from your other question), to illustrate: https://jpattishall.github.io/sweetalert2/ios-bug.html

And for those who are looking for a more general fix, you could do something like the following when opening/closing a modal:

function toggleModal() {
    var offset;
    if (document.body.classList.contains('modal--opened')) {
        offset = parseInt(document.body.style.top, 10);
        document.body.classList.remove('modal--opened');
        document.body.scrollTop = (offset * -1);
    } else {
        offset = document.body.scrollTop;
        document.body.style.top = (offset * -1) + 'px';
        document.body.classList.add('modal--opened');
    }
}

Edit: To avoid the "shifting/unshifting" on desktops, I would suggest feature detection/ua sniffing to apply this to only mobile safari.

danronmoon
  • 3,814
  • 5
  • 34
  • 56
Jack
  • 9,151
  • 2
  • 32
  • 44
  • Just fyi in IE, `document.body.scrollTop` is always 0 and setting it doesn't scroll. Use `window.scroll(x,y)` instead and obtain scrollTop via `window.pageYOffset` in IE – Jeremy Bernier Mar 07 '17 at 05:01
1

I have experienced this issue as well. A short explanation is that iOS Safari will try to auto scroll to any input that is focused on and in this particular case the focused element is within a fixed positioned element. Safari seems to struggle with finding the fixed position element when it wants to center the element on the screen hence the background scrolling.

One possible fix is to add a touchstart event listener to the input field and calculate the current position of the overlay, change the positioning to absolute and update the top/left position to place the overlay back where it was on the screen when fixed positioned, and finally add a new blur listener to reset the overlay back to fixed positioning when leaving focus/blurring on the input. This should prevent the page from scrolling. I suggest using touchstart because it should trigger before the focus event at which case the page will already start scrolling. Safari should be able to find and center the absolute positioned overlay when the focus event is triggered.

The_Dude
  • 574
  • 2
  • 6
  • 16
1

So i have solved this and tested on my Iphone 5, don't have Ipad to check. I have disable overflow:hidden in my solution, you can add, If you want to disable scroll all in one for all modals. Solution is to add basically height and position property to both html and body element.

html, body {
   position:relative;
   /*overflow:hidden;*/
   height: 100%;
}

So, that only when you focus on input, height and position will be defined, i have already coded this solution from your repo, i will send you a pull request. I have also added browserSync in your gulp setup. Therefore, Now it will be easy to test across any device.

Cheers!

EDIT: another way, if above solution don't work for some reason. then,

 /*
  * @summary touch handler; will remove touch ability
  * @author yeomann
  */
  function Touchyhandler(e) {
    e.preventDefault();
  }

and later pragmatically add and remove touch listener like this

//to add
document.addEventListener('touchmove', Touchyhandler, false); 
//to remove   
document.removeEventListener('touchmove', Touchyhandler);

above js solution tested on IOS 9.3.2 work like charm for me]

Danish
  • 1,467
  • 19
  • 28
1

To stop the page from scrolling, in both x, and y axis, we use the overflow: hidden; attribute in css.

So if we apply this to the body,

body {
    overflow: hidden !important;
}

It should work right?

In fact, this actually doesn't work, because you've just disabled x and y scrolling for the entire page the for the entire time.

To bypass this, we can use a tad a javascript to add a class to the body when the modal is active.

First we must add an id to our body, <body id="body"> this allows javascript to recognize the body.

Secondly, we must add an id to our modal, <div id="modal">, also allowing javascript to recognize the modal.

<script type="text/javascript">
    function modalActive() {
        if (document.getElementById("modal").classList.contains("active")) {
            document.getElementById("body").classList.add("modal-active");
        } else {
            getElementById("modal").classList.remove("active"));
            getElementById("body").classList.remove("modal-active"));           
        }
    }
</script>

for both the button that launches, and closes the modal, we must add an onclick event,

<button onclick="modalActive()">Click Me!</button>

On top of that we must add this to the css file.

body {
    overflow: initial !important;
}

body.modal-active {
    overflow: hidden !important;
}

And there we go.

0

I'm not 100% sure but i could imagine the following:

When the keyboard appears, the window height decreases, but the scrollTop value is still the same, so the site jumps to that value. You could add overflow:hidden to the body when the modal is open. This will block the scrolling "behind" the modal and probably solve your problem.

Kilian So
  • 125
  • 7
  • Thanks for reply @Kilian! Unfortunately this trick doesn't fix my issue. Beside that, when I add `overflow: hidden` to body, in desktop browser this negative effect appears https://i.imgur.com/HDOxzmm.gif (body goes left-right on scrollbar show/hide). – Limon Monte May 20 '16 at 09:09
  • Hmm, you could add the `overflow` to a `#wrapper` instead of the `body` to avoid that issue. And then, add `position:absolute` to the modal instead of `fixed`. Have you already tried that? But if you add `position:absolute` without the `overflow:hidden` the page will jump to the top when you open the modal. – Kilian So May 20 '16 at 09:40
0

I tried multiple things which kind of worked for the bouncing modal inputs on the html page. The simplest solution which worked for me was adding following styles to the body tag when the modal is open on the page.

position: fixed;
width: 100%;
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
0

Add this meta (maximum-scale=1, minimum-scale=1 ) to reset the scroll, which occurred when focusing the input field.

ExOrIntro
  • 221
  • 3
  • 7
0

I had this issue after upgrading to iPadOS 13. I had to remove the following old JavaScript code, which was required to fix a different scrolling issue in older versions:

function fixIpadKeyboardScrolling() {
   if ((Device.is("ipad") || Device.is("iphone"))) {
    console.log("Fixing iPad/iPhone floating bar bug");
    var inputs = document.getElementsByTagName("input");
    if (inputs.length) {
      for (var i = inputs.length - 1; i >= 0; i--) {
        addListener(inputs[i], "blur", function () {
          setTimeout(function () {
              window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
          }, 0);
        });
      }
    }
    console.log(inputs.length + " input controls where edited to fix keyboard scrolling");
  }
}

If you are suddenly experiencing this issue after upgrading you may have similar code applied to your application.

In my case I added detection for version safari mobile 13 and only run the script for versions less than that.

Sebris87
  • 452
  • 5
  • 10