|
| 1 | +/* |
| 2 | +criticalCSS by @scottjehl. Run this on your CSS, get the styles that are applicable in the viewport (critical). The url arg should be any part of the URL of the stylesheets you'd like to parse. So, 'all.css' or '/css/' would both work. |
| 3 | +*/ |
| 4 | +(function(exports){ |
| 5 | + "use strict"; |
| 6 | + /** |
| 7 | + * opts |
| 8 | + * opts.sheets = document.styleSheets |
| 9 | + * opts.maxTop = window.innerHeight |
| 10 | + * opts.querySelector = function( selector ){ |
| 11 | + * return page.evaluate(function(s){ |
| 12 | + * return document.querySelector( s ); |
| 13 | + * },selector); |
| 14 | + * opts.matchMedia = window.matchMedia |
| 15 | + */ |
| 16 | + var criticalCSS = function( url, opts ){ |
| 17 | + var sheets = opts.sheets, |
| 18 | + maxTop = opts.maxTop, |
| 19 | + critical = []; |
| 20 | + |
| 21 | + var removeNull = function( el ){ |
| 22 | + return el !== null; |
| 23 | + }; |
| 24 | + |
| 25 | + var critCSSText; |
| 26 | + var aboveFold = function( rule ){ |
| 27 | + if( !rule.selectorText ){ |
| 28 | + return false; |
| 29 | + } |
| 30 | + var selectors = rule.selectorText.split(","), |
| 31 | + criticalSelectors = []; |
| 32 | + for( var k = 0, sl = selectors.length; k < sl; k++ ) { |
| 33 | + var elem = opts.querySelector( selectors[ k ] ); |
| 34 | + if( elem && elem.offsetTop <= maxTop ){ |
| 35 | + criticalSelectors.push( selectors[ k ] ); |
| 36 | + } |
| 37 | + } |
| 38 | + if( criticalSelectors.length ){ |
| 39 | + return criticalSelectors.join(",") + rule.cssText.match( /\{.+/ ); |
| 40 | + } |
| 41 | + else { |
| 42 | + return false; |
| 43 | + } |
| 44 | + }; |
| 45 | + |
| 46 | + sheets = Array.prototype.filter.call(sheets, removeNull); |
| 47 | + |
| 48 | + for( var i = 0, l = sheets.length; i < l; i++ ){ |
| 49 | + var sheet = sheets[ i ], |
| 50 | + href = sheet.href, |
| 51 | + rules = sheet.rules; |
| 52 | + |
| 53 | + rules = Array.prototype.filter.call( rules, removeNull ); |
| 54 | + |
| 55 | + if( url && href && href.indexOf( url ) > -1 ){ |
| 56 | + for( var j = 0, rl = rules.length; j < rl; j++ ){ |
| 57 | + |
| 58 | + var media = rules[ j ].media, |
| 59 | + matchingRules = []; |
| 60 | + if( media && opts.matchMedia( media.mediaText ).matches ){ |
| 61 | + var innerRules = rules[ j ].rules; |
| 62 | + for( var k in innerRules ){ |
| 63 | + critCSSText = aboveFold( innerRules[ k ] ); |
| 64 | + if( critCSSText ){ |
| 65 | + matchingRules.push( critCSSText ); |
| 66 | + } |
| 67 | + } |
| 68 | + if( matchingRules.length ){ |
| 69 | + matchingRules.unshift( "@media " + media.mediaText + "{" ); |
| 70 | + matchingRules.push( "}" ); |
| 71 | + } |
| 72 | + |
| 73 | + } else if( !media ){ |
| 74 | + critCSSText = aboveFold( rules[ j ] ); |
| 75 | + if( critCSSText && !critCSSText.match(/^\s+$/) ){ |
| 76 | + matchingRules.push( critCSSText ); |
| 77 | + } |
| 78 | + } |
| 79 | + critical.push( matchingRules.join( "\n" ) ); |
| 80 | + } |
| 81 | + |
| 82 | + } |
| 83 | + } |
| 84 | + return critical.join( "\n" ); |
| 85 | + }; |
| 86 | + |
| 87 | + exports.criticalCSS = criticalCSS; |
| 88 | + |
| 89 | +}(typeof exports === 'object' && exports || this)); |
0 commit comments