With the help of this answer (get all css classes background & color properties values) I can get all CSS classes background & color properties values. It works when I use internal css codes.
Now, I have more than 35 external css stylesheets. When I tried the below code, It returns first external CSS file output only. Unable to get remaining stylesheet background & color properties values. How do I access remaining stylesheets?
$('#nightMode').on('click', function() {
// var color = $("body").css("background");
// var test = invertColor("#00a3fe");
// console.log(color);
let styles = document.styleSheets;
const rgbToHex = (rgbStr) => !rgbStr ? '':'#' + rgbStr
.slice(4,-1)
.split(', ')
.map(x => (+x).toString(16).padStart(2, '0'))
.join('');
let cssArr =[...styles[0].cssRules].map(x=> ({
class: x.selectorText,
background: rgbToHex(x.style.background),
color: rgbToHex(x.style.color)
} ));
let genCssStr='';
genCssStr+= '<style> \n\n';
cssArr.forEach(x=> genCssStr+=`${x.class}{\n` +
(x.background ? ` background:${invertColor(x.background)};\n` : '') +
(x.color ? ` color:${invertColor(x.color)};\n` : '') + `}\n\n`);
genCssStr+= '</style>';
console.log(styles);
console.log(genCssStr);
$(genCssStr).appendTo("body");
// console.log("array:", JSON.stringify(cssArr));
// console.log("text:\n\n", genCssStr);
});
The read-only CSSStyleSheet property cssRules returns a live CSSRuleList which provides a real-time, up-to-date list of every CSS rule which comprises the stylesheet. Each item in the list is a CSSRule defining a single rule.
The issue can be reproduced easily by injecting a style (e.g. by using the Chrome Developer Tools) that points to a CSS file from another domain (e.g. a CDN). If your CSS Stylesheet is from the same domain as the HTML, you will be able to access the document. styleSheets .get (index). cssRules property. Otherwise, it will throw the following error:
Each item in the list is a CSSRule defining a single rule. A live-updating CSSRuleList containing each of the CSS rules making up the stylesheet. Each entry in the rule list is a CSSRule object describing one rule making up the stylesheet.
In the latest version of Chrome, CORS security rules are also applicable for stylesheets (similar to Iframe rules). You can load and render them, but you cannot access the content stylesheets loaded from another domain through JavaScript. While this information was helpful, I still did not understand why this should be a problem.
The primary issue is that you are iterating the first stylesheet only. You need to iterate all stylesheets. Also note that you cannot enumerate cssRules
property of cross-domain stylesheets.
The following code processes all css rules inside all stylesheets (<link rel>
and <style>
). The try...catch
block is added to ignore DOMExceptions if the external stylesheet cannot be accessed:
var cssArr = [];
[...document.styleSheets].forEach(function(styleSheet) {
var cssRules;
try {
cssRules = styleSheet.cssRules;
} catch (e) {
console.log("Cannot process " + styleSheet.href);
return;
}
[...cssRules].forEach(function(cssRule) {
cssArr.push({
class: cssRule.selectorText,
background: cssRule.style.background,
color: cssRule.style.color
});
});
});
console.log(cssArr);
You are accessing only the first external file as you are using only the index 0
: styles[0].cssRules
. You should loop through all files like this:
styles.forEach(style => {
let cssArr =[...style.cssRules].map(x=> ({ class: x.selectorText, background: rgbToHex(x.style.background), color: rgbToHex(x.style.color)} ));
})
This answer describes why some rules may not be able to be accessed.
The long and short is that if the css resources are cross domain, then security restrictions prevent access.
Additionally, within that answer, there is this reference which describes the style sheet interface and explicitly states the above assertion where cross origin resources can't be accessed, and this applies to cssRules, among some other properties on the document.styleSheets
object.
The below code will catch that error gracefully and print the output of the error, or the cssRule to the console.
for (let i in [...document.styleSheets]){
try{
console.log(styles[i]['cssRules']);
}catch(e){
console.log(e);
}
}
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