• You are currently browsing the Christian Heilmann blog archives for June, 2009.

  • Archive for June, 2009

    TTMMHTM: Easy fixes for everything, Pirated HTML5, iPod vs. Walkman, Hubble data and Propaganda

    Monday, June 29th, 2009

    On password fields masking and Jakob Nielsen

    Friday, June 26th, 2009

    Jakob Nielsen just posted on alertbox that we should stop password masking (you know, showing asterisks or dots instead of showing the password while the user types it in.

    His argument is the following:

    Most websites (and many other applications) mask passwords as users type them, and thereby theoretically prevent miscreants from looking over users’ shoulders. Of course, a truly skilled criminal can simply look at the keyboard and note which keys are being pressed. So, password masking doesn’t even protect fully against snoopers.
    More importantly, there’s usually nobody looking over your shoulder when you log in to a website. It’s just you, sitting all alone in your office, suffering reduced usability to protect against a non-issue.

    Which makes me wonder when was the last time that Mr.Nielsen left his house to communicate with the real world. As a frequent traveller I am constantly seeing people logging into web sites in hotel lobbies (when they check in for their flight for example and enter their bonus miles account details), in Internet Cafes or when they use their laptop in a public space. While it is harder to spot the keyboard (especially with fast typers) there is no problem whatsover looking over their shoulder or – using my 10x optical zoom camera – even spot what they enter on the screen from across the room.

    However, password masking is not a 100% security measure but anyone working in security promising you a 100% security is nobody you should trust anyways.

    I do agree though that password masking can be very annoying on a mobile device, as is entering any form (my favourite bugbear is Opera Mini Uppercasing the first word I enter in any text field – no this is my user name, not a sentence).

    As I am changing my passwords every few weeks I do get confused from time to time, too, which is why I have written myself a GreaseMonkey script that adds a link to any password field that allows me to toggle its display:

    Password shower greasemonkey script by  you.

    This, in my book, should be a standard feature of browsers (or a convention we should start to follow when we design forms) – not showing sensitive information as readable text on a screen just because we don’t think anyone would ever watch us.

    Let’s also not forget that browsers deal with an input field with the type of password differently than with one that is text. For starters browsers do not collect previously entered information and offer them as options to autofill the field – something that would be terribly dangerous for passwords.

    TTMMHTM: Religion lulz, 60s computer labs, blind dogs and touchscreens, a new UK power plug and badass babies

    Thursday, June 25th, 2009

    Thinks that made me happy this morning:

    Chatting with ppk on mobile browser, standards support, testing, conferences and more

    Wednesday, June 24th, 2009

    Today PPK came to visit in our office in Covent Garden, London to talk to us about his research into mobile browsers and testing on
    mobile devices.

    PPK on mobile browsers by  you.

    I took the chance to take him out to lunch afterwards and have a quick chat about his findings, what he thinks about the usage of libraries, what we can do to advocate web standards better and many other things we thought necessary to discuss. Some of the things were interesting to mull over, for example if it really makes sense to test browser performance by creating 5000 LI elements or using every JS library in a single document embedded in IFRAMES.

    Here’s the half hour open interview for you to listen:

    Alternatively go to the archive.org site to download the audio for your mp3 player

    Sadly enough Audacity failed me and some of the interview got lost, but I thoroughly enjoyed chatting abot these topics and will continue doing these kind of quick interviews whenever someone comes over to talk.

    Creating accessible JavaScript menu systems – some basic steps that get forgotten

    Tuesday, June 23rd, 2009

    OK, so you want to write yet another collapsing menu/section/widget thingamabob. This is really easy and in the following few examples I want to point out some ideas that make it much easier for you.

    The following is what we’re going to build – it doesn’t have any bells and whistles like smooth animation, random unicorns, swoosh noises or whatever else you might want to come up with, but it is a good solid base to work from.

    Collapsing menu example by  you.

    Click the image to go to the live example.

    The Markup

    The first trick is to use easy to understand and highly styleable markup for your widget. You see a lot of widgets that use endless DIVs, SPANs, IDs on every element and classes on every sub-element. If you build a simple solution (and not a catch-all reusable widget that is part of a framework) none of that is needed. In this case the markup is the following:

    
    <ul id="menu">
    <li><h3>Section 1</h3>
    <ul>
    <li><a href="foo.html">Foo</a></li>
    <li><a href="bar.html">Bar</a></li>
    <li><a href="baz.html">Baz</a></li>
    </ul>
    </li>
    <li><h3>Section 2</h3>
    <ul>
    <li><a href="foo.html">Foo-1</a></li>
    <li><a href="bar.html">Bar-1</a></li>
    <li><a href="baz.html">Baz-1</a></li>
    </ul>
    </li>
    <li><h3>Section 3</h3>
    <ul>
    <li><a href="foo.html">Foo-2</a></li>
    <li><a href="bar.html">Bar-2</a></li>
    <li><a href="baz.html">Baz-2</a></li>
    </ul>
    </li>
    <li><h3>Section 4</h3>
    <ul>
    <li><a href="foo.html">Foo-3</a></li>
    <li><a href="bar.html">Bar-3</a></li>
    <li><a href="baz.html">Baz-3</a></li>
    </ul>
    </li>
    </ul>
    

    In other words: a nested list with headings for the different sections. This makes sense without styling or scripting which is still and important point considering mobile devices or environments that have JavaScript turned off (and yes, they are not mythical but do exist).

    Assistive access does not mean lack of JavaScript

    The first mistake that people do is to think that this is all you need to be accessible – as users with assistive technology have no JavaScript, right? Wrong. Assistive technology is not a browser replacement but in most cases hooks into browser functionality and offers easier access. In other words, what the browser gets the assistive technology gets and you have to make sure it still makes sense without a mouse (to name just one example).

    Thinking too complex

    The next extra step people take is starting to loop through the menu construct to hide the elements with JavaScript. This is made much easier with clever libraries that don’t use the DOM to do that but piggy-back on the CSS selector engine, but for good old IE6 this is still not an option. And you don’t need to. In order to hide the nested lists in the above example all you need to do is to apply a class to the main list and leave the rest to CSS:

    
    <style type="text/css" media="screen">
    #menu.js ul{
    position:absolute;
    left:-9999px;
    }
    </style>
    <script type="text/javascript" charset="utf-8">
    var m = document.getElementById('menu');
    m.className = 'js';
    </script>
    

    This means that in order to show any of the nested lists, all you need to to is to add a class called “open” to the parent list item. The CSS to undo the hiding is the following:

    
    <style type="text/css" media="screen">
    #menu.js li.open ul{
    position:relative;
    left:0;
    }
    </style>
    

    You can add the classes on the backend when you render the page – which makes a lot more sense to indicate a current open section of the page than any JavaScript analyzing of window.location or other shenanigans. See the first stage demo. You can also define a “current” class which means you can style it differently and the script will simply quietly skip that section and not collapse it at all.

    That is the beauty in leaving all the showing and hiding to the CSS. Of course you can’t animate in CSS (unless you use webkit), but you can make your animation precede the change in classes.

    Hiding and showing

    So the way to show and hide things is simply to add and remove classes. We need to use event handling to listen for click events to do that. Click events are the only safe ones as they fire with keyboard and mouse. The problem is that a header can be made clickable, but is not keyboard accessible. To work around this, let’s use DOM scripting to inject a button element into the headers. You can use CSS to make it look not like a button:

    
    <style type="text/css">
    h3 button{
    border:none;
    background:transparent;
    }
    </style>
    

    The second stage demo shows how this works and here’s the code.

    
    (function(){
    
    // get the menu and make sure it exists
    var m = document.getElementById('menu');
    if(m){
    
    // add a class to allow the CSS magic to happen
    m.className = 'js';
    
    // loop over all headers
    var headers = m.getElementsByTagName('h3');
    for(var i=0;headers[i];i++){
    // get the content of the current header
    var content = headers[i].innerHTML;
    // create a button, delete the content of the header
    // replace it with the button and set the content to
    // the cached header content
    var a = document.createElement('button');
    headers[i].innerHTML = '';
    headers[i].appendChild(a);
    a.innerHTML = content;
    }
    
    // apply a single click event to the menu
    m.addEventListener('click',function(e){
    
    // find the event target and chec that it was a button
    var t = e.target;
    if(t.nodeName.toLowerCase()==='button'){
    
    // get the LI the button is in
    var mom = t.parentNode.parentNode;
    
    // check if its class name is not content and
    // remove the open class if it exists, else
    // add an open class
    
    if(mom.className!=='current'){
    if(mom.className = 'open'){
    mom.className = '';
    } else {
    mom.className = 'open';
    }
    }
    
    // don't do the normal things buttons do
    e.preventDefault();
    }
    },true);
    }
    })()
    

    This code also takes advantage of event delegation – there is so no need to apply and event handler to each heading – even if that is really easy to do with a library and an each() or batch() command. Event handling is a great concept and the tricks you find when you bother to read the docs are staggering.

    Hiding is not removing

    This is where most menu scripts stop. Great stuff, it expands and collapses and everybody is happy. Unless you are an unhappy chap and you need to use a keyboard to access it – or an older mobile device. Try it out yourself – use the second example by tabbing from link to link. You’ll find that you have to tab through the invisible links to reach the next section to open or hide. That surely can’t be the idea, right?

    The trick to work around is to change the tabindex property of an element. A value of 1 will remove it from the tabbing order and setting it back to 0 will make them available again. So, to make keyboard access easier, let’s remove the tab order upfront and reset or remove it when we show and hide the menus. This is terribly annoying as we have to loop through the links. I hate loops, but browsers are not our friends.

    
    (function(){
    
    // get the menu and make sure it exists
    var m = document.getElementById('menu');
    if(m){
    
    // add a class to allow the CSS magic to happen
    m.className = 'js';
    
    // loop over all headers
    var headers = m.getElementsByTagName('h3');
    for(var i=0;headers[i];i++){
    // get the content of the current header
    var content = headers[i].innerHTML;
    // create a button, delete the content of the header
    // replace it with the button and set the content to
    // the cached header content
    var a = document.createElement('button');
    headers[i].innerHTML = '';
    headers[i].appendChild(a);
    a.innerHTML = content;
    }
    
    // loop over all nested lists
    // and set the taborder of the nested links to -1 to
    // remove them from the tab order
    
    var uls = m.getElementsByTagName('ul');
    for(var i=0;uls[i];i++){
    if(uls[i].parentNode.className!‘open’ &&
    uls[i].parentNode.className!==’current’){
    var as = uls[i].getElementsByTagName(‘a’);
    tabOrder(as,-1);
    }
    }
    
    // apply a single click event to the menu
    m.addEventListener(‘click’,function(e){
    
    // find the event target and chec that it was a button
    var t = e.target;
    if(t.nodeName.toLowerCase()===’button’){
    
    // get the LI the button is in
    var mom = t.parentNode.parentNode;
    
    // check if its class name is not content and
    // remove the open class if it exists, else
    // add an open class. Also, remove or add the
    // links to the tab order
    
    if(mom.className!==’current’){
    if(mom.className = 'open'){
    mom.className = '';
    tabOrder(as,-1);
    } else {
    mom.className = 'open';
    tabOrder(as,-1);
    }
    }
    
    // don't do the normal things buttons do
    e.preventDefault();
    }
    },true);
    }
    
    // remove from or add elements to the tab order
    
    function tabOrder(elms,index){
    for(var i=0;elms[i];i++){
    elms[i].tabIndex = index;
    }
    }
    })()
    

    The third demo does exactly that – use your keyboard and marvel at being able to tab from parent element to parent element when sub-sections are collapsed.

    Fixing it for Internet Explorer 6 and 7bad old browsers

    Now, this is all good and fine but of course we need to fix the code to work around the quirks of browsers that don’t understand the W3C event model or consider an element with a name attribute the same as one with and id. We could fork and fix in the code we have here, but frankly I am tired of this. People give us libraries to work around browser differences and to make our lives easier. This is why we can use YUI for example to make this work reliably cross-browser:

    
    <script type="text/javascript" charset="utf-8">
    (function(){
    var config = {
    'id':'menu',        // id of the menu
    'jsenabled':'js',   // class to add to apply design/functionality
    'show':'open',      // show the menu
    'current':'current' // current item (will not be collapsed)
    };
    var YE = YAHOO.util.Event, YD = YAHOO.util.Dom, YS = YAHOO.util.Selector;
    var m = YD.get(config.id);
    if(m){
    YD.addClass(m,config.jsenabled);
    tabOrder(YS.query('#'+config.id+' ul a'),-1);
    
    // set keyboard access for links in open sections - thanks David Lantner
    tabOrder(YS.query('#'+config.id+' li.'+config.current+' a'),0);
    tabOrder(YS.query('#'+config.id+' li.'+config.show+' a'),0);
    
    YD.batch(YS.query('#'+config.id+' h3'),function(o){
    var c = o.innerHTML;
    var b = document.createElement('button');
    o.innerHTML = '';
    o.appendChild(b);
    b.innerHTML = c;
    });
    YE.on(m,'click',function(e){
    var t = YE.getTarget(e);
    if(t.nodeName.toLowerCase()=’button’){
    var mom = YD.getAncestorByTagName(t,’li’);
    if(!YD.hasClass(mom,config.current)){
    var as = YS.query(‘ul a’,mom);
    if(YD.hasClass(mom,config.show)){
    YD.removeClass(mom,config.show);
    tabOrder(as,-1);
    } else {
    YD.addClass(mom,config.show);
    tabOrder(as,0);
    }
    }
    }
    },true);
    }
    function tabOrder(elms,index){
    for(var i=0;elms[i];i++){
    elms[i].tabIndex = index;
    }
    }
    })();
    </script>
    

    Good start

    This is just a start to make this work. A real menu should also have support for all kind of keys that a menu like this in a real app gives us and notify screen readers of all the happenings. For this, we need ARIA. Right now, I’d be happy to get some comments here :)