views:

690

answers:

7

The ultimate goal: pretty pages for mouse users, accessible pages for keyboard users. The effect I want is for clicking an anchor to produce no outline during and leave no outline after. Further, I want keyboard tabbing to move the focus and thus surround items with an outline. The following code works in FF (and I assume the other modern browsers, but I will have to test them tomorrow at the office), but not IE6-8. The problem lies in the fact that onmousedown doesn't seem to blur as expected:

var links = document.getElementsByTagName('a');
for (var i=0; i < links.length; i++) {
    links[i].onmousedown = function () {
        this.blur();
        return false;
    }
    links[i].onclick = function() {
        this.blur();
    }
}

One compromise would be if any one has a solution that can handle the case in IE where the user mouses down, mouses off the anchor, then mouses up, and leaves no outline behind would be a step in the right direction. Thanks.

EDIT: Friday, March 5th, 2010 My deepest apologies for taking so long to get back to this, but I needed a solution that worked in as many browsers as possible. Well, it turns out no timeouts are needed only some outline, class, and focus management. The following solution works in IE6+, FF2+, Safari 3+, and Chrome. I have not tested in Opera, but would love if someone could confirm/deny that it works. What follows is more suedo-code than pure js. I leave it as an exercise for the reader to implement in your favorite framework:

var anchorEventIsMouse = true;
$('a').mousedown(function() {
  anchorEventIsMouse = true;
  this.hideFocus = true;  /* IE6-7 */
  this.style.outlineStyle = 'none';  /* FF2+, IE8 */
  this.addClass('NoOutline');  /* see click func */
  this.setFocus();  /* Safari 3+ */
  });
$('a').keydown(function() {
  anchorEventIsMouse = false;
  });
$('a').blur(function() {
  this.style.outlineStyle = '';
  this.hideFocus = false;
  this.removeClass('NoOutline');
  });
$('a').click(function(e) {
  /* Adding class NoOutline means we only allow keyboard
   * clicks (enter/space) when there is an outline
   */
  if (!anchorEventIsMouse && this.hasClass('NoOutline')) {
    e.stopEventPropagation();
    }
  });
A: 

Try this css for your links:

<style>
  a {outline: none;}

  a:hover, a:active, a:focus {
      // styling for any way a link is about to be used
  }
</style>

More here:

http://css-tricks.com/removing-the-dotted-outline/

http://www.smashingmagazine.com/2009/10/14/css-differences-in-internet-explorer-6-7-and-8/

Sarfraz
This will remove the outline altogether, both for "mousing" and keyboard tabbing. The OP wants to keep the outline for the latter, though.
RegDwight
+1  A: 

I haven't tested it, but usually a delay sorts this sort of thing out:

var links = document.getElementsByTagName('a'); 
for (var i=0; i < links.length; i++) { 
    links[i].onmousedown = function () { 
        window.setTimeout(function () { this.blur(); }, 0);
        return false; 
    } 
    links[i].onclick = function() { 
        this.blur(); 
    } 
} 

The reason for this is, most events fire on the element before it actually gains focus. The timer delays the blurring until the thread is idle, thus focus will have been gained and can be blurred.

Some browsers support the CSS outline property, which will remove the focus outline if set to none, IE doesn't but you might be able to work out a none-js solution for those browsers.

EDIT Honestly, sometimes I don't know where my brain goes. It disappeared temporarily but it's back again. It didn't work for you because in a timer, this doesn't point to the target element correctly. You can fix it like so:

links[i].onmousedown = function () { 
    var self = this;
    window.setTimeout(function () { self.blur(); }, 0); 
    return false; 
} 

It can sometimes flicker the outline on before removing it though, so I would recommend using the hideFocus property to temporarily hide the outline during mouse events:

links[i].onmousedown = function () { 
    var self = this;
    this.hideFocus = true;
    window.setTimeout(function () { self.blur(); self.hideFocus = false; }, 0); 
    return false; 
} 
Andy E
Thanks Andy. I wanted so badly for this to work, unfortunately its still not working in IE.
Brett Pontarelli
@Brett Pontarelli: I'm sorry Brett, I had a funny turn and told you to use `this` inside a timer callback. See my edit for more info.
Andy E
Don't blur(). It's evil, and unnecessary!
porneL
A: 
$("a").click(function() {
     $(this).blur();
});
$("a").mousedown(function() {
     $(this).blur();
});

Try this ;)

Amad
I tried it just to see if jquery would work any magic. It doesn't work. It also requires that I load jquery into a page that only needs 10 lines a javascript.
Brett Pontarelli
Keyboard activation does trigger `click` event.
porneL
+2  A: 

DON'T USE blur()!

You don't need to nuke focus from the orbit just to tweak look of it.

In IE you can set hideFocus JS property to prevent outline from being drawn. Other browsers allow overriding via outline CSS property.

Just set those in mousedown handler. You could probably take advantage of event bubbling and do it from a single handler on body:

event.srcElement && event.srcElement.hideFocus=true; // IE
event.target && event.target.style.outline='none'; // non-IE

and if you want to support switching between keyboard and mouse, in mousedown attach blur handler that restores those to default (you'll need outline='' and closure over event target).

porneL
I see your point that using `blur` means the focus orbit is reset and on IE this is a problem, but FF seems to remember where it was and starts there. Either way, I fear the switching between keyboard and mouse will not work 100%. The moment you start setting `hideFocus` and `outline` properties you run the risk (e.g. mousedown, mouseout, mouseup on IE) of putting an element into a state that will show no outline during tabbing. I will have to look into your solution further to be sure.
Brett Pontarelli
I've noticed that there may be case when element gets mousedown, but not blur, so it might not be always cleaned up. Fix for this would be to use `mousedown` to set `focus` handler that removes outlines, and in `focus` handler add `blur` handler that removes the hack.
porneL
A: 

I have no idea if this will help but as nothing else works try setting the styling based on events rather than trying to trigger an event. If it's a mouseover (therefore a click) keep the underlining out, if it's a focus without a mouseover (keyboard use) then leave the underlining behaviour there.

This is another long shot, but it might be worth a try.

Joe Mills
A: 

This seems to work. Hiding the focus rectangle on page load and only enabling it if they use the TAB key. If they click on a link it turns off the focus rectangle again:

document.onkeydown = checktab;  
function checktab(e) {  
    var tabKey=9;
    var code=(e) ? e.which : window.event.keyCode;
    if(code==tabKey){
        showOutline(true);
    }
}

function showOutline(show){
    var links = document.getElementsByTagName('a');
    for (var i=0; i < links.length; i++) {
        links[i].style.outline=(show) ? '' : 'none';
        links[i].onmousedown = function () {showOutline(false);};
        links[i].hideFocus=!show;
    }
}

showOutline(false);
Wizard