Why your click events don't work on Mobile Safari

After ensuring that your newly created website works great on all desktop browsers, you put in the effort to make the site responsive. Everything is spot on with any of the Android browsers, but then you test on iOS/Mobile Safari and some of your click events aren't registering. Why is that? In my most recent project, I've encountered two different causes for this. Oddly enough, neither has anything to do with JavaScript, but CSS is the culprit. While one of them might be by design, the other is most definitely a bug, in my opinion. Since Mobile Safari is hell to debug (especially since in iOS 6, the developer console was removed and the only way to debug is by using desktop Safari, which isn't even available for Windows any more — probably a good thing, as the Windows versions were utter crap), it took ages to find the cause of this and I figured I'd spare you the trouble. Here's what happens and how to fix it.

#1 Adjacent input type=search

This just has to be a bug. It occurs under very specific conditions:

In that case, tapping the clickable element (whether that click is a JavaScript onclick handler, or just a simple <a href="...">) does not register. Instead, it applies the :hover style and only on the second tap does it navigate or run the JavaScript. Here's a minimal testcase. As far as I've seen, this happens only on Mobile Safari, so try it with an iPhone or somesuch. Changing pretty much anything will make the bug disappear, so all of these are valid workarounds:

#2 No event bubbling without a cursor style

This one may be as intended, but I still think it's a nasty one. For my project, I dynamically needed to add and remove certain elements that were not anchors, but were clickable. It would be inefficient to bind an onclick handler to each and every one of those elements, so instead, I used a handler on their container element and simply did a check in that. It is a popular construct in jQuery, too:

$('body').on('click', 'div.clickable', function(){ ... });

By virtue of event bubbling, the parent (<body> in the jQuery example) catches all child elements (<div class="clickable">) being clicked. Such a construct enables you have only 1 click handler for any number of matching elements without needing to bind them to each element individually. This works on every standards-compliant browser. Mobile Safari chooses to differ, however. It does not generate click events for elements that do not have either or both of:

Again, I've created a minimal testcase. Every browser I've encountered, other than Mobile Safari, will properly register clicks on both "buttons".

As an obvious workaround, either bind the onclick handler to each individual element or add a CSS rule: .clickable { cursor: pointer; }. This may be by design as a performance optimisation, but I do think it's rather bad form for behaviour mandated by the standard to be affected by purely presentational styles. The cursor isn't even visible on a touchscreen device!

Note: version used for testing was Mobile/10B329 Safari/8536.25, iOS version 6.1.3 on an iPod Touch, but I've seen it happen on iPhones too.

Pingbacks

Comments

Ben

I know this post is hardly recent, but I just wanted to thank you. After two hours of hunting for a solution, yours was the first post I found that explained what was going wrong.

The lack of event bubbling without a cursor style completely threw me - I couldn't work out where I had gone wrong as walking through my code was shedding no light on the issue. Mobile safari and chrome on iOS were both showing this behaviour. I believe it's because the browsers use the onClick attribute or the cursor property to decide whether non-natively clickable elements should generate a click event, but the inconsistency with desktop browsers caught me out.

Once again, thank you.

Mirza V U

Thanks a lot dearr... woRKED

Mark Churchill

I'm really glad you posted this. Props for sharing your findings!

Andre

Thank you so mutch for this post. You solved my problem.

filip

Thanks a lot man. Woooo hoooo !!! Thank you, thank you, thank you, thank you, thank you!

edward

You're God!. Thank you. I was pulling my hair with mobile slide out navigation menu working erratically. I removed :hover state from links and it fixed it. Thank YOU!

Ben Hirsch

Yes. Totally saved by this post. Thanks.

Sky

Thank you so much! You saved me many hours for figuring out why body on click not working on ISO.

Alex

Thanks for your thorough post. Tested on iOS 6.1 Hardware 10B141.

Jon Welker

Still relevant as of today in Chrome and Safari on an iPhone 6.

Gabriele Tiboni

I really really reall appreciate this article, it helped me found the solution of the problem, I've been looking for what was going wrong on safari from my mobile phone and couldn't find a solution, thank you so much for this. much appreciated. +1

Kyle

This was super helpful, #2 still happening on at least iPad Mini 2s and iOS 8.3

Chris

Folks -

Sort of off-topic, but I figured I'd give it a shot....

Do you have any idea why my basic input button (input type=email, etc) works in literally every browser, but is completely useless in Safari? I've tested with Yosemite and El Capitan....nada. Is there any logic to be had here, a command to run, a test to do, some bug that everyone knows about but me?

Would be most grateful for any thoughts -

Chris

Chris Dutrow

Had this issue in both mobile and Chrome and Safari.

For me, it happened under different circumstances, and unfortunately, the fixes above did not work in my case.

What did work was that I just turned the clickable element into a button element. Not sure this would work in all use cases, but might be helpful for some people.

Carry

You are a genius! Thank you! Adding the cursor: pointer; to my class fixed it, along with making sure the element had a width. It fixed it for both Chrome and Safari on iPhone 6s Plus (iOS 9.2) and iPhone 6 Plus (9.3.1).

David

Wow! I would've never come up with this solution. Thanks for posting this!

P

Late to this but THANK YOU!

Costa

I still can't get mobile Safari to respect my click events : (

I'm using a play-pause button, mute button, fullscreen and such for custom html5 video controls. Safari doesn't respect anything. Just the play button. And when I swap out the image of the pause for play, it shrinks my play button down reeeeeal tiny so it looks cute and harmless.

Makes me wanna punch an apple.

Michal

Thanks Steven! You saved me quite some time.

Wobbo

On some sites I need to use css "cursor:help". Only iOS it gave me a lot irritation... To solve this, change everything af the page to "cursor:pointer". That works for me.

jQuery:
if (/iP(hone|od|ad)/.test(navigator.platform)) {
$("*").css({"cursor":"pointer"});
}

Ash Menon

Oh my god, adding that cursor: pointer solved it!

Imagine. The solution is to add a cursor icon CSS rule, FOR A MOBILE BROWSER. Gah so annoyed right now, I could drop-kick a llama.

Thank you for this!

Dane MacMillan

I've never read of such a ridiculous set of circumstances causing a bug like this. I applied the advice from this post, and sure enough my problems were resolved. This one goes down in the history books.

Sebastian

Another way to get click´s to work on Safari is not to use <div> as a click target. Just use a an <a> for example. "Use a typically interactive element (e.g. <a>) instead of one that isn't typically interactive (e.g. <div>)." From MDN

Andy

Great post & great comments. I thought I'd add this, since nothing here quite worked for me.

function overlayClickHandler() {
console.log('Do stuff...');
}

["click", "touchstart"].forEach(function(event_type) {
document.body.addEventListener(event_type, overlayClickHandler, false);
});

Slakjejasper

That's incredible! Cursor pointer fixes the click bug...

Josh

This solution did not help me unfortunately, but I was able to figure out a solution. I had a toggle menu that didn't work well when it was clicked on in the mobile safari. The JavaScript was : window.onclick = function(event) { ......
once I changed it to window.HTMLButtonElement = function(event) {....
It worked fine.

Salakin

Thanks it works
it save my 12 hours :)

Struggling

Dealing with something similar. Only thing is that it works in all countries but not in but not in the UK. Any ideas?

Brad

Cursor: pointer. Brilliant. Thanks!!

rosebk

Hats off to your presence of mind..I really enjoyed reading your blog. I really appreciate your information which you shared with us.


https://www.besanttechnologies.com/training-courses/software-testing-training/selenium-training-institute-in-chennai

Brandi

I just want to tell you that the advice to remove the :hover feature fixed a problem I've spent over 13 hours trying to fix. Bless you.

dom

5 years on and still a life saver. cursour: pointer
to the rescue

Charles Robertson

I realise this article is now 6 years old, but I felt I really needed to thank you.

Bearing in mind, that when you wrote this article, we were using iOS6, I decided to test something on an iPhone 7, using iOS12.1.4, which is the most up-to-date version of Apple's Mobile OS.

So, my objective was to build a custom overlay that emulates the behaviour of an Angular Material overlay.

The scenario:

A user clicks on a menu icon and a menu panel slides out from the left. At the same time, an overlay appears behind the menu. Because the menu only slides out to three quarters of the width of the viewport, a thin strip of overlay is visible behind.

I added a simple "on('click touch','#overlay'..." event handler to the overlay, so that the menu has a way of closing.

On every other browser, apart from Mobile Safari, the event handler is fired successfully.

I spent hours changing the CSS & JavaScript, but to no avail. In absolute desperation, I did a Google search and came across your article. I decided that the "cursor: pointer;" fix looked like the most likely solution, but I have to say, I wasn't very hopeful, because of how old this article is.

To my utter amazement, this fix worked like a charm.

But, can you believe that Apple is still enforcing this rule, or even worse, has not fixed this potential bug.

Maybe, Apple's thinking behind this, is to do with accessibility?

Anyway, thanks once again for this great article. It has certainly stood the test of time.

wuzla

Just want to say thank you for cursor:pointer. This post helped me a great deal a couple years ago. Just found it again in my bookmarks.
I had built a navigation menu with hundreds of anchor tags that had submenus inside submenus that worked great on everything until I got to the iphone. Found the problem and because of you I had the solution implemented in under an hour.

Shashi Shekhar

Thank you so much for this.

After spending hours hunting for 'that bug' in event handler function, turns out the fix is in CSS. This article's a life saver.

Code Herb

The safe answer ;)

Post a comment