/* Critical CSS Finder w/media query support and output to console by Katie Harron - https://github.com/pibby - https://pibby.com forked from james-Ballyhoo (https://gist.github.com/james-Ballyhoo/04761ed2a5778c505527) who forked from PaulKinlan (https://gist.github.com/PaulKinlan/6284142) I don't know why this isn't keeping my 2 space indents :( */ (function() { function findCriticalCSS(w, d) { // Pseudo classes formatting var formatPseudo = /([^\s,\:\(])\:\:?(?!not)[a-zA-Z\-]{1,}(?:\(.*?\))?/g; // Height in px we want critical styles for var targetHeight = 900; var criticalNodes = []; // Step through the document tree and identify nodes that are within our targetHeight 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 < targetHeight) { criticalNodes.push(node); } } console.log("Found " + criticalNodes.length + " critical nodes."); // Find stylesheets that have been loaded var stylesheets = document.styleSheets; console.log("Found " + stylesheets.length + " stylesheet(s)."); var outputCss = Array.prototype.map.call(stylesheets,function(sheet) { var rules = sheet.rules || sheet.cssRules; // If style rules are present if (rules) { return { sheet: sheet, // Convert rules into an array rules: Array.prototype.map.call(rules, function(rule) { try { // If the rule contains a media query if (rule instanceof CSSMediaRule) { var nestedRules = rule.rules || rule.cssRules; var css = Array.prototype.filter.call(nestedRules, function(rule) { return criticalNodes.filter(function(e){ return e.matches(rule.selectorText.replace(formatPseudo, "$1"))}).length > 0; }).map(function(rule) { return rule.cssText }).reduce(function(ruleCss, init) {return init + "\n" + ruleCss;}, ""); return css ? ("@media " + rule.media.mediaText + " { " + css + "}") : null; } else if (rule instanceof CSSStyleRule) { // If rule does not contain a media query return criticalNodes.filter(function(e) { return e.matches(rule.selectorText.replace(formatPseudo, "$1")) }).length > 0 ? rule.cssText : null; } else { // If identified via CSSRule like @font and @keyframes return rule.cssText; } } catch(e) { /* This results in an error if you have print styles with @page embedded. As I do, I'm commenting it out. */ /*console.error("Improper CSS rule ", rule.selectorText); throw e;*/ } }).filter(function(e) { return e; }) } } else { return null; } }).filter(function(cssEntry) { return cssEntry && cssEntry.rules.length > 0 }) .map(function(cssEntry) { return cssEntry.rules.join(""); }) .reduce(function(css, out) {return out + css}, "") // Remove linebreaks console.log(outputCss.replace(/\n/g,"")) } findCriticalCSS(window, document); })()