Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

92
Visualizações
Unexpected results using Element.querySelector

Given the following markup (I've only included the relevant part for the sake of brevity)

<ul>
  <li id="item">
    <a href="#foo">Stuff</a>
    <ul>
      <li> <a href="#foo">Foo stuff</a></li>
      <li><a href="#bar">Bar Stuff</a></li>
      <li><a href="#foobar">Foo-Bar Stuff</a></li>
    </ul>
  </li>
</ul>

Let's say that I have a reference to the li element with the ID of 'item' which I could get like this:

let item = document.querySelector('#item');

Now I need to retrieve the last anchor element within the nested ul list. For this I'm going to use the 'last-child' selector. This is what I initially tried:

let lastLink = item.querySelector('li:last-child > a');

I thought this would do the trick, but alas it actually returns the very first link in the markup ('Stuff'). I don't quite understand this as my base-element is already the 'item' element and I'm asking it to find the li element within that base-element which is the last-child of its parent and then return the a element from within it.

Indeed, if I do this:

let lastLink = item.querySelector('li:last-child');

It does actually return the last li element within the nested ul list, so why doesn't the first option work to simply get the 'a' element within that?

Here are some other things I tried which do work:

let lastLink = item.querySelector('#item li:last-child > a');

However, since I already have a reference to the base element it seems pointless to specify its ID here. These also work and return the correct a element:

let lastLink = item.querySelector('li ul li:last-child > a');
let lastLink = item.querySelector('li:last-child li:last-child > a');  

My question is, why doesn't the 1st option work? Appreciate if anyone can throw some light on the reason

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

Doing rootElm.querySelector(selector) essentially does:

for (const node of recursiveDescendantNodes) {
  if (node.matches(selector)) {
    return node;
  }
}

The selector is not broken down and analyzed to see if the first part of the selector starts lower than the root node - usually, all that specifying the root node does is indicate which descendants to search through.

Since the first <a> that points to #foo matches the selector passed, it's returned.

console.log(
  document.querySelector('#item > a').matches('li:last-child > a')
);
<ul>
  <li id="item">
    <a href="#foo">Stuff</a>
    <ul>
      <li> <a href="#foo">Foo stuff</a></li>
      <li><a href="#bar">Bar Stuff</a></li>
      <li><a href="#foobar">Foo-Bar Stuff</a></li>
    </ul>
  </li>
</ul>

There is a way to get around that behavior, though, by using :scope - which, in supported browsers, indicates "the element querySelector (or querySelectorAll) was called on", which is the functionality you're hoping to see.

let item = document.querySelector('#item');
let lastLink = item.querySelector(':scope li:last-child > a');
console.log(lastLink);
<ul>
  <li id="item">
    <a href="#foo">Stuff</a>
    <ul>
      <li> <a href="#foo">Foo stuff</a></li>
      <li><a href="#bar">Bar Stuff</a></li>
      <li><a href="#foobar">Foo-Bar Stuff</a></li>
    </ul>
  </li>
</ul>

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda