Question Details

No question body available.

Tags

javascript html dom

Answers (3)

Accepted Answer Available
Accepted Answer
August 5, 2025 Score: 1 Rep: 415,373 Quality: High Completeness: 50%

The element matches the selector string. It doesn't matter that the

that matches div:nth-of-type(2) is not a descendant of the starting node. When the is reached, it matches, and that's what counts. To put it another way, your CSS "test" is not valid, as the selector string you pass in to .querySelectorAll() is not the same as what's in your CSS.

Note that searching for only div:nth-of-type(2) matches nothing, because none of the descendant elements from "bbb" match that selector.

It's good that it works this way, if you think about it.

August 6, 2025 Score: 1 Rep: 139,863 Quality: Medium Completeness: 80%

Element#querySelector[All]() doesn't set the scope of the selector to the element on which it's been called, it only sets the scope of the tree from where to grab the elements to be tested. So the scope of the selector is still the root, and your selector is equivalent to

element :is(div:nth-of-type(2) span)

const parent = document.querySelector("div.bbb");
const elements = parent.querySelectorAll("div:nth-of-type(2) span");
console.log(elements.length);
div.bbb :is(div:nth-of-type(2) span) {
  border: 1px red solid; / now matches */
}

me

You can set the scope of the selector to the current element by prepending the :scope pseudo-class to your selector:

const parent = document.querySelector("div.bbb");
const elements = parent.querySelectorAll(":scope div:nth-of-type(2) span");
console.log("should not match", elements.length); // 0
const matching = parent.querySelectorAll(":scope div:nth-of-type(1) span");
console.log("should match", matching.length); // 1
div.bbb div:nth-of-type(2) span {
  border: 1px red solid;
}

me

And in modern browsers we can even use the newer & selector from CSS nesting:

const parent = document.querySelector("div.bbb");
const elements = parent.querySelectorAll("& div:nth-of-type(2) span");
console.log("should not match", elements.length);
const matching = parent.querySelectorAll("& div:nth-of-type(1) span");
console.log("should match", matching.length);
div.bbb div:nth-of-type(2) span {
  border: 1px red solid;
}

me

August 5, 2025 Score: 0 Rep: 8,402 Quality: Low Completeness: 60%

I think what the other answers are trying to say is that chaining query selectors in JavaScript is not the same as composing a CSS selector that uses descendant combinators. Which is to say this—

div.bbb div:nth-of-type(2) span { ... }

—is quite different than this:

document.querySelector('div.bbb').querySelectorAll('div:nth-of-type(2) span')

The former matches span elements that are descendants of div:nth-of-type(2) elements that are descendants of div.bbb elements.

The latter searches inside of a div.bbb element for span elements that are descendants of div:nth-of-type(2). But importantly, the div:nth-of-type(2) element that the span is a descendant of doesn't itself have to be a descendent of the div.bbb element—it can be an ancestor.

Another way to think of it is like this (even though this isn't the actual process being used): Your JavaScript is selecting all of the elements that match the div:nth-of-type(2) span selector, and of those, it's discarding all of the matches where the span isn't a descendant of the div.bbb element.