Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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);
})();
@PaulKinlan

This comment has been minimized.

Copy link
Owner Author

@PaulKinlan PaulKinlan commented Aug 22, 2013

Just added merging of styles.

@PaulKinlan

This comment has been minimized.

Copy link
Owner Author

@PaulKinlan PaulKinlan commented Aug 22, 2013

Fixing merge of styles.

@GlynnPhillips

This comment has been minimized.

Copy link

@GlynnPhillips GlynnPhillips commented Aug 22, 2013

Hey @PaulKinlan

Not sure if there is a reason why you have chosen to use d.body but I found that using the body as the start node missed body and html styles which could be very important on the critical css. Mind you my understanding of walkers is limited.

var walker = d.createTreeWalker(d, NodeFilter.SHOW_ELEMENT, function(node) { return NodeFilter.FILTER_ACCEPT; }, true);

instead of

var walker = d.createTreeWalker(d.body, NodeFilter.SHOW_ELEMENT, function(node) { return NodeFilter.FILTER_ACCEPT; }, true);

@PaulKinlan

This comment has been minimized.

Copy link
Owner Author

@PaulKinlan PaulKinlan commented Aug 22, 2013

@GlynnPhillips funny, I had this on my list :) great spot. not sure about head elements but let's give it ago.

@PaulKinlan

This comment has been minimized.

Copy link
Owner Author

@PaulKinlan PaulKinlan commented Aug 22, 2013

Fixed, head makes thinks look great. noticed a couple of other issues, working on them too.

@GlynnPhillips

This comment has been minimized.

Copy link

@GlynnPhillips GlynnPhillips commented Aug 23, 2013

Awesome, looking better now :)

@PaulKinlan

This comment has been minimized.

Copy link
Owner Author

@PaulKinlan PaulKinlan commented Aug 23, 2013

@GlynnPhillips I just relaised that it doesn't pull in scripts that are external to your domain (i.e cross-origin), whilst a little inconvienient I think this makes sense.

@qgustavor

This comment has been minimized.

Copy link

@qgustavor qgustavor commented Aug 25, 2013

I see cross-browser issues...

@GlynnPhillips

This comment has been minimized.

Copy link

@GlynnPhillips GlynnPhillips commented Aug 27, 2013

@PaulKinlan in what way? I can see script tags from external domains being 'walked' through. Is it just that it wouldn't pick up any styles which are set by these?

@mohammedzamakhan

This comment has been minimized.

Copy link

@mohammedzamakhan mohammedzamakhan commented Sep 14, 2013

Looks great when I tested on some websites, but it failed miserably on facebook.com AND youtube.com, it just returned bunch of selectors with css of { display: none !important; orphans: 4321 !important; }

So what is the issue here??

@marcis

This comment has been minimized.

Copy link

@marcis marcis commented Sep 17, 2013

What about this error message: "Uncaught SyntaxError: Unexpected end of input"?

I'm using Chrome :)

@cforge79

This comment has been minimized.

Copy link

@cforge79 cforge79 commented Oct 4, 2013

great work! just got pagespeed insights of 99 / 100 after moving the styles output to inline css! wow

@PaulKinlan

This comment has been minimized.

Copy link
Owner Author

@PaulKinlan PaulKinlan commented Oct 22, 2013

@cforge79 - awesome!!

@multiwebinc

This comment has been minimized.

Copy link

@multiwebinc multiwebinc commented Oct 29, 2013

Are there any workarounds for the cross origin thing? I serve all my static content from a different domain to prevent users from sending cookies to it.

@blueprintmrk

This comment has been minimized.

Copy link

@blueprintmrk blueprintmrk commented Nov 2, 2013

Patrick from feed the bot told me about this this is a fantastic set of code you have there. Thank you so much

@sigginet

This comment has been minimized.

Copy link

@sigginet sigginet commented Nov 7, 2013

@marcis you have to convert it to a bookmarklet (URLencoded, etc) code .. try http://chriszarate.github.io/bookmarkleter/

@luixxiul

This comment has been minimized.

Copy link

@luixxiul luixxiul commented Nov 10, 2013

@PaulKinlan Is it possible to pick up styles with media queries?

@satya61229

This comment has been minimized.

Copy link

@satya61229 satya61229 commented Dec 6, 2013

Sorry, possibly unrelated. But I want to test this.
How to use it as bookmark? I even minified it to put in bookmark in chrome but it is not taking. Possibly size!

@scunliffe

This comment has been minimized.

Copy link

@scunliffe scunliffe commented Dec 17, 2013

@satya61229 it should work fine minified... but don't forget you'll need to prefix it with "javascript:" ;-) (oh, and make sure you delete the comments... or the // will terminate your bookmarklet code early)

@alishahab

This comment has been minimized.

Copy link

@alishahab alishahab commented Mar 26, 2014

Hey @PaulKinlan

It should also return the pseudo-elements like ::after, ::before, hover, focus and active as well, check http://ali.shahab.pk/

@pocketjoso

This comment has been minimized.

Copy link

@pocketjoso pocketjoso commented May 13, 2014

A little bit of a resurrection, but I couldn't find anything on this problem:

Do you have any solution for the same-origin problem?

It seems that if you deliver your static resources via a CDN, this code will not work, because of the above problem.. I guess we can always temporarily move that CSS to be inline or so for testing, but I was hoping for something without many manual steps. :)

Awesome little tool by the way!

@pocketjoso

This comment has been minimized.

Copy link

@pocketjoso pocketjoso commented Jun 5, 2014

I built my own CriticalCSS Generator to solve these issues, something I can use for production. You can check it out here if you're interested:

https://github.com/pocketjoso/penthouse

Thanks for the inspiration!

@shidhincr

This comment has been minimized.

Copy link

@shidhincr shidhincr commented Sep 30, 2014

Hey @PaulKinlan @pocketjoso

Is there any solution available for CDN served css files ?

@cleberdantas

This comment has been minimized.

Copy link

@cleberdantas cleberdantas commented Jan 19, 2015

I put this script inside a CLI tool (Node) running on top of PhantomJS.

https://github.com/cleberdantas/atf

It's good for some automations.

Thanks for de original idea @PaulKinlan

@amityweb

This comment has been minimized.

Copy link

@amityweb 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

This comment has been minimized.

Copy link

@amityweb 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

This comment has been minimized.

Copy link

@mihawk90 mihawk90 commented May 13, 2015

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

This comment has been minimized.

Copy link

@mpiontek mpiontek commented Aug 14, 2015

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

This comment has been minimized.

Copy link

@ctorx 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

This comment has been minimized.

Copy link

@vuquangchien vuquangchien commented Sep 12, 2015

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

This comment has been minimized.

Copy link

@james-Ballyhoo james-Ballyhoo commented Sep 18, 2015

@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

This comment has been minimized.

Copy link

@alirabet alirabet commented Mar 10, 2016

@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

This comment has been minimized.

Copy link

@verkaro 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

This comment has been minimized.

Copy link

@MiFreSu 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

This comment has been minimized.

Copy link

@alexlii1971 alexlii1971 commented Jan 22, 2018

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

This comment has been minimized.

Copy link

@optimalisatie 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

This comment has been minimized.

Copy link

@DirkPersky DirkPersky commented Oct 9, 2018

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

This comment has been minimized.

Copy link

@CameronKnowlton CameronKnowlton commented Mar 12, 2019

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

This comment has been minimized.

Copy link

@wuworkshop wuworkshop commented Mar 22, 2019

@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

This comment has been minimized.

Copy link

@oopix-jane oopix-jane commented Oct 25, 2019

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

@fisiculturista

This comment has been minimized.

Copy link

@fisiculturista fisiculturista commented Jun 24, 2020

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

This comment has been minimized.

Copy link

@fisiculturista fisiculturista commented Jun 24, 2020

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

This comment has been minimized.

Copy link

@DirkPersky DirkPersky commented Jun 26, 2020

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

@fisiculturista

@gatehealing

This comment has been minimized.

Copy link

@gatehealing gatehealing commented Jul 6, 2020

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

This comment has been minimized.

Copy link

@DirkPersky 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

This comment has been minimized.

Copy link

@gatehealing gatehealing commented Jul 6, 2020

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

@DirkPersky

This comment has been minimized.

Copy link

@DirkPersky 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

This comment has been minimized.

Copy link

@gatehealing gatehealing commented Jul 6, 2020

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

This comment has been minimized.

Copy link

@lewisje 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.