Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save PaulKinlan/6284142 to your computer and use it in GitHub Desktop.

Select an option

Save PaulKinlan/6284142 to your computer and use it in GitHub Desktop.
CriticalCSS Bookmarklet and Devtool Snippet.js
(function() {
var CSSCriticalPath = function(w, d, opts) {
var opt = opts || {};
var css = {};
var pushCSS = function(r) {
if(!!css[r.selectorText] === false) css[r.selectorText] = {};
var styles = r.style.cssText.split(/;(?![A-Za-z0-9])/);
for(var i = 0; i < styles.length; i++) {
if(!!styles[i] === false) continue;
var pair = styles[i].split(": ");
pair[0] = pair[0].trim();
pair[1] = pair[1].trim();
css[r.selectorText][pair[0]] = pair[1];
}
};
var parseTree = function() {
// Get a list of all the elements in the view.
var height = w.innerHeight;
var walker = d.createTreeWalker(d, NodeFilter.SHOW_ELEMENT, function(node) { return NodeFilter.FILTER_ACCEPT; }, true);
while(walker.nextNode()) {
var node = walker.currentNode;
var rect = node.getBoundingClientRect();
if(rect.top < height || opt.scanFullPage) {
var rules = w.getMatchedCSSRules(node);
if(!!rules) {
for(var r = 0; r < rules.length; r++) {
pushCSS(rules[r]);
}
}
}
}
};
this.generateCSS = function() {
var finalCSS = "";
for(var k in css) {
finalCSS += k + " { ";
for(var j in css[k]) {
finalCSS += j + ": " + css[k][j] + "; ";
}
finalCSS += "}\n";
}
return finalCSS;
};
parseTree();
};
var cp = new CSSCriticalPath(window, document);
var css = cp.generateCSS();
console.log(css);
})();
@lewisje

lewisje commented Aug 6, 2020

Copy link
Copy Markdown

FWIW I also made a version of the bookmarklet, and I even accounted for some cases where the cssRules or rules property threw an error on access.

@gillespieza

Copy link
Copy Markdown

I get Uncaught TypeError: w.getMatchedCSSRules is not a function , using Chrome

@lewisje

lewisje commented Sep 23, 2021

Copy link
Copy Markdown

I get Uncaught TypeError: w.getMatchedCSSRules is not a function , using Chrome

My re-fashioning used a polyfill for that; getMatchedCSSRules was never standardized, and it was removed from Chrome starting with version 63.

@reedjones

Copy link
Copy Markdown

I was able to get it working by replacing getMatchedCSSRules with the script below. However doesn't work if css is from a different domain.

 var getCSS = function(el) {
    var sheets = document.styleSheets, ret = [];
    el.matches = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector 
        || el.msMatchesSelector || el.oMatchesSelector;
    for (var i in sheets) {
        var rules; 
      try {
        rules = sheets[i].rules; 
      } catch {
        console.log("Error reading rules: "); 
        try{
          rules = sheets[i].cssRules;
         
        } catch {
           console.log("Error reading cssRules: "); 
          
        }
         
      }
     
     ```

@reedjones

Copy link
Copy Markdown

@lewisje

lewisje commented Jan 25, 2024

Copy link
Copy Markdown

Your example script was not complete, but I imagine the rest of the way you'd do it is to test the element against each rule to see whether it matches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment