1

I would like to be able to get the non-absolute css path of an element using Javascript so that I can subsequently call:

document.querySelectorAll()

I am trying to grab all elements from a page who share the same css path.

For example using the search results page from Google:

  1. A css selector (absolute) would be:
div.g:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(1) > a:nth-child(1) > h3:nth-child(1) > div:nth-child(1)
  1. A css path (non-absolute) would be:
html body#gsr.srp.tbo.vasq div#main div#cnt div.mw div#rcnt div.col div#center_col div#res.med div#search div div#rso div.bkWMgd div.srg div.g div div.rc div.r a h3.LC20lb div.ellip

Every answer I have seen usually returns the absolute path (css selector) to an element - i.e the nth child. For example: Get CSS path from Dom element.

Does anyone have an idea on how to get just the pure css path which would be applicable to multiple elements on the page?

Edit: What I am really looking for is the source code in the Firefox Web Developer Inspector tool where you can right click and choose 'Copy CSS Path'. If someone has a pointer to this I would appreciate it.

AbuZubair
  • 1,236
  • 14
  • 20

1 Answers1

1

This is a little more difficult since you have to decide what level of specificity you want. You can choose to include or ignore tags, ids, classes, and attributes, all of which have their own format. I've written a function which does this for you.

nonabsoluteCSS() takes in any element and booleans for whether or not to include the element's tag name, classes, id, and attributes. It's recursive and will climb up the DOM tree until it hits the <body> element.

You can expand on this function even more if you want to get into things like pseudo-elements and siblings, but this should be a good place to start.

$(function(){
 $("a").click(function(){
   console.log(nonabsoluteCSS(this, true, true, true, true));
  });
});

function nonabsoluteCSS(elm, useElements, useClasses, useIds, useAttributes)
{
  if($(elm).length < 1)
   return false;

  var p = $(elm).parent()[0];
  var e = $(elm)[0];
  
  var output = "";
  
  if(!useElements && !useClasses && !useIds && !useAttributes)
   output = "*";
  else
  {
    if(useElements)
     output += e.tagName.toLowerCase();
    if(useClasses)
    {
     for(var i = 0; i < e.classList.length; i++)
       output += "."+e.classList[i];
    }
    if(useIds && e.id != "")
     output += "#"+e.id;
    if(useAttributes)
    {
     for(var i = 0; i < e.attributes.length; i++)
      {
       output += "["+e.attributes[i].name+"=\""+e.attributes[i].value+"\"]";
      }
    }
  }
  
  if(p.tagName.toLowerCase() != "body")
  {
   return nonabsoluteCSS(p, useClasses, useIds, useAttributes) + " " + output;
  }
  else
  {
   return output;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <p class="class1">
    <span class="class2 class3" id="spanid">
      <a href="#">
        Click me to see my CSS path.
      </a>
    </span>
  </p>
</div>
Liftoff
  • 24,717
  • 13
  • 66
  • 119
  • This works great so far. You have a bug though on the recursive call. You you have less arguments then what's needed. After I made the change it works fine. – AbuZubair Sep 14 '19 at 06:30