Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When exactly does the :active pseudo class get applied

I was trying to use querySelector to find active elements in a page. I assumed that a handler bound to a mousedown event on the document would trigger after the event had bubbled its way back from the target, which means the :active pseudoclass should already be applied.

document.addEventListener("mousedown",function(e){

    console.log(document.querySelector("*:active"));// logs null

    // expected value was the target of the mousedown event, that is,
    console.log(e.target);

});

My question is: at what point exactly does the the :active pseudo-class apply? Note that when I log the value, the mousedown event has already triggered on the target.

See http://jsfiddle.net/tK67w/2/ for an example. An interesting thing to note here is that if you set a breakpoint within the handler, you can see the css rule I defined for a:active already applying, although querySelector is returning null

EDIT:

Credit goes to TJ for coming up with a much better demonstration. The problem still stands though: in browsers other than IE and Chrome, how can I get an HTMLCollection of all active elements as they become active?

like image 263
Asad Saeeduddin Avatar asked Nov 04 '22 11:11

Asad Saeeduddin


1 Answers

I believe the issue is that as you're using querySelector, you're only getting the first active element. But your anchor is much further down the tree.

Update: Interesting, I'm not getting anything with Firefox or Opera, but I am with Chrome. The below are Chrome results. See more on that below.

Consider (live copy):

document.addEventListener("mousedown", handler, false);
function handler(e){
    console.log(
        "event " + e.type + ": " +
        Array.prototype.join.call(document.querySelectorAll("*:active")));
}​

When I click the anchor, I see this in the console:

event mousedown: [object HTMLHtmlElement],[object HTMLBodyElement],[object HTMLDivElement],http://fiddle.jshell.net/_display/#

Note the URL at the end, which is the default toString for HTMLAnchroElement instances, which is triggered by the join.

Since querySelectorAll is required to return the elements in document order, if you want the most specific active element, you'd use the last one. Example (live copy):

(function() {
    document.addEventListener("mousedown",handler, false);

    function handler(e){
        var active = document.querySelectorAll("*:active");
        var specific = active && active.length && active[active.length-1];
        display("Most specific active element: " +
                (specific ? specific.tagName : "(none)"));
    }

    function display(msg) {
        var p = document.createElement('p');
        p.innerHTML = String(msg);
        document.body.appendChild(p);
    }
})();
​

In my case (using Chrome), I see the tag name of the most specific element (the anchor if I click the link, etc.).


It seems like Chrome is following the spec and taht Firefox and Opera are not. From Section 6.6.1.2 of the CSS3 Selectors spec:

The :active pseudo-class applies while an element is being activated by the user. For example, between the times the user presses the mouse button and releases it.

It seems to me that :active should therefore apply in the above. This assertion is backed up if we use this CSS:

*:active {
    background-color: red;
}

...with this JavaScript:

(function() {
    document.addEventListener("mousedown", mouseDown, false);
    document.addEventListener("mouseup", mouseUp, false);

    function mouseDown(){
        var active = document.querySelectorAll("*:active");
        var specific = active && active.length && active[active.length-1];
        display("Mouse down: Most specific active element: " +
                (specific ? specific.tagName : "(none)"));
    }

    function mouseUp() {
        display("Mouse up");
    }

    function display(msg) {
        var p = document.createElement('p');
        p.innerHTML = String(msg);
        document.body.appendChild(p);
    }
})();

Live Copy

With all three browsers I tried (Chrome, Firefox, Opera), the element gets a red background while the mouse is down, and goes white again when I release it; but the mousedown handler doesn't see the :active element in Firefox or Opera, just Chrome.

But I'm not a CSS specification lawyer. :-)

like image 159
T.J. Crowder Avatar answered Nov 12 '22 20:11

T.J. Crowder