So I've been playing around with querySelector recently and noticed some really odd behaviour when trying to select descendant elements.
Take the following markup as an example:
<div id="parent">
<div id="foo">
<div id="bar"></div>
</div>
</div>
If I want to query this DOM tree from the context of the #parent element, I may do the following:
var parent = document.getElementById('parent');
parent.querySelector('div')
This returns the #foo element as expected. Now, if I wanted to get the #bar element by only referencing tag names, I could do either of these:
var parent = document.getElementById('parent');
parent.querySelector('div div')
parent.querySelector('div > div')
Instead, both selector strings return the #foo element, not the #bar element? However, changing the contextual element (#parent) to a span fixes the issue? It seems as if the contextual element influences how it interprets the selector string. Alternatively, jQuery's selector engine performs as expected.
I created a CodePen that illustrated the problem.
I don't think this is a bug because the results are consistent in multiple browsers (I'm using Chrome 37). I suppose my question is; am I missing something? Is this part of the spec? Does anyone have an explanation for this behaviour?
Any insight would be appreciated, thanks, Ryan
Per the docs, "Selectors are evaluated against a given element in the context of the entire DOM tree in which the element is located."
That is, it's not a jQuery-style "find an element matching the selector path starting here".
#parent #foo
definitely matches div div
and div > div
, when viewed from the DOM tree level, per the spec.
It "works" when you change #parent
to a span
because #parent #foo
no longer matches div div
, and #foo #bar
is the new first match.