Weird behaviour when using querySelector The 2019 Stack Overflow Developer Survey Results Are In Unicorn Meta Zoo #1: Why another podcast? Announcing the arrival of Valued Associate #679: Cesar Manara The Ask Question Wizard is Live! Data science time! April 2019 and salary with experienceWhen are you supposed to use escape instead of encodeURI / encodeURIComponent?When to use double or single quotes in JavaScript?How to execute a JavaScript function when I have its name as a stringChange the selected value of a drop-down list with jQueryWhat is the purpose of the var keyword and when should I use it (or omit it)?How to decide when to use Node.js?What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?Get current applied style with JSRunning JavaScript function to gives “Uncaught SyntaxError: Unexpected token }”Accessing elements from HTML in JavaScript

What happens to a Warlock's expended Spell Slots when they gain a Level?

1960s short story making fun of James Bond-style spy fiction

Why are PDP-7-style microprogrammed instructions out of vogue?

What do I do when my TA workload is more than expected?

should truth entail possible truth

How to type a long/em dash `—`

Does Parliament hold absolute power in the UK?

Can I visit the Trinity College (Cambridge) library and see some of their rare books

What information about me do stores get via my credit card?

How did the audience guess the pentatonic scale in Bobby McFerrin's presentation?

My body leaves; my core can stay

how can a perfect fourth interval be considered either consonant or dissonant?

US Healthcare consultation for visitors

Is an up-to-date browser secure on an out-of-date OS?

Do I have Disadvantage attacking with an off-hand weapon?

The following signatures were invalid: EXPKEYSIG 1397BC53640DB551

Are there continuous functions who are the same in an interval but differ in at least one other point?

Didn't get enough time to take a Coding Test - what to do now?

Make it rain characters

For what reasons would an animal species NOT cross a *horizontal* land bridge?

"... to apply for a visa" or "... and applied for a visa"?

Do working physicists consider Newtonian mechanics to be "falsified"?

"is" operation returns false even though two objects have same id

Python - Fishing Simulator



Weird behaviour when using querySelector



The 2019 Stack Overflow Developer Survey Results Are In
Unicorn Meta Zoo #1: Why another podcast?
Announcing the arrival of Valued Associate #679: Cesar Manara
The Ask Question Wizard is Live!
Data science time! April 2019 and salary with experienceWhen are you supposed to use escape instead of encodeURI / encodeURIComponent?When to use double or single quotes in JavaScript?How to execute a JavaScript function when I have its name as a stringChange the selected value of a drop-down list with jQueryWhat is the purpose of the var keyword and when should I use it (or omit it)?How to decide when to use Node.js?What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?Get current applied style with JSRunning JavaScript function to gives “Uncaught SyntaxError: Unexpected token }”Accessing elements from HTML in JavaScript



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








26















As my understanding, when using element.querySelector(), the query should be start on particular element.



However, when I run using code below, it keep selected the first DIV tag in particular element.






const rootDiv = document.getElementById('test');
console.log(rootDiv.querySelector('div').innerHTML);
console.log(rootDiv.querySelector('div > div').innerHTML);
console.log(rootDiv.querySelector('div > div > div').innerHTML);
console.log(rootDiv.querySelector('div > div > div > div').innerHTML);
console.log(rootDiv.querySelector('div > div > div > div > div').innerHTML);

<div>
<div>
<div id="test">
<div>
<div>
This is content
</div>
</div>
</div>
</div>
</div>





As you can see, the first few results is the same.
This this a bug? Or it will query from start of the document?










share|improve this question






























    26















    As my understanding, when using element.querySelector(), the query should be start on particular element.



    However, when I run using code below, it keep selected the first DIV tag in particular element.






    const rootDiv = document.getElementById('test');
    console.log(rootDiv.querySelector('div').innerHTML);
    console.log(rootDiv.querySelector('div > div').innerHTML);
    console.log(rootDiv.querySelector('div > div > div').innerHTML);
    console.log(rootDiv.querySelector('div > div > div > div').innerHTML);
    console.log(rootDiv.querySelector('div > div > div > div > div').innerHTML);

    <div>
    <div>
    <div id="test">
    <div>
    <div>
    This is content
    </div>
    </div>
    </div>
    </div>
    </div>





    As you can see, the first few results is the same.
    This this a bug? Or it will query from start of the document?










    share|improve this question


























      26












      26








      26


      2






      As my understanding, when using element.querySelector(), the query should be start on particular element.



      However, when I run using code below, it keep selected the first DIV tag in particular element.






      const rootDiv = document.getElementById('test');
      console.log(rootDiv.querySelector('div').innerHTML);
      console.log(rootDiv.querySelector('div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div > div > div').innerHTML);

      <div>
      <div>
      <div id="test">
      <div>
      <div>
      This is content
      </div>
      </div>
      </div>
      </div>
      </div>





      As you can see, the first few results is the same.
      This this a bug? Or it will query from start of the document?










      share|improve this question
















      As my understanding, when using element.querySelector(), the query should be start on particular element.



      However, when I run using code below, it keep selected the first DIV tag in particular element.






      const rootDiv = document.getElementById('test');
      console.log(rootDiv.querySelector('div').innerHTML);
      console.log(rootDiv.querySelector('div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div > div > div').innerHTML);

      <div>
      <div>
      <div id="test">
      <div>
      <div>
      This is content
      </div>
      </div>
      </div>
      </div>
      </div>





      As you can see, the first few results is the same.
      This this a bug? Or it will query from start of the document?






      const rootDiv = document.getElementById('test');
      console.log(rootDiv.querySelector('div').innerHTML);
      console.log(rootDiv.querySelector('div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div > div > div').innerHTML);

      <div>
      <div>
      <div id="test">
      <div>
      <div>
      This is content
      </div>
      </div>
      </div>
      </div>
      </div>





      const rootDiv = document.getElementById('test');
      console.log(rootDiv.querySelector('div').innerHTML);
      console.log(rootDiv.querySelector('div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div > div').innerHTML);
      console.log(rootDiv.querySelector('div > div > div > div > div').innerHTML);

      <div>
      <div>
      <div id="test">
      <div>
      <div>
      This is content
      </div>
      </div>
      </div>
      </div>
      </div>






      javascript






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Apr 8 at 9:00









      Abana Clara

      1,7351020




      1,7351020










      asked Apr 8 at 7:27









      Joey ChongJoey Chong

      1,0571116




      1,0571116






















          3 Answers
          3






          active

          oldest

          votes


















          24














          What querySelector does is it finds an element somewhere in the document that matches the CSS selector passed, and then checks that the found element is a descendant of the element you called querySelector on. It doesn't start at the element it was called on and search downwards - rather, it always starts at the document level, looks for elements that match the selector, and checks that the element is also a descendant of the calling context element. It's a bit unintuitive.



          So:



          someElement.querySelector(selectorStr)


          is like



          [...document.querySelectorAll(selectorStr)]
          .find(elm => someElement.contains(elm));


          A possible solution is to use :scope to indicate that you want the selection to start at the rootDiv, rather than at document:






          const rootDiv = document.getElementById('test');
          console.log(rootDiv.querySelector(':scope > div').innerHTML);
          console.log(rootDiv.querySelector(':scope > div > div').innerHTML);
          console.log(rootDiv.querySelector(':scope > div > div > div').innerHTML);

          <div>
          <div>
          <div id="test">
          <div>
          <div>
          This is content
          </div>
          </div>
          </div>
          </div>
          </div>





          :scope is supported in all modern browsers but Edge.






          share|improve this answer

























          • Neat trick! Thanks!

            – Tico
            Apr 8 at 7:35











          • :scope is not supported by all but most of the major browsers. Anyways, thank for explanation and this should be the answer. Thanks.

            – Joey Chong
            Apr 8 at 7:44












          • :scope doesn't work with IE and Edge, I think it's important to point this out

            – Cristian Traìna
            Apr 8 at 7:47











          • Here is the browser compatibility table - we have to resist just few months more since Edge is implementing Chromium engine :P

            – Cristian Traìna
            Apr 8 at 7:47












          • Do you have any sources for the browser engine actually working this way ? - The query would have the same result, if the engine would start with the first div and check if it matches the query selector...

            – Falco
            Apr 8 at 11:17


















          6














          The currently accepted answer somehow provides a valid logical explanation as to what happens, but they are factually wrong.



          Element.querySelector triggers the match a selector against tree algorithm, which goes from the root element and checks if its descendants do match the selector.



          The selector itself is absolute, it doesn't have any knowledge of a Document and doesn't even require that your Element be appended to any. And apart from the :scope attribute, it doesn't either care with which root you called the querySelector method.



          If we wanted to rewrite it ourselves, it would be more like



          const walker = document.createTreeWalker(element, 
          NodeFilter.SHOW_ELEMENT,
          acceptNode: (node) => return node.matches(selector) && NodeFilter.FILTER_ACCEPT
          );
          return walker.nextNode();





          const rootDiv = document.getElementById('test');
          console.log(querySelector(rootDiv, 'div>div').innerHTML);

          function querySelector(element, selector)
          const walker = document.createTreeWalker(element,
          NodeFilter.SHOW_ELEMENT,

          acceptNode: (node) => node.matches(selector) && NodeFilter.FILTER_ACCEPT
          );
          return walker.nextNode();
          ;

          <div>
          <div>
          <div id="test">
          <div>
          <div>
          This is content
          </div>
          </div>
          </div>
          </div>
          </div>





          With the big difference that this implementation doesn't support the special :scope selector.



          You may think it's the same going from the document or going from the root element, but not only will it make a difference in terms of performances, it will also allow for using this method while the element is not appended to any document.






          const div = document.createElement('div');
          div.insertAdjacentHTML('beforeend', '<div id="test"><div class="bar"></div></div>')

          console.log(div.querySelector('div>.bar')); // found
          console.log(document.querySelector('div>.bar')); // null





          In the same way, matching elements in the Shadow-DOM would not be possible if we only had Document.querySelector.






          share|improve this answer























          • Goood explanaition - especially the bit about Nodes not part of the document. This represents more clearly what the browser engine actually does.

            – Falco
            Apr 8 at 13:46


















          1














          The query selector div > div > div only means:



          Find a div which has a parent and a granparent which are both also a div.



          And if you start with the first child of test and check the selector, it is true. And this is the reason why only your last query selects the innermost div, since it has the first predicate (find a div with a great-great-grandparent-div) which is not fulfilled by the first child of test.



          The query-selector will only test descendants, but it will evaluate the expression in scope of the whole document. Just imagine a selector like checking properties of an element - even if you only view the child element, it is still the child of its parent.






          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55568211%2fweird-behaviour-when-using-queryselector%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            3 Answers
            3






            active

            oldest

            votes








            3 Answers
            3






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            24














            What querySelector does is it finds an element somewhere in the document that matches the CSS selector passed, and then checks that the found element is a descendant of the element you called querySelector on. It doesn't start at the element it was called on and search downwards - rather, it always starts at the document level, looks for elements that match the selector, and checks that the element is also a descendant of the calling context element. It's a bit unintuitive.



            So:



            someElement.querySelector(selectorStr)


            is like



            [...document.querySelectorAll(selectorStr)]
            .find(elm => someElement.contains(elm));


            A possible solution is to use :scope to indicate that you want the selection to start at the rootDiv, rather than at document:






            const rootDiv = document.getElementById('test');
            console.log(rootDiv.querySelector(':scope > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div > div').innerHTML);

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            :scope is supported in all modern browsers but Edge.






            share|improve this answer

























            • Neat trick! Thanks!

              – Tico
              Apr 8 at 7:35











            • :scope is not supported by all but most of the major browsers. Anyways, thank for explanation and this should be the answer. Thanks.

              – Joey Chong
              Apr 8 at 7:44












            • :scope doesn't work with IE and Edge, I think it's important to point this out

              – Cristian Traìna
              Apr 8 at 7:47











            • Here is the browser compatibility table - we have to resist just few months more since Edge is implementing Chromium engine :P

              – Cristian Traìna
              Apr 8 at 7:47












            • Do you have any sources for the browser engine actually working this way ? - The query would have the same result, if the engine would start with the first div and check if it matches the query selector...

              – Falco
              Apr 8 at 11:17















            24














            What querySelector does is it finds an element somewhere in the document that matches the CSS selector passed, and then checks that the found element is a descendant of the element you called querySelector on. It doesn't start at the element it was called on and search downwards - rather, it always starts at the document level, looks for elements that match the selector, and checks that the element is also a descendant of the calling context element. It's a bit unintuitive.



            So:



            someElement.querySelector(selectorStr)


            is like



            [...document.querySelectorAll(selectorStr)]
            .find(elm => someElement.contains(elm));


            A possible solution is to use :scope to indicate that you want the selection to start at the rootDiv, rather than at document:






            const rootDiv = document.getElementById('test');
            console.log(rootDiv.querySelector(':scope > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div > div').innerHTML);

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            :scope is supported in all modern browsers but Edge.






            share|improve this answer

























            • Neat trick! Thanks!

              – Tico
              Apr 8 at 7:35











            • :scope is not supported by all but most of the major browsers. Anyways, thank for explanation and this should be the answer. Thanks.

              – Joey Chong
              Apr 8 at 7:44












            • :scope doesn't work with IE and Edge, I think it's important to point this out

              – Cristian Traìna
              Apr 8 at 7:47











            • Here is the browser compatibility table - we have to resist just few months more since Edge is implementing Chromium engine :P

              – Cristian Traìna
              Apr 8 at 7:47












            • Do you have any sources for the browser engine actually working this way ? - The query would have the same result, if the engine would start with the first div and check if it matches the query selector...

              – Falco
              Apr 8 at 11:17













            24












            24








            24







            What querySelector does is it finds an element somewhere in the document that matches the CSS selector passed, and then checks that the found element is a descendant of the element you called querySelector on. It doesn't start at the element it was called on and search downwards - rather, it always starts at the document level, looks for elements that match the selector, and checks that the element is also a descendant of the calling context element. It's a bit unintuitive.



            So:



            someElement.querySelector(selectorStr)


            is like



            [...document.querySelectorAll(selectorStr)]
            .find(elm => someElement.contains(elm));


            A possible solution is to use :scope to indicate that you want the selection to start at the rootDiv, rather than at document:






            const rootDiv = document.getElementById('test');
            console.log(rootDiv.querySelector(':scope > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div > div').innerHTML);

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            :scope is supported in all modern browsers but Edge.






            share|improve this answer















            What querySelector does is it finds an element somewhere in the document that matches the CSS selector passed, and then checks that the found element is a descendant of the element you called querySelector on. It doesn't start at the element it was called on and search downwards - rather, it always starts at the document level, looks for elements that match the selector, and checks that the element is also a descendant of the calling context element. It's a bit unintuitive.



            So:



            someElement.querySelector(selectorStr)


            is like



            [...document.querySelectorAll(selectorStr)]
            .find(elm => someElement.contains(elm));


            A possible solution is to use :scope to indicate that you want the selection to start at the rootDiv, rather than at document:






            const rootDiv = document.getElementById('test');
            console.log(rootDiv.querySelector(':scope > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div > div').innerHTML);

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            :scope is supported in all modern browsers but Edge.






            const rootDiv = document.getElementById('test');
            console.log(rootDiv.querySelector(':scope > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div > div').innerHTML);

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            const rootDiv = document.getElementById('test');
            console.log(rootDiv.querySelector(':scope > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div').innerHTML);
            console.log(rootDiv.querySelector(':scope > div > div > div').innerHTML);

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited yesterday









            Nisarg

            11.2k52341




            11.2k52341










            answered Apr 8 at 7:31









            CertainPerformanceCertainPerformance

            99k166089




            99k166089












            • Neat trick! Thanks!

              – Tico
              Apr 8 at 7:35











            • :scope is not supported by all but most of the major browsers. Anyways, thank for explanation and this should be the answer. Thanks.

              – Joey Chong
              Apr 8 at 7:44












            • :scope doesn't work with IE and Edge, I think it's important to point this out

              – Cristian Traìna
              Apr 8 at 7:47











            • Here is the browser compatibility table - we have to resist just few months more since Edge is implementing Chromium engine :P

              – Cristian Traìna
              Apr 8 at 7:47












            • Do you have any sources for the browser engine actually working this way ? - The query would have the same result, if the engine would start with the first div and check if it matches the query selector...

              – Falco
              Apr 8 at 11:17

















            • Neat trick! Thanks!

              – Tico
              Apr 8 at 7:35











            • :scope is not supported by all but most of the major browsers. Anyways, thank for explanation and this should be the answer. Thanks.

              – Joey Chong
              Apr 8 at 7:44












            • :scope doesn't work with IE and Edge, I think it's important to point this out

              – Cristian Traìna
              Apr 8 at 7:47











            • Here is the browser compatibility table - we have to resist just few months more since Edge is implementing Chromium engine :P

              – Cristian Traìna
              Apr 8 at 7:47












            • Do you have any sources for the browser engine actually working this way ? - The query would have the same result, if the engine would start with the first div and check if it matches the query selector...

              – Falco
              Apr 8 at 11:17
















            Neat trick! Thanks!

            – Tico
            Apr 8 at 7:35





            Neat trick! Thanks!

            – Tico
            Apr 8 at 7:35













            :scope is not supported by all but most of the major browsers. Anyways, thank for explanation and this should be the answer. Thanks.

            – Joey Chong
            Apr 8 at 7:44






            :scope is not supported by all but most of the major browsers. Anyways, thank for explanation and this should be the answer. Thanks.

            – Joey Chong
            Apr 8 at 7:44














            :scope doesn't work with IE and Edge, I think it's important to point this out

            – Cristian Traìna
            Apr 8 at 7:47





            :scope doesn't work with IE and Edge, I think it's important to point this out

            – Cristian Traìna
            Apr 8 at 7:47













            Here is the browser compatibility table - we have to resist just few months more since Edge is implementing Chromium engine :P

            – Cristian Traìna
            Apr 8 at 7:47






            Here is the browser compatibility table - we have to resist just few months more since Edge is implementing Chromium engine :P

            – Cristian Traìna
            Apr 8 at 7:47














            Do you have any sources for the browser engine actually working this way ? - The query would have the same result, if the engine would start with the first div and check if it matches the query selector...

            – Falco
            Apr 8 at 11:17





            Do you have any sources for the browser engine actually working this way ? - The query would have the same result, if the engine would start with the first div and check if it matches the query selector...

            – Falco
            Apr 8 at 11:17













            6














            The currently accepted answer somehow provides a valid logical explanation as to what happens, but they are factually wrong.



            Element.querySelector triggers the match a selector against tree algorithm, which goes from the root element and checks if its descendants do match the selector.



            The selector itself is absolute, it doesn't have any knowledge of a Document and doesn't even require that your Element be appended to any. And apart from the :scope attribute, it doesn't either care with which root you called the querySelector method.



            If we wanted to rewrite it ourselves, it would be more like



            const walker = document.createTreeWalker(element, 
            NodeFilter.SHOW_ELEMENT,
            acceptNode: (node) => return node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();





            const rootDiv = document.getElementById('test');
            console.log(querySelector(rootDiv, 'div>div').innerHTML);

            function querySelector(element, selector)
            const walker = document.createTreeWalker(element,
            NodeFilter.SHOW_ELEMENT,

            acceptNode: (node) => node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();
            ;

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            With the big difference that this implementation doesn't support the special :scope selector.



            You may think it's the same going from the document or going from the root element, but not only will it make a difference in terms of performances, it will also allow for using this method while the element is not appended to any document.






            const div = document.createElement('div');
            div.insertAdjacentHTML('beforeend', '<div id="test"><div class="bar"></div></div>')

            console.log(div.querySelector('div>.bar')); // found
            console.log(document.querySelector('div>.bar')); // null





            In the same way, matching elements in the Shadow-DOM would not be possible if we only had Document.querySelector.






            share|improve this answer























            • Goood explanaition - especially the bit about Nodes not part of the document. This represents more clearly what the browser engine actually does.

              – Falco
              Apr 8 at 13:46















            6














            The currently accepted answer somehow provides a valid logical explanation as to what happens, but they are factually wrong.



            Element.querySelector triggers the match a selector against tree algorithm, which goes from the root element and checks if its descendants do match the selector.



            The selector itself is absolute, it doesn't have any knowledge of a Document and doesn't even require that your Element be appended to any. And apart from the :scope attribute, it doesn't either care with which root you called the querySelector method.



            If we wanted to rewrite it ourselves, it would be more like



            const walker = document.createTreeWalker(element, 
            NodeFilter.SHOW_ELEMENT,
            acceptNode: (node) => return node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();





            const rootDiv = document.getElementById('test');
            console.log(querySelector(rootDiv, 'div>div').innerHTML);

            function querySelector(element, selector)
            const walker = document.createTreeWalker(element,
            NodeFilter.SHOW_ELEMENT,

            acceptNode: (node) => node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();
            ;

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            With the big difference that this implementation doesn't support the special :scope selector.



            You may think it's the same going from the document or going from the root element, but not only will it make a difference in terms of performances, it will also allow for using this method while the element is not appended to any document.






            const div = document.createElement('div');
            div.insertAdjacentHTML('beforeend', '<div id="test"><div class="bar"></div></div>')

            console.log(div.querySelector('div>.bar')); // found
            console.log(document.querySelector('div>.bar')); // null





            In the same way, matching elements in the Shadow-DOM would not be possible if we only had Document.querySelector.






            share|improve this answer























            • Goood explanaition - especially the bit about Nodes not part of the document. This represents more clearly what the browser engine actually does.

              – Falco
              Apr 8 at 13:46













            6












            6








            6







            The currently accepted answer somehow provides a valid logical explanation as to what happens, but they are factually wrong.



            Element.querySelector triggers the match a selector against tree algorithm, which goes from the root element and checks if its descendants do match the selector.



            The selector itself is absolute, it doesn't have any knowledge of a Document and doesn't even require that your Element be appended to any. And apart from the :scope attribute, it doesn't either care with which root you called the querySelector method.



            If we wanted to rewrite it ourselves, it would be more like



            const walker = document.createTreeWalker(element, 
            NodeFilter.SHOW_ELEMENT,
            acceptNode: (node) => return node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();





            const rootDiv = document.getElementById('test');
            console.log(querySelector(rootDiv, 'div>div').innerHTML);

            function querySelector(element, selector)
            const walker = document.createTreeWalker(element,
            NodeFilter.SHOW_ELEMENT,

            acceptNode: (node) => node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();
            ;

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            With the big difference that this implementation doesn't support the special :scope selector.



            You may think it's the same going from the document or going from the root element, but not only will it make a difference in terms of performances, it will also allow for using this method while the element is not appended to any document.






            const div = document.createElement('div');
            div.insertAdjacentHTML('beforeend', '<div id="test"><div class="bar"></div></div>')

            console.log(div.querySelector('div>.bar')); // found
            console.log(document.querySelector('div>.bar')); // null





            In the same way, matching elements in the Shadow-DOM would not be possible if we only had Document.querySelector.






            share|improve this answer













            The currently accepted answer somehow provides a valid logical explanation as to what happens, but they are factually wrong.



            Element.querySelector triggers the match a selector against tree algorithm, which goes from the root element and checks if its descendants do match the selector.



            The selector itself is absolute, it doesn't have any knowledge of a Document and doesn't even require that your Element be appended to any. And apart from the :scope attribute, it doesn't either care with which root you called the querySelector method.



            If we wanted to rewrite it ourselves, it would be more like



            const walker = document.createTreeWalker(element, 
            NodeFilter.SHOW_ELEMENT,
            acceptNode: (node) => return node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();





            const rootDiv = document.getElementById('test');
            console.log(querySelector(rootDiv, 'div>div').innerHTML);

            function querySelector(element, selector)
            const walker = document.createTreeWalker(element,
            NodeFilter.SHOW_ELEMENT,

            acceptNode: (node) => node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();
            ;

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            With the big difference that this implementation doesn't support the special :scope selector.



            You may think it's the same going from the document or going from the root element, but not only will it make a difference in terms of performances, it will also allow for using this method while the element is not appended to any document.






            const div = document.createElement('div');
            div.insertAdjacentHTML('beforeend', '<div id="test"><div class="bar"></div></div>')

            console.log(div.querySelector('div>.bar')); // found
            console.log(document.querySelector('div>.bar')); // null





            In the same way, matching elements in the Shadow-DOM would not be possible if we only had Document.querySelector.






            const rootDiv = document.getElementById('test');
            console.log(querySelector(rootDiv, 'div>div').innerHTML);

            function querySelector(element, selector)
            const walker = document.createTreeWalker(element,
            NodeFilter.SHOW_ELEMENT,

            acceptNode: (node) => node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();
            ;

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            const rootDiv = document.getElementById('test');
            console.log(querySelector(rootDiv, 'div>div').innerHTML);

            function querySelector(element, selector)
            const walker = document.createTreeWalker(element,
            NodeFilter.SHOW_ELEMENT,

            acceptNode: (node) => node.matches(selector) && NodeFilter.FILTER_ACCEPT
            );
            return walker.nextNode();
            ;

            <div>
            <div>
            <div id="test">
            <div>
            <div>
            This is content
            </div>
            </div>
            </div>
            </div>
            </div>





            const div = document.createElement('div');
            div.insertAdjacentHTML('beforeend', '<div id="test"><div class="bar"></div></div>')

            console.log(div.querySelector('div>.bar')); // found
            console.log(document.querySelector('div>.bar')); // null





            const div = document.createElement('div');
            div.insertAdjacentHTML('beforeend', '<div id="test"><div class="bar"></div></div>')

            console.log(div.querySelector('div>.bar')); // found
            console.log(document.querySelector('div>.bar')); // null






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Apr 8 at 12:42









            KaiidoKaiido

            45.9k467108




            45.9k467108












            • Goood explanaition - especially the bit about Nodes not part of the document. This represents more clearly what the browser engine actually does.

              – Falco
              Apr 8 at 13:46

















            • Goood explanaition - especially the bit about Nodes not part of the document. This represents more clearly what the browser engine actually does.

              – Falco
              Apr 8 at 13:46
















            Goood explanaition - especially the bit about Nodes not part of the document. This represents more clearly what the browser engine actually does.

            – Falco
            Apr 8 at 13:46





            Goood explanaition - especially the bit about Nodes not part of the document. This represents more clearly what the browser engine actually does.

            – Falco
            Apr 8 at 13:46











            1














            The query selector div > div > div only means:



            Find a div which has a parent and a granparent which are both also a div.



            And if you start with the first child of test and check the selector, it is true. And this is the reason why only your last query selects the innermost div, since it has the first predicate (find a div with a great-great-grandparent-div) which is not fulfilled by the first child of test.



            The query-selector will only test descendants, but it will evaluate the expression in scope of the whole document. Just imagine a selector like checking properties of an element - even if you only view the child element, it is still the child of its parent.






            share|improve this answer



























              1














              The query selector div > div > div only means:



              Find a div which has a parent and a granparent which are both also a div.



              And if you start with the first child of test and check the selector, it is true. And this is the reason why only your last query selects the innermost div, since it has the first predicate (find a div with a great-great-grandparent-div) which is not fulfilled by the first child of test.



              The query-selector will only test descendants, but it will evaluate the expression in scope of the whole document. Just imagine a selector like checking properties of an element - even if you only view the child element, it is still the child of its parent.






              share|improve this answer

























                1












                1








                1







                The query selector div > div > div only means:



                Find a div which has a parent and a granparent which are both also a div.



                And if you start with the first child of test and check the selector, it is true. And this is the reason why only your last query selects the innermost div, since it has the first predicate (find a div with a great-great-grandparent-div) which is not fulfilled by the first child of test.



                The query-selector will only test descendants, but it will evaluate the expression in scope of the whole document. Just imagine a selector like checking properties of an element - even if you only view the child element, it is still the child of its parent.






                share|improve this answer













                The query selector div > div > div only means:



                Find a div which has a parent and a granparent which are both also a div.



                And if you start with the first child of test and check the selector, it is true. And this is the reason why only your last query selects the innermost div, since it has the first predicate (find a div with a great-great-grandparent-div) which is not fulfilled by the first child of test.



                The query-selector will only test descendants, but it will evaluate the expression in scope of the whole document. Just imagine a selector like checking properties of an element - even if you only view the child element, it is still the child of its parent.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Apr 8 at 11:25









                FalcoFalco

                2,8501620




                2,8501620



























                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55568211%2fweird-behaviour-when-using-queryselector%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Hidroelektrana Sadržaj Povijest | Podjela hidroelektrana | Snaga dobivena u hidroelektranama | Dijelovi hidroelektrane | Uloga hidroelektrana u suvremenom svijetu | Prednosti hidroelektrana | Nedostaci hidroelektrana | Države s najvećom proizvodnjom hidro-električne energije | Deset najvećih hidroelektrana u svijetu | Hidroelektrane u Hrvatskoj | Izvori | Poveznice | Vanjske poveznice | Navigacijski izbornikTechnical Report, Version 2Zajedničkom poslužiteljuHidroelektranaHEP Proizvodnja d.o.o. - Hidroelektrane u Hrvatskoj

                    WordPress Information needed

                    Oconto (Nebraska) Índice Demografia | Geografia | Localidades na vizinhança | Referências Ligações externas | Menu de navegação41° 8' 29" N 99° 45' 41" O41° 8' 29" N 99° 45' 41" OU.S. Census Bureau. Census 2000 Summary File 1U.S. Census Bureau. Estimativa da população (julho de 2006)U.S. Board on Geographic Names. Topical Gazetteers Populated Places. Gráficos do banco de dados de altitudes dos Estados Unidos da AméricaEstatísticas, mapas e outras informações sobre Oconto em city-data.com