Last active
June 30, 2016 17:28
-
-
Save FMCorz/10015057 to your computer and use it in GitHub Desktop.
Chunk CSS into smaller chunks
This file contains hidden or 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
<?php | |
function chunk($css, $every = 4095) { | |
$chunks = array(); | |
$offsets = array(); | |
$offset = 0; | |
$selectorcount = 0; | |
$lastvalidoffset = 0; | |
$lastvalidoffsetselectorcount = 0; | |
$inrule = 0; | |
$inmedia = false; | |
$mediacoming = false; | |
// Remove the comments. Because it's easier, safer and probably a lot of other good reasons. | |
$css = preg_replace('#/\*(.*?)\*/#m', '', $css); | |
$strlen = strlen($css); | |
// Walk through the CSS content character by character. | |
for ($i = 1; $i <= $strlen; $i++) { | |
$char = $css[$i - 1]; | |
$offset = $i; | |
// Is that a media query that I see coming towards us? | |
if ($char === '@') { | |
if (!$inmedia && substr($css, $offset, 5) === 'media') { | |
$mediacoming = true; | |
} | |
} | |
// So we are entering a rule or a media query... | |
if ($char === '{') { | |
if ($mediacoming) { | |
$inmedia = true; | |
$mediacoming = false; | |
} else { | |
$inrule++; | |
$selectorcount++; | |
} | |
} | |
// Let's count the number of selectors, but only if we are not in a rule as they | |
// can contain commas too. | |
if (!$inrule && $char === ',') { | |
$selectorcount++; | |
} | |
// We reached the end of something. | |
if ($char === '}') { | |
// Oh, we are in a media query. | |
if ($inmedia) { | |
if (!$inrule) { | |
// This is the end of the media query, let's note that it is safe to split here. | |
$inmedia = false; | |
$lastvalidoffset = $offset; | |
$lastvalidoffsetselectorcount = $selectorcount; | |
} else { | |
// We were in a rule, in the media query. | |
$inrule--; | |
} | |
} else { | |
$inrule--; | |
if (!$inrule) { | |
// We exited the rule, it is safe to split here. | |
$lastvalidoffset = $offset; | |
$lastvalidoffsetselectorcount = $selectorcount; | |
} | |
} | |
} | |
// Alright, this is splitting time... | |
if ($selectorcount >= $every) { | |
if (!$lastvalidoffset) { | |
// We must have reached more selectors into one set than we were allowed. That means that either | |
// the chunk size value is too small, or that we have a gigantic group of selectors, or that a media | |
// query contains more selectors than the chunk size. We have to ignore this because we do not | |
// support split inside a group of selectors or media query. | |
debugging('Could not find a safe place to split at ' . $offset . ', ignoring...', DEBUG_DEVELOPER); | |
} else { | |
// We identify the offset to split at and reset the number of selectors found from there. | |
$offsets[] = $lastvalidoffset; | |
$selectorcount = $selectorcount - $lastvalidoffsetselectorcount; | |
$lastvalidoffset = 0; | |
} | |
} | |
} | |
// Now that we have got the offets, we can chunk the CSS. | |
$offsetcount = count($offsets); | |
foreach ($offsets as $key => $index) { | |
$start = 0; | |
if ($key > 0) { | |
$start = $offsets[$key - 1]; | |
} | |
// From somewhere up to the offset. | |
$chunks[] = substr($css, $start, $index - $start); | |
} | |
// Add the last chunk, from the last offset to the end of the string. | |
$chunks[] = substr($css, end($offsets)); | |
return $chunks; | |
} |
Other useful snippets:
http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/10164546.aspx
http://support.microsoft.com/kb/262161
A sheet may contain up to 4095 rules A sheet may @import up to 31 sheets @import nesting supports up to 4 levels deep
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Might be worth adding an:
too to warn about >= 32 import limit.