HomeThe ClassicsBlog

getCSSSelector

Published:

I’m working on indexing every link on my site. If I left it at that, it wouldn’t be useful as the noise from templated links vastly outstrip those in an article’s body. To that end, I wanted to find a way of tracing where a link is on a web page and the best way I could think of doing that is by generating a CSS selector for an anchor element, much like how you can copy a selector.

Stak overflow open with dev tools. The sites header is highlighted along with it’s element name and classes. In dev tools, the copy selector is chosen

Notice all the ways to copy an element and how it includes a CSS selector? It results in body > header, though it has multiple classes. Trying to mimick this will need a lot of effort on my part

The algorithm involves walking up the anchors ancestors elements, appending it the front of an array until none are left (i.e. it reaches the root html element). I then add change the appended elements to a string containing the tag name, id and classes before joining the array with a direct descendant selector >.

function getCSSSelector (elem) {
    let currElem = elem
    const elems = []
    while (currElem) {
        elems.unshift(currElem)
        currElem = currElem.parentElement
    }
    elems.forEach((elem, i) => {
        let selector = elem.tagName.toLowerCase()
        if (elem.id) {
            selector += "#" + elem.id
        }

        elem.classList.forEach((cl) => {
            selector += "." + cl
        })
        elems[i] = selector
    })
    return elems.join(" > ")
}

For example, something like html > body > main > ul > li > a is probably in a content list, whereas html > body > main > article > div.article__content > p > sup#fnref:3 > a.footnote-ref is the return link for a post’s footnote.

While it looks good to me, I’m open to feedback if you know a better way of doing this.