javascriptselectors-api

Using querySelector to Find Descendant Elements Returns Unexpected Results


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


Solution

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