watt
watt

Reputation: 879

Mobile Safari sometimes does not trigger the click event

This is a dynamic JavaScript application I am working on. I have many <a> anchor elements that have a class. When that class is clicked, something should happen. This works fine in Firefox, Chrome, IE, but in some cases the click event is not triggered on mobile Safari (iPad and iPhone).

These elements all have exactly the same CSS, it's just their position that differs (they are in different containers).

I tried various solutions that I found here but with no luck. For instance:

Do you have any other idea that might help me find a solution to this? Why does the click event triggers only in some cases?

Upvotes: 30

Views: 49829

Answers (9)

Victoria Ventura
Victoria Ventura

Reputation: 1

This is mindblowing but what Benny K posted about underlying CSS causing reflow on hover fixed my issue!

I removed the following two tags from my CSS and it magically worked:

position: absolute;
z-index: 9999;

I'm still shocked but happy that it fixed the issue. Hope this helps someone else too.

Upvotes: 0

ion
ion

Reputation: 540

In my case the button had a :hover/:focus with a size changing property like border: 3px.

The small size change was enough to reflow the position and void the click.

It happened on mobile just because the space was limited.

Upvotes: 0

Benny K
Benny K

Reputation: 1237

Just spent an hour debugging another crazy scenario where Safari swallows taps as none of the tips above helped and the issue appeared seemingly out of nowhere.

tl;dr: if underlying CSS causes reflow on hover, bubbling won't reach the element where reflow happens.

Consider the following markup:

container
  div 
    span
    container.addEventListener('click', MouseClick, false)
span {opacity: 0;} 

div:hover {
    span {opacity: 1;}
 }

As a result, in mobile Safari on tap the div element won't receive a click event due to the fact that the first tap equals hover-like event and this triggers CSS reflow on the span (which is much smaller than div and is OUTSIDE of tap target coordinates). At the same time, there're other css hover events happening within the same div which does not cause lost clicks.

I was mindblown when narrowed this down to this CSS.. luckily it was added to codebase yesterday and was easy to track down, but holy web, Safari truly sucks to develop for.

Upvotes: 5

SinunHenkka
SinunHenkka

Reputation: 565

For me the behaviour was random. Everything worked fine, but after some changes really random problems with firing the click event of some buttons occured.

The problem was button hover with some mobile devices (Atleast some iOS iPads with Safari for me) And I fixed it with adding @media hover and pointer addition to all my hoverings:

@media (hover: hover) and (pointer: fine) {
    .topnav a:hover {
        background-color: lightcoral;
    }
}

This writing help me to figure this out (even I don't use react here) https://github.com/facebook/react/issues/7635#issuecomment-365089006

Upvotes: 2

xanobius
xanobius

Reputation: 158

There is an additional event for mobile devices. Try to add the tap event listener in addition to the click event. They can be attached simultaneously with the following:

$(document).on('click tap', [selector], [handler])

Upvotes: 5

gitaarik
gitaarik

Reputation: 46270

This is a crazy issue and indeed LinusR's answer and the description on quirksmode are accurate. My general click event listener didn't work because of this in iOS Safari:

window.addEventListener('click', function(event) {
    alert("Where's my click?!");
});

I now have wrapped my app with a <div onclick="void(0);"></div> and that works. I also added some extra things to fix some issues that came out of it:

<div onclick="void(0);" style="height: 100%; -webkit-tap-highlight-color: transparent;">
  <div style="height: 100%; -webkit-tap-highlight-color: initial;">
    <my-app></my-app>
  </div>
</div>

I needed the height: 100%; to make the click available on the whole page because I needed that. If you don't do height: 100%; the click event will still only fire within the height of the div.

The -webkit-tap-highlight-color: transparent; is to prevent an onclick flash overlay style, as iOS does this by default with clickable elements. The div after that restores the initial value of that CSS property, so that other clickable elements do have normal behavior in this regard. See this answer for more info.

Upvotes: 1

Yair Kukielka
Yair Kukielka

Reputation: 11396

Just declaring these empty event listeners does the trick. Just try it :)

This will make it work on all browsers:

container.addEventListener('touchstart', () => {});
container.addEventListener('touchend', () => {});
container.addEventListener('touchcancel', () => {});
container.addEventListener('touchmove', () => {});

Upvotes: 7

LinusR
LinusR

Reputation: 1209

The click event resulting from a tap on iOS will bubble as expected under just certain conditions -- one of which you mentioned, the cursor style. Here is another:

The target element, or any of its ancestors up to but not including the <body>, has an explicit event handler set for any of the mouse events. This event handler may be an empty function.

http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html

This is much better fix vector, and can be done without a browser check. You do have to add an extra div due to the "not including the <body>" part:

<body>
  <div onclick="void(0);">
    <!-- ... all your normal body content ... -->
  </div>
</body>

Now every click event originating inside that div will bubble as expected in iOS (meaning you can catch them with $(document).on('click', '.class', etc...)).

Upvotes: 39

Gopinath Koothaperumal
Gopinath Koothaperumal

Reputation: 398

Have you tried this?? This is because ios doesn't fire the click event sometimes, only recognizes the touch event

$(document).on('touchstart click', [Selector], [ Event ]

Upvotes: 7

Related Questions