Skip to content

Instantly share code, notes, and snippets.

@mardukbp
Forked from gampleman/README.md
Created October 9, 2022 15:01
Show Gist options
  • Save mardukbp/23e4ade9745c2ce50e74073754204a69 to your computer and use it in GitHub Desktop.
Save mardukbp/23e4ade9745c2ce50e74073754204a69 to your computer and use it in GitHub Desktop.
Algorithm to find a short unique CSS selector from an arbitrary node

This algorithm when passed a DOM node will find a very short selector for that element.

function getPath(node) {
// phase 1: generation
var path = [];
while (node) {
name = node.localName;
if (!name) break;
name = name.toLowerCase();
if (node.id && node.id !== '') {
path.unshift('#' + node.id);
break;
}
var parent = node.parentElement;
if (!parent) break;
if (node.classList.length > 0) {
for (var i = 0; i < node.classList.length; i++) {
var className = node.classList[i];
var sameClassSiblings = [].filter.call(parent.children, function(e) {
return [].indexOf.call(e.classList, className) > 0;
});
if (sameClassSiblings.length == 1) {
name = '.' + className;
break;
}
}
} else {
var sameTagSiblings = [].filter.call(parent.children, function(e) { return e.localName.toLowerCase() == name});
if (sameTagSiblings.length > 1) {
allSiblings = parent.children;
var index = [].indexOf.call(allSiblings, node) + 1;
if (index > 1) {
name += ':nth-child(' + index + ')';
}
}
}
path.unshift(name);
node = parent;
}
// phase 2: simplification
var results = 0, tempPath, origPath = path.slice(0);;
for (var i = path.length - 1; i >= 0; i--) {
// tempPath = path[i] + (tempPath ? '>' + tempPath : '');
tempPath = path.slice(i).join(' ');
var newResults = document.querySelectorAll(tempPath).length;
if (newResults == results) {
path.splice(i, 1);
} else {
results = newResults;
}
}
// simplification failed
if (results != 1) {
path = origPath;
}
return path.join(' > ');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment