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.
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.
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:
<body>, has an explicit event handler set for any of the mouse events. This event handler may be an empty function.
cursor: pointerCSS 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.
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.
If you like this blog, why not donate a little bit of money to help me pay my bills?