Skip to content

Instantly share code, notes, and snippets.

@PaulKinlan
Last active April 2, 2024 02:45
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);
})();
@amityweb
Copy link

amityweb commented May 7, 2015

Doesn't work for me in Chrome. I made it into a Bookmarklet using http://chriszarate.github.io/bookmarkleter/

Edit: Ok this gives it away console.log(css); - i can see it now :)

@amityweb
Copy link

amityweb commented May 7, 2015

Doesn't grab ALL the critical CSS for us... leaves out our header menu, so we get a flash of unstyled content, mainly the header menu

@mihawk90
Copy link

Just found this gem, works really well :)

When executing, I get this warning however:

'getMatchedCSSRules()' is deprecated. For more help, check https://code.google.com/p/chromium/issues/detail?id=437569#c2

@amityweb I suspect it has it has something to do with the positioning of the elements, as it works fine for me on my current project (with a fixed header nav)

@mpiontek
Copy link

Not working for me :( http://neu.contur-online.de/de/index.php . After fill in only the 'critical path css', your tool gives me, the page is showing up wrong

@ctorx
Copy link

ctorx commented Aug 20, 2015

It seems the getMatchCSSRules function is expecting 2 arguments. Calling it with an empty string kills the deprecated message and still works as expected.

var rules = w.getMatchedCSSRules(node, '');

@vuquangchien
Copy link

It doesn't work for media query and responsive websites. I tried with Bootstrap (http://getbootstrap.com/examples/theme/). Is there any way to make it work with Bootstrap?

@james-Ballyhoo
Copy link

@vuquangchien, this might be of use (I based it off Paul's code when we also hit the media queries issue) https://gist.github.com/james-Ballyhoo/04761ed2a5778c505527

@alirabet
Copy link

@james-Ballyhoo I tested it, It didn't work well on default brower on Android. It works well on chrome 👍 Can you fix it for all browers?

@verkaro
Copy link

verkaro commented Sep 9, 2016

non-techie reporting: this doesn't work with chromium-browser in Ubuntu 16.10 -- but running under google's chrome download worked. thanks for the work you've done.

@MiFreSu
Copy link

MiFreSu commented Jun 2, 2017

The function getMatchedCSSRules does not work anymore. Long time it was deprecated and now it is removed. Does someone knows a replacement?

@alexlii1971
Copy link

Hello,

Someone wrote a plugin as per your code:
Generate Critical CSS at https://wordpress.org/plugins/generate-critical-css/

but that plugin is out to update, would like to update it?

As per suggestion from google page speed insight, we need generate critical css, some plugins (https://wordpress.org/plugins/above-the-fold-optimization/) only handle optimize, but not handle generate those css.

Anyone would like to update those wordpress' plugin?

Alex

@optimalisatie
Copy link

optimalisatie commented Jan 24, 2018

Hi!

Thanks a lot for this snippet!

getMatchedCSSRules will be removed in Chrome 63.

We have created an improved snippet based on this concept that includes a polyfill for getMatchedCSSRules to support more browsers, including Firefox.

https://docs.style.tools/critical-css-generator

@DirkPersky
Copy link

Hi!

i modidyed the snippet for the latest Chrome, and testet it a lot of Times!
If you need the Bookmarklet version you can copy it

https://github.com/DirkPersky/criticalcss

@CameronKnowlton
Copy link

hi DirkPersky , I wasn't able to get your https://github.com/DirkPersky/criticalcss bookmarklet working in Chrome 72 Mac... should it be working? I tried it on several URLs, nothing happens (e.g. https://www.nytimes.com/ ). Thanks for your work on this.

@wuworkshop
Copy link

@CameronKnowlton I just tried https://github.com/DirkPersky/criticalcss on the NY Times site and it worked for me in Chrome Canary Version 75.0.3740.0 macOS 10.13.6. The generated critical CSS is displayed in the console in DevTools.

@oopix-jane
Copy link

Just tried DirkPersky's bookmarklet. It works. Thanks!

@fisiculturista
Copy link

Hello, Paul Kilan's code pops an error and DirkPerky's code does nothing. Anyone knows a working script to run on Chrome console to extract the critical css?

@fisiculturista
Copy link

hi DirkPersky , I wasn't able to get your https://github.com/DirkPersky/criticalcss bookmarklet working in Chrome 72 Mac... should it be working? I tried it on several URLs, nothing happens (e.g. https://www.nytimes.com/ ). Thanks for your work on this.

Same issue here. Nothing happens.

@DirkPersky
Copy link

DirkPersky commented Jun 26, 2020

On Windows 10 with Crome 83.0.... the Bookmarklet works.
Maybe update your Chrome.

@fisiculturista

@gatehealing
Copy link

Hi, I was sent here via the Autoptimize plugin FAQ. I have no clue how to use this to generate critical/above the fold CSS for the inline and defer css field of AO. Using another critical css generator I am getting the flash of unoptimized code (something like that). Could somebody please point me in the right direction of how to use this tool to extract (*the FAQ link points to this page)
Thanks!
Jon

@DirkPersky
Copy link

DirkPersky commented Jul 6, 2020

@gatehealing you create a new bookmark, and copy all javascript code from my https://github.com/DirkPersky/criticalcss/blob/master/bookmark.js into that field like the screenshot =)
image

using it:
open the developer console, on you site and press the bookmark button in yout browser an wait for it ;)
image

@gatehealing
Copy link

Thanks DirkPersky! Please forgive my ignorance . . . what page am I bookmarking? This one (the one I am commenting on?)

@DirkPersky
Copy link

DirkPersky commented Jul 6, 2020

@gatehealing Non of both! Only create a new bookmark, but instead of adding a url to it, copy the content of my javascript and paste it to the url =)

image

@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