Skip to content

Instantly share code, notes, and snippets.

@PaulKinlan
Last active October 12, 2024 16:34
Show Gist options
  • Save PaulKinlan/6284142 to your computer and use it in GitHub Desktop.
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);
})();
@gatehealing
Copy link

got it! Now what I see is not wrapped in <style></style> tags, and I believe I am supposed to put what is wrapped in those style tags in the AO inline and defer css box. I don't want to crash my site (which I have managed to do before on things like this), so I want to be sure I have extracted the correct code to put in that AO field....

@lewisje
Copy link

lewisje commented Aug 6, 2020

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

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

@lewisje
Copy link

lewisje commented Sep 23, 2021

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

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

@lewisje
Copy link

lewisje commented Jan 25, 2024

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