Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I remove focus onmousedown in IE?

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();
    }
  });
like image 480
Brett Pontarelli Avatar asked Feb 05 '10 07:02

Brett Pontarelli


2 Answers

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).

like image 127
Kornel Avatar answered Sep 29 '22 09:09

Kornel


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; 
} 
like image 43
Andy E Avatar answered Sep 29 '22 10:09

Andy E