Mouse event bubbling in iOS

It’s that time again when I worry about the bubbling of mouse events on Safari iOS. Three years ago I did some research and a follow-up, and I found that the click event refused to bubble up to the body or higher in Safari iOS, unless some specific criteria were met. Today I repeated that research, and found the situation has changed.

Bubbling and the event cascade

Most events, including mouse events, bubble up. That is, if the user triggers a mouseover on an element, the browser sees if that element has an onmouseover event handler, and if so executes it. Then it does the same with all the element’s ancestors up to and including the document. This is standard behaviour that works everywhere — except in Safari iOS.

When the user touches a touchscreen, the browser reacts by firing a cascade of events that includes the touchstart and touchend events, all mouse events, and click. This is done for reasons of backward compatibility, and last week I retested this cascade to make sure it still works. It does.

So touching any element would trigger the mouse events, and all of them would subsequently bubble up to the document. This is what happens in all browsers except for Safari on iOS.

Safari’s oddities

With the help of this test page I found that Safari on iOS only allows the mouse events, including click, to bubble up in the following situations:

  1. The target element of the event is a link or a form field.
  2. 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.
  3. The target element, or any of its ancestors up to and including the document has a cursor: pointer CSS declarations.

This goes only for Safari iOS and only for the mouse events. The touch events always bubble up to the document even in Safari, and all other browsers allow all events to bubble up.

I also tested this in Chrome on iOS, and it obeys the same restrictions as Safari. That makes sense, since on iOS Chrome is forced to use Apple’s WebView, which is pretty close to Safari.

And no, I don’t understand it. The third situation, especially, ignores the difference between the CSS presentation layer and the JavaScript behaviour layer in addition to not making any sense at all.

I used to theorise that there was some kind of a performance drawback to allowing mouse events to always bubble up. But if that’s the case, why didn’t any of the other browsers implement the same restrictions? Besides, just checking if an element has an event handler isn’t that much drain on memory, processor, or battery, is it?

So I don’t understand why all this is the case, but it most certainly is the case. If you’re having bubbling problems, just add an empty-function event handler anywhere between the body and the element, and you’re set to go. But it shouldn’t be necessary.

This is the blog of Peter-Paul Koch, web developer, consultant, and trainer. You can also follow him on Twitter or Mastodon.
Atom RSS

If you like this blog, why not donate a little bit of money to help me pay my bills?