YUI Theater — PPK (Peter-Paul Koch): “JavaScript Events”

By Eric MiragliaApril 27th, 2009

PPK (Peter-Paul Koch) of Quirksmode.org

PPK (Peter-Paul Koch) of Quirksmode has been sharing his research into browser quirks for years, and this year he’s turned his attention to mobile browsers while doing a consultancy for Vodafone. That work has got him thinking about JavaScript events once again, and, as is his habit, the results of his research are freely available to the rest of us on Quirksmode (big-screen browser compatibility tables; mobile browser compatiblity tables).

PPK was in California last week and he was kind enough to visit Yahoo and deliver a tech talk outlining some of the interesting browser-event work he’s been doing. We’re happy to share that talk with you on YUI Theater. Slides from PPK’s talk are available in PDF form here.

PPK (Peter-Paul Koch): "JavaScript Events" @ Yahoo! Video

download (m4v)

In Case You Missed…

Some other recent videos from the YUI Theater series:

Subscribing to YUI Theater:

Transcript: PPK, “JavaScript Events”

Peter-Paul Koch: Thank you for inviting me, once again, to speak at Yahoo!. I’m PPK: Peter-Paul Koch, but everybody calls me PPK. It’s a long story. I run a site called http://quirksmode.org, where you can find information about browser incompatibilities. And I have a Twitter account, obviously — who doesn’t?

And today, here at Yahoo!, I’m going to talk about JavaScript events. And I sincerely hope I can teach you something. That’s always the question when I speak for a Yahoo! audience, because you guys already know so much, I have no idea what I can contribute to it. But anyway, we’re going to give it a try. I am going to talk about JavaScript events.

It was about a year ago that I started some serious research into JavaScript events, and I published some compatibility tables. What I basically was doing, was testing the compatibility of all the common events, in all the common browsers. And there’s several things surprised me in that research. Some of these things are what I’m going to talk about today.

If you don’t know where my compatibility table is, here at http://quirksmode.org/dom/events. Use it to look up some complicated events stuff that you want to know about.

Today, we’re going to talk about four things. First of all, I’m going to give a quick introduction to the key events, because there is some confusion, sometimes, about exactly how they work. Secondly, I’m going to talk about the change event. It’s one of my absolute favorite events in the whole of JavaScript – unfortunately, it hardly works, and I’m going to talk about that. Thirdly, I’m going to talk about delegating the focus event. Event delegation, you’ll probably know about that – I’m going to give a very short introduction later on. Event delegation usually only works with a mouse and key event, but I’ve found a way to have it work with focus, and other interface events too, and I’d like to share that with you. And finally, I’m going to present the first results of my test of mobile events – and the results are weird, I can tell you that already. I’ll show you that later on.

But first: the key events. It all seems so simple. There are three key events – keydown, keypress, and keyup. And people generally think they know exactly when they fire. I’m here to tell you that it isn’t always as clear as you think it is.

Let’s go through some quick definitions. The keydown event fires when a key is depressed by the user, and it keeps on firing as long as the user keeps it depressed. That’s simple. The keypress event, basically that’s the same, except that it fires only when a character key is depressed – in other words, a key that will lead to a character being inserted into, say, a textarea. Finally, the keyup event fires when the user releases the key. Well, that’s all pretty simple.

Just to make absolutely sure that everybody understands – if I press, say, an ‘o’ key, or an ‘i’ key, or one of these strange bracket keys, both a keydown and a keypress event will fire. On the other hand, if I press special keys such as the shift key, or the arrow keys, only a keydown event will fire.

This theory of the difference between keydown and keypress originated with Microsoft. All the Internet Explorer versions actually use this difference between keydown and keypress. And Safari has copied it, as from version 3.1, I think, which was released about a year ago, maybe slightly more. The point is, here, that this theory is the only theory about the difference between keydown and keypress in existence. In contrast, Opera and Firefox just fire lots of events at you all the time, because it is tradition that it is both a keydown and a keypress event, so we should fire both whenever we see an opportunity. Which is fine, but it doesn’t explain why there should be two events, instead of just one: the keydown event. So that’s why I kind of like this theory of the difference between keydown and keypress.

So, let’s repeat it once more. Keydown fires when a key – any key – is depressed. Keypress fires when a character key is depressed. And as we can see here, it works in IE, and in Safari. Oh, and I don’t have Google Chrome items here yet, but assume that anything that works in Safari also works in Google Chrome. They are really quite close, these two browsers.

OK, so let’s move on to some practical questions. Usually when you write a script that detects user keys, he wants to know which key the user pressed, and do some interesting interface stuff based on that.

Now, there are two properties that any key event carries – those are the keyCode, and the charCode properties. And there are also two bits of data you might want to know about – the key code, and the character code. And the difference is, the key code is the actual code of the physical key the user depresses, and the character code is the code of the resulting character. So, if I press an ‘a’ key, I get key code 65, because the ‘a’ key has the code 65. But the character code is 97, for a lower case ‘a’. If I press a shift key, I get key code 16, because that’s shift – but I do not get a character code, because the shift key, by itself, doesn’t result in any character. Well, that sounds simple.

So we have one property – we have, actually, two properties, and two bits of data. And having one property containing one bit of data, and the other property the other, would of course, be far, far too simple. It would mean that you don’t need a specialized content engineers, that anyone can just write a key script, which is obviously not the idea.

So, what exactly is going on? It’s pretty complicated, actually, and frankly, I do not understand entirely why it should work like this. But it does work like this. The keyCode property. With a keydown event, onkeydown, it contains the key code – the code of the physical key the user depresses. Onkeypress, on the other hand, contains the character code – basically, the ASCII code of the character that appears on the screen. And this works in all browsers – except that in Firefox, onkeypress shows zero for key code; don’t ask me why. Then, charCode. Onkeydown, charCode returns zero, and onkeypress, charCode returns the character code. And this, too, works only in Firefox and Safari, because these are the only browsers to support charCode.

Let’s move on to something really practical. If you need the actual key that the user depressed, the physical key, use the keydown event and ask for the keyCode. That will work in all browsers. On the other hand, if you needed the character the user has just entered in a text area, or whatever, you should use the keypress event, and ask for either keyCode or charCode – one of them will contain the information you’re looking for in the browser.

Finally, sometimes you want to prevent the default action of a key. I’m especially thinking of arrow keys. Suppose you have a keyboard accessible drag and drop menu, and then you want the user to be able to manipulate the drag element by the arrow keys, and you want to cancel the default of the arrow keys – namely, scrolling the page. Basically, you should do that onkeydown, because, as I said before, keydown fires when any key is depressed, and keypress only fires when character keys are being depressed. Unfortunately, this does not work in Opera – and I must admit I did not test it the latest Opera, so it might have changed there. And preventing arrow keys in Opera is something I’m not going to talk about today, because frankly I forgot the answer.

That concludes the key events. It is not really complicated, all those key events, but you have to be aware of the difference between keydown and keypress.

Now, the change event. In theory, the change event would be absolutely wonderful to have, because the change event fires when the value of the form field is changed. Often, you want to detect everything the user does in a form – for instance, onformsubmission, you of course want to go through all form fields and validate them. But there’s also ways of making a form – or form fields, checkboxes for instance – a kind of menu that the user can use to go through a complicated interface. And what you want to do, always, is see what, exactly, that the user changed in the form. And in theory, the change event would be absolutely wonderful for that.

But usually, we are forced to use the focus or blur events instead – or maybe the click event, in the case of detecting a checkbox changes – because the change event doesn’t work quite correctly. We’re to distinguish three different cases. First of all, the change event of text fields; second, on select boxes; and third, on checkboxes and radios.

We start with text fields. And I suppose the user focuses on a text field, in any way, either by the mouse or the keyboard, and then blurs again. In other words, he moves on to the next field. In that case, no change fires, because there’s nothing that has changed – the value of the text field has not been modified. But if we change it slightly – if we say the user focuses on the text field, and then enters something, then blurs the text field, then a change event fires at the moment the user blurs the text field. Because the value of the text field has been modified, and that obviously causes a change event. This is all good; this works perfectly in all browsers.

However, when we get to select boxes, we start to encounter some difficulties. The change event of select boxes is, of course, about the oldest JavaScript event you can think of. I think even back in ’95, ’96, we already used select box navigations – you know, with the nice list of links you can go to, and you put it in the select box because it takes up less screen real estate, stuff like that. We’ve been using the change event for ages, and it works, provided you use a mouse. With a mouse, it’s all pretty simple. The first click on the select box opens up all the options, and the second click selects a new option – and as soon as a new option has been selected, a change event fires, because the browser is now sure: OK, the user has changed the value of the form field. This works, as I said, from at least 1996 onwards. It works in all browsers.

Select boxes have also a way of…I’m sorry. The user also has a way to use the keyboard to enter select boxes, and then the situation gets much more complicated. Not at first – the first step the user has to take, obviously, is focusing on the select box. Then he can use the arrow keys to go through the options and select the one he wants. Which is all fine, except that as soon as the user presses an arrow key once, a change event fires in IE and Opera. And that is, of course, a huge problem. Suppose you have a list of, say, twenty options, and the user wants to select the twentieth one – then he has to go through the actual list option by option, presses the arrow key nineteen times, and a change event fires nineteen times. You do not want to write a work around for that. This is, as far as I’m concerned, a pretty serious bug in IE and Opera.

Instead, what should happen, and what Firefox and Safari actually do, is they just allow the user to use the arrow keys to scroll through the select box. And only when the user blurs the select box – in other words, says OK, I’m ready now, I’ve selected the option I want – only then a change event is fired. And this is, of course, the correct way of doing it. Still, the problem with IE means that select box navigations, or similar stuff, is pretty dangerous to write because it can misfire horribly when the user uses the keyboard. And that’s the first really, really serious problem we encounter with the change event.

When we come to checkboxes and radios it becomes even worse. I’m going to use a checkbox as an example, but it basically works the same for radios. A click on a checkbox – and I do not mean necessarily a mouse click, but an activate event can be fired either by the mouse, or by the keyboard. A click event on a checkbox, of course, changes the value of the check property – goes from true to false, or vice versa – and what should happen is that a change event fires right then and there, because the user has actually changed something. And a change event does fire in Firefox, Safari, and Opera, but not in IE.

What happens in IE? You click on this checkbox; nothing happens. What’s going on? You first have to blur the checkbox. You have to go somewhere else, either with your mouse or with your keyboard. And only when the checkbox has been blurred, then the change event fires. Which is, of course, totally horrible for any sort of interface that wants to use a lot of checkboxes – for instance, to fold stuff out or in, the user wants to check this checkbox, and immediately the thing he expects folds out, or folds in. And this IE bug means that we cannot use the change event for this – we have to use a click event. That’s not such a terrible problem, but it’s once again a pretty annoying bug in IE.

Oh, and you also see that I’ve crossed out the W3C logo. That’s because as far as I know, the event specification only talks about blurring, as according to the event specification, a change event should fire when a certain form field has been changed, and is blurred. And as we saw right now, that makes perfect sense for text fields; it makes perfect sense for select boxes when we used a keyboard; but it does not make sense for checkboxes or radios, or for select boxes when you use the mouse.

So this is a kind of a problem we’re having right now, and frankly I don’t see a really easy solution for it. Fortunately, we can usually get along with either the click events, or the focus or blur events. It’s not such a huge thing to work around. But still, I would love the change events to become really, really useful – because what we could do, then, is say OK, we’ve got this form here, and it has a text field, and it has select boxes, and checkboxes, and stuff. And any change event in the form will be detected by a central script, and some nice script will be executed. That would be absolutely wonderful, in my opinion, but we can’t do that right now, because of the problems I sketched here.

Our third subject, today, is event delegation. I’m absolutely sure that you all already know what event delegation is, but for the people at home, I’d like to give a very short introduction. Some slightly new material will come later on. Basically, event delegation is a way of defining less event handlers. And we take a dropdown menu as an example. Of course, a dropdown menu, in theory, would need a lot of event handlers – if you mouse over this, then that sub menu should drop down, etc, you know all that. What we do in event delegation is make use of the fact that many events bubble up. That is, as soon as the user mouse is over a link, the mouseover event, if any, on the link itself, fires – and then the event bubbles up all the way to the document level, triggers any event handler for the mouseover on the ‘li’, on the ‘ul’, etc, etc. All the way up to the document. The point here is the mouseover and the mouseout events will bubble up to the ‘ul’ anyway, so why shouldn’t we handle the event there? Basically, it saves you a lot of event handlers.

I once had a client who complained that his site was a bit slow, especially in IE. So I came there, I took a look at the code, and I discovered that they had this huge dropdown menu with 60 or 70 links or so, and every single link had its own mouseover, and mouseout, event. And yes, that makes your site a bit slower, because obviously all browsers have to allocate memory to every single event handle they encounter. Besides this, of course, the infamous IE memory leak – and of course this was in full force there, they did not do anything like removing the events when the page unloads . So they had a terrible mess there, and I taught them about events delegation – it really only took me ten minutes – and the site worked a lot better then.

So, basically what we do is we create a dropdown menu. The dropdown variable contains the ‘ul’, the top-level element of the dropdown. You assign one mouseOver, and one mouseOut event to that ‘ul’ – simple. And it works in all browsers, by the way.

But suppose somebody doesn’t use a mouse, but the keyboard. How shall we make the menu fold out then? And that brings us to the supremely important topic of device independence. Device independence is something I’m trying to explain to as many people as possible, because it’s just important. Back in the bad old days, we used to think that everybody used a mouse, and people who didn’t use a mouse were kind of the strange people, and we didn’t really have to pay attention to them. Fortunately, that has changed, and now we also want to accommodate our keyboard users. So basically, this does not work for people with a keyboard, because we use a mouse event.

Basically, the general rule is: any event that has mouse in its name, only works when you actually use a mouse. Sounds simple, but many people overlook that fact. So, we need events that tell us whether the user enters or leaves a link by means of the keyboard – and those are, of course, the focus and blur events. So, we would like to do this. We would like to say: OK, if the mouseOver events bubbles up, to the root of our dropdown menu, or if the focus event bubbles up to the root of our dropdown menu, then we execute this function. And given the mouseOut, or the blur event, execute that function. The problem is that this does not work, because the focus and blur events do not bubble up.

Which brings us to the question: which events do bubble up, and which events don’t? Basically, you should distinguish two kinds of events. First, the mouse and key events; and secondly, the interface events.

Mouse and key events are events that fire when the user initiates a device specific action. I’m still working on this definition, but this should be roughly correct. Basically, what the user does is either press a mouse key, or press a keyboard key, or move the mouse, or do something else, that is clearly associated with a specific device. Examples are mouseover, mouseout, click, keydown, keypress, etc. By the way, the click event is the only event that fires both with mouse, and with the keyboard. If you click on a link with the mouse, the click event fires; if you move to a link by means of tabbing until the focus is on the link, and then you hit enter or the spacebar, that the click event also fires. The click event is one of the very few events that is truly device independent. So, a click event is always safe. All the other events I mention here are device specific. And the general rule for these events is that they bubble up all the way to the document level.

Interface events, on the other hand, they fire when a certain event takes place, regardless of how that event was initialized. The best example of that is a form submission – as soon as a form is submitted, a submit event fires, and it does not matter exactly how the user has submitted that form. It could go to the submit button with the mouse, if I click on it, or chart all the way through the form to the submit button and hit enter, or be in a text field and also hits enter, because that also submits a form. It does not matter exactly how the user submits the form, which of these three methods he chooses – a submit event will always fire. And that’s the general idea of the interface events. Other examples include load, change, focus, and blur. And, of course, we are on the hunt for focus and blur here, because we want to make our dropdown menu device independent.

In general, interface events do not bubble. And that’s bad news for us, because if we want to make our dropdown menu keyboard accessible, we have to do this – we have to go through all the links in the entire dropdown menu, and add a focus and a blur event to it. And that’s not what we want to hear, because we want to use nice event delegation, that concentrates all the events on the top level of the dropdown menu. Fortunately – and this was a real surprise for me when I found this out – there is a work around. And that work around centers on event capturing, instead of event bubbling. Event capturing is the exact opposite of event bubbling. And it is supported in all standards complying browsers, which excludes IE, unfortunately. But we’ll get back to IE later on.

This is event bubbling, I already said that. If you click on the ‘a’, the event starts on the ‘a’, bubbles up to the ‘li’, to the ‘ul’, etc, etc, all the way up to the document level. Event capturing, on the other hand, starts at the document level and then moves its way down, through the ‘ul’, the ‘li’, and the ‘a’, and ends here. Now, in practice, there’s not terribly so much difference between event capturing and event bubbling. I myself would say that is really no difference at all, but when I said that to Dean Edwards, back in London, he said: oh, no, no, no! You absolutely need event capturing for certain situations. And of course I believe him, so event capturing does have its uses.

The point is – and this is a really strange point – that if you capture a focus event, event handlers on the target element’s ancestors are executed. And this was really weird for me. This works in all browsers – well, except for IE of course, because it doesn’t support event capturing. So basically, if we focus on a link while we use event bubbling, only the unfocused event handler of that link will fire, and that event will stop. But if we do the opposite, if we use event capturing, then the unfocused event handler of the documents, all the way down to the ‘ul’, the ‘li’, and the ‘a’ – they are all executed.

Why is there this difference between event capturing and event bubbling? I’m afraid I have absolutely no clue. I discovered it in… well, I think I was testing Opera at the moment, and I thought: OK, well it must be something specific to Opera. Interesting – let’s test it in Firefox. Hey, wow, it works there too. Safari – oh my God, it works there too. Is this something [that's] cross browser? And yes, it turns out to be an actual cross browser thing taking place. Which kind of led me to think that it maybe becomes fine to have event bubbling and event capturing act the same, because in my opinion, it doesn’t really make sense for events to be able to be captured, but not to bubble up. In any case, the current situation does not really make sense, but it’s pretty useful to our problem at hand, because we can now use event delegation for the focus and blur events too.

What we do, very simple, is this. We add an event listener – we use the actual add event listener syntax – and we give the last argument as true, which means that this event fires in capturing phase. Which means that as soon as any focus event occurs, anywhere in the dropdown menu, the event will first be captured by the ‘ul’, by the top level element, and this .mouseOver function will be executed. Don’t ask me why, but this is what happens.

Of course, because IE doesn’t support an event like this, we have to add a little bit. Which brings us to IE itself. IE doesn’t support event capturing – well, it does, there are some proprietary methods for it, but frankly I’ve never tested them, so I’m not sure how good they are. But fortunately, it supports the proprietary focusin and focusout events. Basically, these events are exactly the same as focus and blur, except that they do bubble up. So for IE’s sake, we add these two lines: dropdown.onfocusin, and dropdown.onfocusout. And now, magically, our events and delegation of the focus events, works in all browsers. So this is something you should know about.

By the way – the YUI team has already incorporated this into the library, so if you use YUI, you’ll have no problems at all, it will work fine. But if you’re working with another library, with some custom JavaScript code, this would be a useful trick to keep in mind. As far as I know, this works for all the interface events. This trick, the add event listener trick. However, IE does not always have a proprietary method that helps you out, as in the case of focusin, focusout. So you may run into IE problems, then.

Device independence. We have now successfully made our dropdown menu device independent, but of course there are more devices than just the mouse and the keyboard. Mobile phones – personally, I feel that after years, and years, and years of talk, especially marketing talk, the Mobile Web is finally coming. We now finally have phones that really and truly support good browsers, which in turn, support good HTML, CSS, and JavaScript – good enough to show actual sites on mobile phones. The user experience will absolutely be different from the user experience on the desktop computer, but I still think we should try to do our best to make our websites mobile phone compatible.

About two and a half months ago, I was contacted by Vodafone internet services group, and they asked me: hey, could you please help us out to test mobile browsers? And I said: yes, of course I can! Because frankly, I was already thinking, OK, the next obvious step for me is testing mobile browsers, but that would mean I have to buy, I don’t know, I’ve got an iPhone, but I need to have at least an Android, a Nokia, and maybe the new Palm Pre that’s coming. I thought, oh my God, this is going to cost me a lot of money. No, no, no, said Vodafone – no problem. We’ve got two closets full of mobile phones, and you can test them all if you want to. So I went over to Dusseldorf, in Germany, and yes – they showed me two closets full of mobile phones which I could test. I have not tested all those phones; I merely selected nineteen browsers on thirteen phones, which I am currently testing. Besides, I found out that my mother’s phone, the default browser on my mother’s new phone, is a very, very obscure browser named Obigo. So, of course I’m going to test that one too. I haven’t actually done so yet.

But thanks to this most generous offer by Vodafone, I’m now able to give you some information about JavaScript events on mobile phones. The subject remains terribly tricky, and I’m pretty sure that at least one thing I’m going to tell you right now will turn out to be totally false within a year. But I’m doing the best I can, and some information is better than no information at all.

Before we go to the actual events, we have to recognize that on mobile phones there are basically three input modes. The first input mode is, of course, touch, and I’ll assume most of you are familiar with a touch screen interface on a mobile phone. The second way is a cursor – or rather, a pseudo-cursor, as I call it. And the third way is – this is also the oldest way – the four-way navigation, which basically means you use the arrow keys to navigate through a website, and there is no cursor in view.

OK, let’s take a look at a few screenshots. This is the pseudo-cursor input in Opera Mini on the Nokia E71. Basically, most of the Nokias support a cursor, although I think you can turn it off as a browser handler. Anyway, this Opera Mini does not turn it off. Basically, what you do here is you use… These are the arrow keys, and you use it to steer the cursor across the screen. And when the cursor comes within, say, ten to fifteen pixels of one of the edges of the frame, the browser starts to scroll. The cursor moves in increments of about ten pixels or something And it can be very funny if you have an iframe within here, with scroll bars that are only three pixels wide, and you have to put the cursor exactly on the scroll bar in order to be able to move it. And I needed that in a certain tests I did, and it was not fun at all to try to do that in a couple of browsers. Anyway, most normal users will probably never encounter such a situation, but be very careful with iframes, especially scrolling iframes, on a mobile phone, please.

So, this is a pseudo-cursor. Here you see a typical four-way navigation. You don’t see the button, but it’s basically the same as on the previous phone. When you press the down key, I’ve just done so, and then the phone focuses on the next focusable element – which means a link, or a form field, basically. And it gives that link or form field a special highlight. If I would press the down key again, the focus would jump to the get elements by tag names, link here. And of course, if I click the middle button, this link is followed, and we go to the edit text script. If there is no link or form field within, say, one screen height’s worth of content, then an arrow down key will just scroll along. I think most of you will have seen this kind of interface on older mobile phones.

It can also be funny. This is also a four-way navigation phone, this is a NetFront browser on a Sony Ericsson. If I click on the large button here, which link do I follow? I have no idea either. I think some CSS misfires here, because these links are, of course, heavily styled. But on a totally unstyled homepage of my tests, this four-way navigation works fine. If I scroll down, it puts the highlight on every next link, and I can perfectly see where I’m going – except that, apparently, on this specific browser, on this specific phone, the highlight is overruled by use of CSS. This is only something you can find out by actually trying it. So it was terribly difficult for me to test this specific browser, because I have no idea, if I clicked, where I would go to. And I actually was unable to access at least one of my test pages, because I tried to scroll down, click – oh no, now it’s going to the wrong link. Back, which also takes awhile on a mobile phone. Scroll up a bit, click – oh, no, no, I’ve gone to the link above that. And I tried three or four times. And I thought, well, you know, never mind for NetFront’s 3.4 of Sony Ericsson’s K7701. I mean, the world can probably do without this bit of knowledge. Anyway, this is just an example of why testing mobile phones is not as easy as it may seem.

In such environments, where you cannot be sure whether the user touches the screen, or uses a pseudo-cursor, or four-way navigation – in such an environment, what does mouseover mean? What does mouseout mean, mousemove, mousedown, mouseup? And what about click? That’s what makes events research on mobile phones so terribly difficult. In the end, I decided on a simple test. I set up a test with a ‘div’, and specifically not a link or a form field, but a ‘div’. And I attached a lot of events to the ‘div’ – I tried to touch it, or go to it with a cursor, or four-way navigation, or whatever – and I just tried to see what happens.

And I will start with the good news. The good news is that the S60 WebKit browser – that is the default browser on all modern Nokias – acts exactly the same as any desktop browsers. If I move the cursor over the test element, mouseover and mousemove fire, while the :hover styles are applied to the element. If I click on the element, mousedown, mouse up, and click fire normally. And when I remove the mouse, mouseout fires, and the :hover styles are removed. This is exactly the same as in desktop browsers. And as far as I know, this is the only mobile browser that does exactly the same as desktop browsers – all other mobile browsers do it differently.

Let’s take a look at the Opera Mobile 9.5 on an HTC Touch Phone. This is a touch. Basically, the only thing I’m able to do here is actually touch the test element, because if I try to use my finger as a cursor and move over the element, it of course means I try the scroll the page. So that’s one of the problems I’m having. Basically, your finger is not equal to a cursor when you use touch phones. What happens here is that as soon as I touch the element, the :hover styles are applied, and all these events fire immediately, one after the other. Fortunately, this is the same as what the iPhone does, and I was very glad to notice that, because it makes at least a little bit easier to handle mobile events.

So, Nokia cursor phones behave exactly as desktop computers, while the latest Opera behaves exactly at the iPhone. Could also be the other way around – that the iPhone people have copied the Opera event model. I’m not sure. Anyway, we have to delve slightly deeper into this. What do the iPhone and Opera mobile phone do exactly? As soon as the user touches the element, the mouseover, mousemove, mousedown, mouseup, and click event fire, one after the other, immediately, and the :hover styles are applied. And when the user touches another element, the mouseout event on the old element fires, and the :hover styles are removed. This is about the best you can do on a touch screen, and the reason they included all these events is basically that so many websites around the world use these events. You have to be able to fire a mouseover event in a way that makes sense, because otherwise some interfaces will become unusable.

Now, the bad news. This is a Blackberry Storm with its proprietary Blackberry browser. I did the same test – I first touch the element… Oh, and the Blackberry Storm – or Blackberries in general, I’m not sure – have something unusual. They have a touch screen, but in order to actually click, you have to press the touch screen. And when I went over the element with my finger, the :hover styles were applied – you do not see that in the screen shot – and when I actually clicked on the element, mousedown, mouseup, and click fired, in the order. This is fine, this is fine – but I wasn’t able to get a mouseout, mouseover, mousemove event from this particular test. Pity. It can get worse, though.

This is a NetFront on the Samsung F700, again, a touch screen. Basically, it performed pretty badly – the only thing I was able to do was fire a mousedown and a mouseup event, when I clicked the test element. Where is the click event? I have absolutely no clue. Fortunately, this is the only browser I found that does not support click events. All other browsers do, as far as I know.

So these are only four of the nineteen browsers I tested, and there are hundreds of browser-mobile combinations in the mobile world. Right now, I’m being very cautious and conservative – if I test three S60 WebKits, or three different Nokias, I treat them as three different browsers. And I meanwhile, have become pretty certain that there is only one S60 WebKit browser and it works more or less the same on all S60 phones, but still, you have to be cautious. And there are some differences between one of my test phones and the three others, so I have to do some more research there. So this is only the tip of the iceberg I’ve shown you now, and more research is clearly necessary. None-the-less, I dare to give you three general rules for events on mobile phones. But please use your discretion when you apply them, because they may turn out to be wrong for certain elements.

The first one is: use the click event, and do not use the mouse events. Because the click event basically works, because it’s very simple – either you touch the element, or you click on the middle button, and that means click in almost any phone, except for the single NetFront on Samsung, that we saw. So this is the first rule. And in fact, I’m starting to think that it might become time to retire the mouse events altogether, from active duty. There are a few exceptions, obviously – the drop menu that we saw, it’s a sacred tradition that we use mouseover and mouseout events with a dropdown menu. Drag and drop might be another exception. But I think that there are not all that many interfaces that really need mouse events. So, I’m willing to consider not using mouse events at all, and maybe you should think about it too. It will probably not be possible for another one or two years, but it’s something we should think about, as frontenders.

General rule number two is: use the resize and the orientationchange event if you want to capture the orientation change of a phone. I’m not sure why you would be required to capture that event, because if you write your CSS well, your website will work in any orientation, obviously. But still, there might be unusual situations in which you do want to know – in that case, use both the resize and the orientationchange event. Orientationchange is supported only by the iPhone and the Blackberry, while resize is supported by all Operas and all WebKits. And yes, that means that the iPhone supports both events. NetFront, finally, does not support either event, which is too bad for NetFront, I’m afraid.

General rule three, finally: use key events with caution, and use them only to set general access keys. On many mobile websites that have been created in the past, you see that the programmers wanted to make it easy on people, so they said: OK, if you press one, you go back to the homepage; two, access the search menu; three, the main navigation, etc, etc. It’s the same as access keys, basically, except that on mobile phones it’s much, much, much more important than on desktop websites, because many mobile phones only have a numerical keypad. So, use key events for those general access keys, but do not use them for, for instance, reading out user input in a form field. Because some browsers simply do not fire the key events in such a situation, because they start up a special interface that takes over the entire screen, and allows the user to fill out text, and then when they press OK, they return to the website. And no key events fire in that special interface. Instead, just read out the form field’s value if you need it.

OK. We are close to the end of our presentation. Again, event compatibility for desktop can be found at: http://quirksmode.org/dom/events, while my mobile compatibility tables, which are very much a work in progress, can be found at: http://quirksmode.org/m.

Well, thank you so much for your attention. I hope you learned something today, and of course if you have questions, you can ask away right now, or either on Twitter, or my own site.

Thank you.

[audience applause]

[begin Q and A session.]

I’m asked if I could comment on the order of event firing between blur and change. I’m afraid I do not remember, off the top of my head, which event fires first, but I think it should be the blur event, because the blur events says, OK, the user blurs the textbox or whatever, now. And the change event comes later, and says, OK, and the user has changed something in the textbox. But again, I’m not sure the browsers actually do it in that way. But more in general, I would say that you should choose either event, and not use both. Because it just makes things far more complicated.

Did I test multiple select boxes? No, I’m afraid I did not. That’s one notorious gap in my event testing – I still have to do that. Because I have to feeling that multiple select boxes aren’t used very much. Or am I totally wrong on this? Who regularly uses multiple select boxes, here? Who regularly uses single select boxes, here? OK, so that’s the problem with multiple selects. But every time I say I don’t think multiple selects are used much, somebody jumps up to say, oh yeah, I do use them! So it’s a matter of taste, apparently. But no, I’m sorry, I don’t know.

OK, so the question is: if you want to test on mobile phones, but cannot afford to buy twenty to fifty mobile phones, how can you test them? Can you use emulators, for instance? I’m very, very concerned about emulators. As far as I know, there is not a single emulator out there that really, accurately, mimics the phone it’s supposed to emulate. I remember one case, it was ten years back, OK, but it always remains kind of a horror story for me. I was supposed to do some WAP research – this is really ten years back, when WAP was still supposed to be the new, cool technology – and said OK, you can download an emulator there. So I downloaded the emulator, started up, and yeah well – the website was kind of squeezed into the display. But then I did some random tests, and I figured out that they were just running the IE engine in the emulator, which didn’t make sense at all. Now, I’m absolutely sure that today’s emulators will be much better, and that the mobile phone vendors will try to actually run the correct code engine in the emulator, but still… I concede that it’s sometimes the best you can do. But you have to be very, very careful. Basically what we need is a kind of mobile test center or something, where people can go to and play around with mobile phones for a day, or something.

And I really, really advise everybody here, and everybody at home who has some way of getting their hands on more than one mobile device, to just sit down for a few hours and test stuff. Maybe create a little test page – it doesn’t have to be complicated – but just to get a feeling of how mobile phones work. And especially how they can mess up your sites. But there is no really, really good answer to your question about mobile testing. In the end, you do need a mobile phone. You do need several mobile phones. You do need twenty to fifty mobile phones to do a real good job.

The question is whether the iframe scrollbar problems also apply to a ‘div’. Yes, they do, basically. The problem with a ‘div’ for overflow:auto, is that the overflow:auto rarely works. Some browsers, notably the Opera mobile on HTC I showed you earlier, they do show a scrollbar, but it’s not actually usable. In general, scrollbars are pretty easy to use on touch phones, and hell to use on other phones. So, please, please do not use too many scrollbars in your websites – except, of course, for the general scrollbar of the entire bar. Because a single scrollbar is the only thing that mobile phones can actually work with.

The question is what I’m going to test more than events. Yes, I am – I’m actually already working on it. And you can look here: http://quirksmode.org/m – there are all the tests I’ve done to date. I haven’t really done a complete set of tests on events, or the CSS object model, or whatever. I’m just more like doing random tests.

Oh, and this is also a good point to mention – tomorrow, I’m going to speak at Google, also about mobile stuff, and they will also put it online eventually. And I kind of see the presentation I’m holding today, and the presentation I’m holding at Google tomorrow, as a kind of a unit, because I will answer some of your questions in that presentation. But yes, I am definitely going to test everything I can think of on mobile phones. The only problem is that it will take way longer than testing it on desktop computers. Because one of the problems I’m having is, OK, I’ve got eight mobile phones with me at home, and three of them have WiFi – which is really cool, because then I can actually test something immediately. And the other five, I need to insert a SIM card. Do you know what a SIM card is? Yeah, OK, cool. Because I’ve heard a rumor that Americans don’t use SIM cards…

[audience laughter]

…What? Woah. So the rumor’s false – great, wonderful. Anyway, Vodafone gave me only one SIM card. So basically, now I’m trying to get into a good test routine, especially because when you start with a Blackberry, it takes bloody ages to start up. It takes at least five minutes to start up. So, if I do my tests really right, I say, OK, SIM card goes into Blackberry, start it up. OK, now I take phone with WiFi support, and start testing on that. But sometimes I forget, and do the Blackberry last, and then I have to wait five minutes. So those are the little tricks you learn when you are testing mobile phones.

But I will try to test as many phones as possible. The only problem I’m having, right now, is that there are no really good statistics for mobile phone use. I suppose you’ve all heard that the iPhone accounts for 50% of the advertisement scene on mobile phones? The research was out, I don’t know, a month ago or something. Which is good to know, obviously. But first of all, that research only applied to smartphones, and not to feature phones – because we haven’t gone into the difference between smartphones and feature phones yet. Basically, feature phones are phones that you can’t write applications for; smartphones are the phones you can write applications for. It’s a bit more complicated than that, but that is the basic division. What was I going to say? Anyway, it’s complicated, let’s keep it at that. I’m basically trying to figure out which mobile phones are used most, around the world, and I don’t have the faintest idea. So I’m hoping to get some Vodafone statistics, which aren’t really there. So basically I’m doing some educated guesswork right now. I talk a bit with the Vodafone guys, of course – which phone do you think I should test? They give me some suggestions. But in the end, it’s just educated guesswork, I’m afraid.

Do the key events work well when you use a combination of keys? Let’s say the answer is no. I haven’t really tested it. It’s also… Do you mean on the normal desktop browsers? Oh, the normal desktop browsers! Yes, they do. They basically fire separate events for each key event that goes on. So if you press shift and then ‘a’, for a capital ‘A’, it first fires – now, I have to say this right – it first fires a keydown event on shift, which of course gives a keyCode of 16, and no character code, because there is no character. Then you press on ‘a’, and that fires a keydown and a keypress event, because it’s a character, and both the keyCode and the character code are 65. Because the keyCode of a key is always equal to the uppercase character code, in ASCII. So yes, that definitely happens.

Though, it might be useful in practice if you really want to detect, say, shift ‘a’ or something, to quietly forget about shift and concentrate on the ‘a’. Because you also have a property shift key, and alt key, and control key, which say OK, the shift key is now being pressed. And that property’s also true when you keep this shift key depressed, and press the ‘a’. So yes, you can definitely do that, but not on mobile phones, of course. That would be far too easy.

[The question is about] progressive enhancement on mobiles. One of the curious points I’ve found is that all mobile browsers support JavaScript. They may not support it very well, but basically… You can turn JavaScript off, as the user, of course.

Oh yeah, that brings me to another point. Basically, all the browser vendors of course want to have JavaScript turned on in their mobile browsers, because that makes their browsers better. But a browser vendor delivers a browser to a mobile phone vendor, who incorporates it into the mobile phone, and may change some settings just because they can. Then the mobile phone vendor sends the mobile phone, the hardware, over to the operator, because they basically mostly sell this stuff to the operators, who may also make some changes in the setting, because they can. So, all the phones I’ve tested so far have JavaScript enabled, but that may not be a fair comparison, because these are all test phones, and I have no way of knowing whether other people at Vodafone have a turn on JavaScript the first time they try to use the mobile phone. But progressive enhancement, I think, frankly, pretty much works the same as on desktop.

Audience member: But what about the variations between, say, CSS support, things like that? It seems like [inaudible] server side sniffing, [inaudible] or serving up to who there, kind of going against the grain.

PPK: Yes, yes. It kind of pains me to say so, but yes – I think we need some server side sniffing. For the moment, of course. And of course the noble goal of it all is to get rid of the server side sniffing as soon as possible. But yes, I’m afraid we are going to need that now, because as I will show in my Google presentation, you even have to test basic CSS level stuff like style italic. Style italic does not work in certain browsers in certain [phones]. So, that’s fun. But I think, right now, that the principles of progressive enhancement will remained the same. Basically, make sure your website works without JavaScript. And the only thing that’s of course really, really different, is the tiny display. But basically, some creative CSS will help you get around that.

One Comment

  1. I watched the video of your talk several times and found it excellent.

    Nicholas Zakas’ book (JavaScript for Web Developers mentions a number of other incompatibilities which you didn’t cover in the talk or in your book. For example, Opera (< 9.5) sets the keyCode for non-alphanumerics equal to the ASCII code and Safari (63000 for the arrow and page up/down keys.

    It would be great to see a really comprehensive list of all the bugs in one place.