Consider the following HTML excerpt from a page:
<style type="text/css">
.existing-class {
background-color: #000;
}
</style>
<div class="existing-class non-existing-class"></div>
It has 2 classes applied. Here is the thing: non-existing-class
is not defined anywhere in the CSS available in the page, however div
is using it.
My question is: How can a developer programmatically detect elements in the page which are using classes that are not actually defined in the loaded CSS?
The idea is to load up document. styleSheets and find all the rules (the ones that are classes). Then, use a MutationObserver to watch the DOM for all HTML, and check the classList of each node to see if it matches any from any stylesheet. If the HTML has a class not found in a stylesheet, report it.
The . class selector selects elements with a specific class attribute. To select elements with a specific class, write a period (.) character, followed by the name of the class.
The :not CSS pseudo-class can be used to select elements that do not contain a specific class, id, attribute etc.
Okay, there you go ;)
Take a look at the script I have created, especially getUndefinedClasses
function.
function httpGet(theUrl) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
function getAllCSSClasses(cssdata) {
var re = /\.(.+)\{/g;
var m;
let classes = [];
do {
m = re.exec(cssdata);
if (m) {
for(let key in m) {
if(
(typeof m[key] == "string") &&
(classes.indexOf(m[key]) == -1) &&
(m[key].indexOf(".") == -1)
)
classes.push(m[key].replace(/\s/g, " "));
}
}
} while (m);
return classes;
}
function getAllClasses() {
var csses = document.querySelectorAll('link[rel="stylesheet"]');
var classes = []
for (i = 0; i < csses.length; ++i) {
// let styledata = httpGet(csses[i].href);
var styledata = ".hi{ display: none; }";
var cclasses = getAllCSSClasses(styledata);
var classes = Object.assign([], classes, cclasses);
classes.concat(cclasses);
}
return classes;
}
function getHTMLUsedClasses() {
var elements = document.getElementsByTagName('*');
var unique = function (list, x) {
if (x != "" && list.indexOf(x) === -1) {
list.push(x);
}
return list;
};
var trim = function (x) { return x.trim(); };
var htmlclasses = [].reduce.call(elements, function (acc, e) {
return e.className.split(' ').map(trim).reduce(unique, acc);
}, []);
return htmlclasses;
}
function getUndefinedClasses(cssclasses, htmlclasses) {
var undefinedclasses = [];
for (let key in htmlclasses) {
if(cssclasses.indexOf(htmlclasses[key]) == -1 ) {
undefinedclasses.push(htmlclasses[key]);
}
}
return undefinedclasses;
}
var cssclasses = getAllClasses();
var htmlclasses = getHTMLUsedClasses();
console.log("Undefined classes : " + getUndefinedClasses(cssclasses, htmlclasses))
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<link rel="stylesheet" href="hi there">
</head>
<body>
<div class="hi"></div>
<div class="there"></div>
<div class="there_thier_333"></div>
</body>
</html>
What is done:
(jsbin here needed)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With