iOS 7 Safari: OS locks up for 4 seconds when clicking/focusing on a HTML input

10,764

Solution 1

(There are some somewhat-effective solutions, see near the end of the list)

At my company we are also suffering from this. We filed an issue with Apple but have heard mum.

Here are some interesting jsfiddles to help illustrate some of the issues, it definitely seems to revolve around the number of hidden fields, and textareas do not seem to be affected.

From debugging efforts, my guess is that there is some functionality trying to detect if an input is a credit card or phone number or some special kind which seems to cause the locking behavior. This is just one hypothesis though..

Summary:

On a page with a form containing named input elements inside containers that are marked "display: none", the first press on an input in that form has a very noticeable delay (20sec-2min) between the keyboard coming up and the input being focused. This prevents users from using our web app due to the enormous time spent with the ui frozen waiting for the keyboard to respond. We have debugged it in various scenarios to try and discern what is going on, and it appears to be from a change in how iOS7 parses the DOM versus how it did on iOS6, which has none of these issues.

From debugging within Safari's Inspector with the iPad connected, we found that iOS7 provides much more information about the (program)'s activities, to the point that we found that _CollectFormMetaData is the parent of the problem. Searching for meta data causes massive churn that increases more than linearly along with the number of hidden containers containing inputs. We found that _isVisible and _isRenderedFormElement are called far more than they reasonably should be. Additionally, if it helps, we found some detection functions relating to credit cards and address books were large time consumers.

Here are some jsFiddles for illustration. Please view them in Safari on an iPad running iOS6 and then on an iPad running iOS7:

http://jsfiddle.net/gUDvL/20/ - Runs fine on both

http://jsfiddle.net/gUDvL/21/ - Just noticeable delay on iOS 7

http://jsfiddle.net/gUDvL/22/ - More noticeable delay on iOS 7

http://jsfiddle.net/gUDvL/29/ - VERY noticeable delay on iOS 7

http://jsfiddle.net/gUDvL/30/ - Same as 29 but with none hidden - no delay on iOS 7

http://jsfiddle.net/gUDvL/38/ - Same as 29 but further exacerbated

http://jsfiddle.net/gUDvL/39/ - 99 hidden inputs, one visible, one separately visible

http://jsfiddle.net/gUDvL/40/ - 99 hidden textareas, one visible, one separately visible

http://jsfiddle.net/gUDvL/41/ - 99 hidden inputs, one visible, one separately visible, all with the autocomplete="off" attribute

http://jsfiddle.net/gUDvL/42/ - 99 hidden inputs, one visible, one separately visible. Hidden by position absolute and left instead of display.

http://jsfiddle.net/gUDvL/63/ - Same as gUDvL/43/ but with autocomplete, autocorrect, autocapitalize, and spellcheck off

http://jsfiddle.net/gUDvL/65/ - Same as gUDvL/63/ but with cleaned up indentation (seems slower on iPad)

http://jsfiddle.net/gUDvL/66/ - Same as gUDvL/65/ but with display none via css again instead of DOMReady jQuery

http://jsfiddle.net/gUDvL/67/ - Same as gUDvL/66/ but with TedGrav's focus/blur technique

http://jsfiddle.net/gUDvL/68/ - Same as gUDvL/66/ but with css driven text-indent instead of display:block again (noticeable improvement - reduction to 2-3 secs for initial focus)

http://jsfiddle.net/gUDvL/69/ - Same as gUDvL/68/ but with TedGrav's focus/blur re-added

http://jsfiddle.net/gUDvL/71/ - Same as gUDvL/66/ but with js adding a legend tag before each input. (noticeable improvement - reduction to 2-3 secs for initial focus)

<input type="text" autocomplete="off" /> (links to jsfiddle.net must be accompanied by code..)

(We should note that having the iPad connected to a Mac with Safari's debugger engaged dramatically emphasizes the delays.)

Steps to Reproduce:

  1. Load any of the above jsfiddles on the iPad
  2. Press an input to gain focus
  3. Watch screen until you can type

Expected Results:

Expect to be able to type as soon as the keyboard pops up

Actual Results:

Watch the keyboard pop up and the screen freeze, unable to scroll or interact with Safari for a duration. After the duration, focus is given as expected. From then on no further freezes are experienced when focusing on inputs.

tl;dr technique summary

So overall there are a couple proposed fixes from various answers:

  • Don't hide the divs with display: none - use something like text-indent
  • Short circuit Apple's metadata scanning logic - many form tags or legend tags seem to do the trick
  • Auto focus/blur - Did not work for me but two people reported it did

Related threads at Apple:

https://discussions.apple.com/thread/5468360

Solution 2

There seems to be a problem with how IOS handles the touch-event for inputs and textareas. The delay gets larger when the DOM gets larger. There is however not a problem with the focus event!

To work around this problem you can override the touchend event and set focus to the input/textarea.

document.addEventListener("touchend", function (e) {  
     if (e.target.nodeName.toString().toUpperCase() == 'INPUT' || e.target.nodeName.toString().toUpperCase() == 'TEXTAREA') {  
         e.preventDefault(); 
         e.target.focus(); 
     } 
});

This will however create a new problem. It will let you scroll the page while touching the input/textarea, but when you let go, the site will scroll back to the original position.

To fix this, you just need to check if any scrolling has occured, and surround the preventDefault and target.focus with an if statement.

To set the original position, you can use the touchstart event.

document.addEventListener("touchstart", function (e) {
    ... //store the scrollTop or offsetHeight position and compare it in touchend event.
}

EDIT Me and a colleague have improved it a little bit, and it works like a charm.

var scroll = 0; 
document.addEventListener("touchstart", function (e) { 
    scroll = document.body.scrollTop; 
 });   

document.addEventListener("touchend", function (e) { 
    if (scroll == document.body.scrollTop) { 
        var node = e.target.nodeName.toString().toUpperCase(); 
        if (node == 'INPUT' || node == 'TEXTAREA' || node == 'SELECT') { 
            e.preventDefault(); 
            e.target.focus(); 
            if(node != 'SELECT') {
                var textLength = e.target.value.length; 
                e.target.setSelectionRange(textLength, textLength);
            }
        } 
    } 
}); 

Solution 3

Struggled with this issue as well within an ios fullscreen which was inserting /removing pages containing a single input element. Was experiencing delays up to 30 seconds with only a single visible text input element on the page (and within the entire DOM). Other dynamically inserted pages with single or multiple text inputs in the same webapp were not experiencing the input delay. Like others have mentioned, after the initial delay, the input field would behave normally on subsequent focus events (even if the dynamic page containing the input element was removed from the DOM, then dynamically re-rendered/inserted back into the DOM).

On a hunch based on the above behaviour, tried the following on page load:

$("#problem-input").focus(); $("#problem-input").blur();

While the above executes immediately with no delay, the end result is no subsequent delays when the input gets focus via user interaction. Can't explain the reason behind this working, but it appears to work consistently for my app while other suggested fixes have failed.

Solution 4

The main issue for me was with hidden fields. Made the form hang for 10-15 seconds.

I managed to get around by positioning the hidden form fields off the screen.


To hide:

position: absolute;
left: -9999px;

To show:

position: relative;
left: 0;

Solution 5

I have the same freezeing problem.

I am not sure we're in the same situation.

here is my demo:http://tedzhou.github.io/demo/ios7sucks.html

In my page, i use a <p> element with onclick attribute as a button. When user click on the button, page change to a textarea. Then a click on it will freezes the browser.

The time freezing spent relevent to the numbers of the dom elements. In my pages, there are 10000 elements, which make it freeze by 10+ seconds.

We can solve the problem by switching the <p> element to the real <button>, or reducing the nums of dom elements.

ps: sorry for my poor english. LOL

Share:
10,764
transformerTroy
Author by

transformerTroy

Updated on June 07, 2022

Comments

  • transformerTroy
    transformerTroy almost 2 years

    UPDATE: The issue seems to stem from having many select elements on a page. How random is that?

    So here's the issue. On iOS 7 Safari, when tapping the a text input on my site, the keyboard opens then freezes the OS for about 2-5 seconds then finally scrolls to the input. After this happens once, it never happens again until you refresh the page. I've looked all over the place, and yes, iOS 7 Safari is super buggy, but lets try and see if we can figure this out.

    Note: This does not happen in any other mobile browser or any previous iOS Safari. It happens both on the ios 7 iphone and ios 7 ipad.

    I will list everything my friend and I have tried so far:

    • Removed the ability to add event handlers in jQuery. (Note: all our event handlers are assigned through jQuery except for unload and onpageshow).
    • Removed the jQuery autocomplete script from the inputs.
    • Removed all JavaScript from the inputs.
    • Removed all third-party libraries being added on the page by rejecting the domains on the Mac.
    • Switched back to previous jQuery versions. The last one we could actually use before nothing worked was 1.7.0.
    • Switched back to previous jQuery UI versions.
    • Changed input event handling to delegate and live, instead of on('click')
    • Removed all CSS classes.
    • Removed all CSS from the page. Note: The response time for the OS this went down to 1-2 seconds but still happened.

    Does anyone have any ideas?

    Thanks a bunch!

  • c-smile
    c-smile over 10 years
    Interesting of course but even 1 sec delay for focus event is not an option. In our case we do not have that many selects but rather other focusable elements like hyperlinks, buttons, etc. And only few of them are visible and so focusable. Seems like Safari scans all DOM elements as focus candidates when it tries find focusable. target.
  • Raphael Isidro
    Raphael Isidro over 10 years
    also if the elements are somehow not visible the freezze time is bigger
  • Jasmine Hegman
    Jasmine Hegman almost 10 years
    No I do not as we filed it with a different developer's account that I do not have access too and he has not gotten back to me. As far as I know they were completely mum. We are still suffering from this issue and can easily recreate it with the latest 7.1.1 release. No word form Apple, many, many angry customers. I've since tried different combinations, like with autocomplete, autocorrect, autocapitalize, spellcheck, and novalidate attributes to no avail.
  • Jasmine Hegman
    Jasmine Hegman almost 10 years
    Great idea, it does not seem to work for us though. Could you check this jsfiddle? jsfiddle.net/gUDvL/67
  • Jasmine Hegman
    Jasmine Hegman almost 10 years
    This does make a noticeable difference to the speed, but does not completely ameliorate the issue. :(
  • Helen
    Helen almost 10 years
    I couldn't replicate the issue on the jsfiddles (ipad) but the legend tag work around reduced the page I was having issues with from ~4s delay to ~1s delay (on the same ipad as I tried the fiddles with).
  • Jorn van de Beek
    Jorn van de Beek almost 10 years
    Unfortunately in my case, this code makes all the inputs act very slow or even unresponsive at times.
  • Binke
    Binke almost 10 years
    @JornvandeBeek that's wierd. Thought this would work for everyone because it solved the problem for all of our apple devices. Only tried it on one site though. Maby you have some other code interfering with the touch events?
  • bdx
    bdx almost 10 years
    Adding the legend tag before all inputs was the most effective for my form. I have ~90 text inputs, due to pagination a majority is hidden at any one time. Delay is still definitely noticable, but it's in the realm of ~1s which means that by the time someone has started typing, it's responsive again.
  • Jorn van de Beek
    Jorn van de Beek almost 10 years
    That might be the case, so I removed the node == 'INPUT' || part to just make it do its magic on textarea and select nodes. In our case, the hanging was occurring dependably, but either on a select element or on a textarea element. In the end the code did not prevent hanging on a textarea in all cases, but after shuffling around that element a bit that was gone and it did alleviate hanging on an earlier select element.
  • ak85
    ak85 almost 10 years
    I had the issue with a large number of text input fields, a lot of them where hidden on load and you page through to undhide them. I found adding the legend by itself may have improved it but still caused a delay. However adding an autofocus to the first input field as well as a legend fixed the problem for me, I am now down from up to a minute to about 1/2 a second
  • Jasmine Hegman
    Jasmine Hegman almost 10 years
    @ak85 To clarify, when you say you added an autofocus to the first input - was that just the autofocus attribute or JavaScript triggering a focus event?
  • BruceHill
    BruceHill almost 10 years
    For me the situation was the opposite. I had a button with an onclick handler and there was a 10 second delay before the UI was active again after clicking on the button, even if the button just did an alert and nothing more. I replace the <button> with an <a> tag and returned false from the anchor onclick handler. After this change the hanging issue was resolved in the web application. I wish I knew more about what is causing this in iOS because it is a very annoying bug.
  • Umesh K.
    Umesh K. over 9 years
    Thanks Binke... This is simply Excellent work around :)
  • gateblues
    gateblues over 9 years
    This supports my findings in the profiler in Safari in debug mode. iPhone 4s connected via usb (issue not apparent in simulator) Significant time seen on these calls (not included in any javascript must be safari): _isRenderedFormControl _searchForLabelsAfterElement _searchForLabelsBeforeElement _matchesForElement _bestMatchForElement _addressBookLabelForElement _looksLikeMonthField _looksLikeCreditCardTypeField _looksLikeYearField _looksLikeCreditCardNumberField _looksLikeCreditCardCardholderField _looksLikeDayField _looksLikeSocialSecurityNumberField _looksLikeCreditCardSecurityCodeField
  • Tom
    Tom almost 6 years
    One thing worth noting is that the input and select elements don't need to be named to reproduce this issue. I can confirm this issue is still happening on iOS 11.