Created
September 18, 2015 08:34
-
-
Save james-Ballyhoo/04761ed2a5778c505527 to your computer and use it in GitHub Desktop.
Based off of https://gist.github.com/PaulKinlan/6284142 , but with support for media queries and dumps css to a textarea in a panel stuck to the top of the page. Only tested in Chrome, uses height of window to determine "critical path".
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(){ | |
if(document.querySelector("#_CRIT_CSS")){return;} | |
var container = document.createElement("div"); | |
container.id = "_CRIT_CSS"; | |
container.innerHTML = '<textarea cols=80 rows=20></textarea><button id="CRIT_FIND">Find Critical CSS</button><button id="CRIT_CLOSE">Exit</button>'; | |
container.style.position = "fixed"; | |
container.style.top = 0; | |
container.style.left = 0; | |
container.style.right = 0; | |
container.style.backgroundColor = "#FFF"; | |
container.style.zIndex = 99999999999999; | |
document.body.appendChild(container); | |
container.querySelector("#CRIT_FIND").addEventListener("click",function(){ | |
container.querySelector("textarea").value = findCriticalCSS(window,document); | |
}); | |
container.querySelector("#CRIT_CLOSE").addEventListener("click",function(){ | |
container.remove(); | |
container = null; | |
}); | |
function findCriticalCSS(w, d){ | |
//Setup our Pseudo selector killer, view height and critical nodes | |
var removePseudo = /([^\s,\:\(])\:\:?(?!not)[a-zA-Z\-]{1,}(?:\(.*?\))?/g; | |
var height = w.innerHeight; | |
var criticalNodes = []; | |
//Go find all the critical nodes | |
var walker = d.createTreeWalker(d, NodeFilter.SHOW_ELEMENT, function(node) { if(node === container){console.error("FOUND IT", node)};return node === container ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT; }, true); | |
while(walker.nextNode()) { | |
var node = walker.currentNode; | |
var rect = node.getBoundingClientRect(); | |
if(rect.top < height) { | |
criticalNodes.push(node); | |
} | |
} | |
console.log("Found " + criticalNodes.length + " critical nodes"); | |
//Grab loaded stylesheets | |
var sheets = document.styleSheets; | |
var outCss = Array.prototype.map.call(sheets,function(sheet){ | |
var rules = sheet.rules || sheet.cssRules; | |
//If there are rules | |
if(rules){ | |
return { | |
sheet: sheet, | |
rules: Array.prototype.map.call(rules, function(rule){ //Convert each CSSRule into a | |
try{ | |
if(rule instanceof CSSMediaRule){ | |
var subRules = rule.rules || rule.cssRules; | |
var css = Array.prototype.filter.call(subRules, function(rule){ | |
return criticalNodes.filter(function(e){ return e.matches(rule.selectorText.replace(removePseudo,"$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){ | |
return criticalNodes.filter(function(e){ return e.matches(rule.selectorText.replace(removePseudo,"$1"))}).length > 0 ? rule.cssText : null; | |
}else{ | |
console.warn("allowing", rule); | |
return rule.cssText; | |
} | |
}catch(e){ | |
console.error("Bad CSS rule", rule.selectorText); | |
throw e; | |
} | |
}).filter(function(e){return e;}) | |
} | |
}else{ | |
return null; | |
} | |
}).filter(function(cssEntry){return cssEntry && cssEntry.rules.length > 0}) | |
//Enable only this for debug dump | |
//.map(function(e){return {href: e.sheet.href, oldsize: e.sheet.cssRules.length, rules: e.rules, css: e.rules.join("\n")} }) | |
//Enable this for CSS | |
.map(function(cssEntry){ return cssEntry.rules.join(""); }) | |
.reduce(function(css,out){return out + css},"") | |
return outCss.replace(/\n/g,"").replace(/content\: \"(.)\"/g,function(a,e){ | |
return "content: \"\\" + escape(e).substr(2) + "\""; | |
}); | |
} | |
})() |
This is what i found in the console after try
critcss.snippet.js:1 undefined
critcss.snippet.js:31 FOUND IT <div id="_CRIT_CSS" style="position: fixed; top: 0px; left: 0px; right: 0px; background-color: rgb(255, 255, 255); z-index: 2147483647;">…</div>
(anonymous) @ critcss.snippet.js:31
findCriticalCSS @ critcss.snippet.js:32
(anonymous) @ critcss.snippet.js:15
critcss.snippet.js:39 Found 122 critical nodes
critcss.snippet.js:64 allowing CSSFontFaceRule {style: CSSStyleDeclaration, type: 5, cssText: "@font-face { font-family: "Libre Baskerville"; fon…-latin_latin-ext-regular.woff") format("woff"); }", parentRule: null, parentStyleSheet: CSSStyleSheet}
(anonymous) @ critcss.snippet.js:64
(anonymous) @ critcss.snippet.js:50
findCriticalCSS @ critcss.snippet.js:44
(anonymous) @ critcss.snippet.js:15
critcss.snippet.js:64 allowing CSSFontFaceRule {style: CSSStyleDeclaration, type: 5, cssText: "@font-face { font-family: "Libre Baskerville"; fon…e-v4-latin_latin-ext-700.woff") format("woff"); }", parentRule: null, parentStyleSheet: CSSStyleSheet}
(anonymous) @ critcss.snippet.js:64
(anonymous) @ critcss.snippet.js:50
findCriticalCSS @ critcss.snippet.js:44
(anonymous) @ critcss.snippet.js:15
critcss.snippet.js:64 allowing CSSFontFaceRule {style: CSSStyleDeclaration, type: 5, cssText: "@font-face { font-family: "Libre Baskerville"; fon…4-latin_latin-ext-italic.woff") format("woff"); }", parentRule: null, parentStyleSheet: CSSStyleSheet}
(anonymous) @ critcss.snippet.js:64
(anonymous) @ critcss.snippet.js:50
findCriticalCSS @ critcss.snippet.js:44
(anonymous) @ critcss.snippet.js:15
critcss.snippet.js:64 allowing CSSFontFaceRule {style: CSSStyleDeclaration, type: 5, cssText: "@font-face { font-family: "Didact Gothic"; font-st…t_greek_cyrillic-regular.woff") format("woff"); }", parentRule: null, parentStyleSheet: CSSStyleSheet}
(anonymous) @ critcss.snippet.js:64
(anonymous) @ critcss.snippet.js:50
findCriticalCSS @ critcss.snippet.js:44
(anonymous) @ critcss.snippet.js:15
critcss.snippet.js:68 Bad CSS rule undefined
(anonymous) @ critcss.snippet.js:68
(anonymous) @ critcss.snippet.js:50
findCriticalCSS @ critcss.snippet.js:44
(anonymous) @ critcss.snippet.js:15
critcss.snippet.js:69 Uncaught DOMException: Failed to execute 'matches' on 'Element': The provided selector is empty.
at <anonymous>:55:83
at Array.filter (<anonymous>)
at <anonymous>:55:54
at CSSRuleList.filter (<anonymous>)
at <anonymous>:54:62
at CSSRuleList.map (<anonymous>)
at <anonymous>:50:44
at StyleSheetList.map (<anonymous>)
at findCriticalCSS (<anonymous>:44:38)
at HTMLButtonElement.<anonymous> (<anonymous>:15:53)
(anonymous) @ critcss.snippet.js:69
(anonymous) @ critcss.snippet.js:50
findCriticalCSS @ critcss.snippet.js:44
(anonymous) @ critcss.snippet.js:15
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nothing happening here either...
Tested with FF 50 and Chrome 55