9

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 gets focus and native iOS keyboard become visible.

The 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:


UPDATE: the fix commit: limonte/sweetalert2/commit/4a2d36b

Limon Monte
  • 52,539
  • 45
  • 182
  • 213

5 Answers5

2

We are facing a similar issue at work, and I stumbled upon this question with your (excellent) demo page.

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 (this allows overflow: hidden to properly work).

However, this has the unattended 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, 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: One thing to note is that we didn't apply the fix to all devices/platforms blindly, just iOS Safari. I noticed in your other question that you weren't a fan of overflow: hidden due to the shifting of the page when the scrollbar appears/disappears (which I totally agree with). I would suggest just applying the JS to iOS devices only.

Community
  • 1
  • 1
Jack
  • 9,151
  • 2
  • 32
  • 44
  • 1
    Wow! Your demo is working! Finally working solution! You're the hero of my day :) Let me try to implement this solution into sweetalert2 in a nice way. For now vote-up, I'll accept your answer after testing. Thank you! – Limon Monte Oct 14 '16 at 10:00
  • 1
    what a terrible bug! and this is an awesome solution. I tried adding fixed to body but as you said it does scroll page to top. Looks really weird with transparent modal background. But the negative top works! Does anyone know if this bug also appears on android devices? – Nearpoint Jan 25 '17 at 02:44
0

On iOS I had trouble with scroll events caused by setTimeout and setInterval (position the modal causes scrolling?). I found a solution somewhere with the following code.

Function.prototype.bind = function(parent) {
  var f = this;
  var args = [];

  for (var a = 1; a < arguments.length; a++) {
    args[args.length] = arguments[a];
  }

  var temp = function() {
    return f.apply(parent, args);
  }

  return(temp);
}


setTimeout(function() {
  // your animation stuff here
}.bind(this), 100);
poashoas
  • 1,790
  • 2
  • 21
  • 44
  • 1
    This looks to me like a very dirty hack. Even if it works, I would not use it, [extending native objects is a bad practice](http://stackoverflow.com/a/14034242/1331425). – Limon Monte Sep 21 '16 at 22:05
  • @limonte You're right, but isn't the this function just "copying" itself? – poashoas Sep 21 '16 at 22:12
0

One thing I can think of here is to probably add the Fast Click library to your code. Some iOS and Android timeout issues like the 300ms delay are handled by Fast Click. It's worth a shot

nikjohn
  • 20,026
  • 14
  • 50
  • 86
0

Something else to check for is that the font size of the input field is above the minimum that will trigger a zoom on the input. I'm working from memory here, but I had a similar problem. Setting the input font size to 16px (again from memory) or more prevented iOS Safari from trying to zoom the input field and thus messing with the page scroll.

Brendon Muir
  • 4,540
  • 2
  • 33
  • 55
0

Resolved!!!!! Just please add those codes to your script

https://gist.github.com/kiding/72721a0553fa93198ae2bb6eefaa3299

//reach out to that input field (When ever u r gonna click tofocus)
let inputField = document.getElementById("input_focused")

 /*
 * Method 1: Briefly change the opacity.
 * Element might "blink" on focus in some scenarios.
 */
inputField.addEventListener("focus", () => {
      methodOne.style.opacity = 0;
      setTimeout(() => methodOne.style.opacity = 1);
    });
 <section id="modal">
    <input id="input_focused">
  </section>