The iOS event cascade and innerHTML

From Friday until today I spent far too much time reverse-engineering iOS behaviour I was already supposed to be aware of. However, I also found a twist that hasn’t been documented so far — I think.

The behaviour I should already have known about was that during the touch event cascade, Safari iOS stops firing events when a DOM change takes place. The twist is that only DOM methods such as appendChild() count — but innerHTML does not.

Many thanks to Patrick Lauke for helping me out here and putting me on the right track.

The event cascade

When you touch an iPhone’s screen, in principle Safari responds by firing an entire event cascade:

  1. touchstart
  2. touchend
  3. mouseover
  4. mousemove
  5. mousedown
  6. mouseup
  7. click

I recently retested this, and it works. At least, it works in my old test script.

Content changes

The catch is, as Apple’s documentation states (see figure 6-4), that when a “content change” occurs in reaction to the mouseover or mousemove events, the other events are skipped. I was evidently aware of this rule when I created my old test script, since during the events it merely gathers data, while reporting the events (which implies DOM changes) takes place only when the event cascade is done.

Last week I created a new test case to study the effects of preventing the default ontouchstart and ontouchmove. But Safari acted weirdly and refused to show any event after mousemove. Meanwhile you’ll have guessed the cause: the script changes the DOM during the event cascade, which causes the content change rule to come into effect and stops the cascade. I had forgotten about it, and was stumped.

innerHTML change !== content change

Then Patrick Lauke came to the rescue and gave me a version of my script that worked. After playing with it for a while I found out that the reason it worked was that the script added the event names with innerHTML, and not with appendChild().

So evidently an innerHTML change does not count as a content change, though a formal DOM change does. That’s weird, and I would probably have taken a long time to figure that out. But Safari does many weird things when it comes to touch events.

(In case you’re wondering, a style change, either with className or with style doesn’t count as a content change.)


And why mouseover and mousemove? I don’t know, although I know that other browsers also treat these events differently. Android WebKit 4, for instance, fires them before the touchstart event in the cascade. Are these two cases related? Maybe. Perhaps these events are often used to ... well, do stuff that might upset touchscreen browsers and their event cascade. I’m just guessing here, and more research is clearly required.

And what about the mouseenter event? Patrick found that it only fires in specific circumstances. I haven’t studied it yet, but will in the future.

Anyway. With the content change bug squashed I have a test script and I’m actually ready to study the results of preventing the default actions ontouchstart and ontouchmove. Since I fly to London tomorrow for a conference, however, I’ll only get to it next week. Such is the life of a browser tester who forgets crucial rules.

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