Click event delegation on the iPhone — redux

Last Tuesday I blogged about event delegation on the iPhone and concluded that the click event, contrary to all others, is not delegated upward unless you also give the element the user clicks on an onclick event handler (which may be empty).

Turns out this is not the whole story.

First Miller Medeiros published a test page where event delegation does work, although not at the document level. It turns out that the click event bubbles up fine, but for some reason stops before reaching the <body> element. Thus it never arrives at the document.

That confuses me mightily. In my first piece I theorised that the Safari team had disabled event delegation because of memory issues, but with Miller’s additional material it becomes clear that this theory cannot be true. If memory were the issue, why allow event bubbling within the <body>?

So my nice theory is wrong. But I still have no clue why the bubbling stops just below the <body> level.

Then Jimmy Byrum published a test page that is exactly the same as my original one, except that he added cursor: pointer to the clickable div. Lo and behold: the div is clickable and the event bubbles up absolutely fine.

Go. Figure. I would absolutely never have even considered doing CSS tests for what is obviously a JavaScript problem. I get dizzy of Apple’s careless mixing of the CSS presentation and JavaScript behaviour layers.

Apparently, setting cursor: pointer is taken as evidence that you want an element to be clickable. There’s something to say for that. But I don’t think the CSS presentation layer should influence the JavaScript behaviour layer. Obviously, the Safari team disagrees with me.

Occasionally you encounter browser bugs that just defy any rational explanation. This is one of those times.

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?



Comments are closed.

1 Posted by Emil Björklund on 1 October 2010 | Permalink

I remember reading about something perhaps associated with this over on Robert Nyman's blog:

Random thought, without really having gone into the whole problem: could it be some kind of clickjacking-prevention?

2 Posted by Rik on 1 October 2010 | Permalink

Maybe that's something they decided in order to get compatibility with the existing web pages when they first launched the iPhone?

3 Posted by ppk on 1 October 2010 | Permalink

Rik: Definitely not. Event delegation has been supported ever since Netscape 4.

Emil: I don't think there's any relation. pointer-events is about a visually stacked bunch of elements, while I'm testing simple DOM-centric event delegation.

But who knows, you might be right after all.

4 Posted by Jason Johnston on 1 October 2010 | Permalink

Here's my theory:

Good touch interfaces have to build in a certain amount of tolerance for the fact that fingers are fat and inaccurate. So when you tap on a webpage, the actual tap location your finger hits may be slightly outside of the actual link/button/etc. you are trying to click, but the interface should correct that for you to a certain degree. Magnetism if you will.

Apple's team realized this so they added in some tolerance: when you tap on a page, they check if there are any "clickable" elements within a certain distance of the actual tap point, and if so then they dispatch a click event to that element.

So they had to introduce the concept of certain elements that are "clickable" versus "normal" elements which are not, which is a distinction not present in desktop browsers. By default in mobile Safari this appears to include links, buttons, form controls, etc. It also includes anything that has an explicit click event listener attached to it (except, apparently, the body element, which explains why Miller's test case works.) And apparently cursor:pointer is yet another cue.


5 Posted by Jason Johnston on 1 October 2010 | Permalink

So it's not that "the bubbling stops" before the click event reaches the body, it's that if you only attach a click listener to the body element then no click event is dispatched to begin with. I can't test it right now, but I seem to remember if you attach click listeners both to the body and to a descendant, then the body will properly catch the bubbling event dispatched on the descendant.

The act of attempting to observe the event itself changes the conditions of the test... web development has gone quantum! ;)

Now, if this is indeed the reasoning behind it, I'm not convinced mobile Safari's behavior was the only way to do it. It seems to me that instead of making elements either clickable or non-clickable, they could have just made the clickable elements more magnetic. So if you tap near a magnetic element the click event will be dispatched to that element, but if not then a click event will still be dispatched at the location of the tap. Perhaps that's how other mobile browsers do it.

6 Posted by GreLI on 1 October 2010 | Permalink

iPhone Safari Webkit is open-source, isn't it? Maybe it is possible find the reason in the code/comments/bugtracker?

7 Posted by Thomas Traub on 3 October 2010 | Permalink

I stumbled over a Apple proprietary CSS attribute 'pointer-events', maybe it's related, couldn't get it working, see Apple Safari CSS Reference: