/** * Minify a CSS string * * @param string $css * * @param array $options To enable URL rewriting, set the value * for key 'prependRelativePath'. * * @return string */ protected static function _minify($css, $options) { $css = str_replace("\r\n", "\n", $css); // preserve empty comment after '>' // http://www.webdevout.net/css-hacks#in_css-selectors $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css); // preserve empty comment between property and value // http://css-discuss.incutio.com/?page=BoxModelHack $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css); $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css); // apply callback to all valid comments (and strip out surrounding ws self::$_inHack = false; $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@', array(self::$className, '_commentCB'), $css); // remove ws around { } and last semicolon in declaration block $css = preg_replace('/\\s*{\\s*/', '{', $css); $css = preg_replace('/;?\\s*}\\s*/', '}', $css); // remove ws surrounding semicolons $css = preg_replace('/\\s*;\\s*/', ';', $css); // remove ws around urls $css = preg_replace('/ url\\( # url( \\s* ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis) \\s* \\) # ) /x', 'url($1)', $css); // remove ws between rules and colons $css = preg_replace('/ \\s* ([{;]) # 1 = beginning of block or rule separator \\s* ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter) \\s* : \\s* (\\b|[#\'"]) # 3 = first character of a value /x', '$1$2:$3', $css); // remove ws in selectors $css = preg_replace_callback('/ (?: # non-capture \\s* [^~>+,\\s]+ # selector part \\s* [,>+~] # combinators )+ \\s* [^~>+,\\s]+ # selector part { # open declaration block /x', array(self::$className, '_selectorsCB'), $css); // minimize hex colors $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i', '$1#$2$3$4$5', $css); // remove spaces between font families $css = preg_replace_callback('/font-family:([^;}]+)([;}])/', array(self::$className, '_fontFamilyCB'), $css); $css = preg_replace('/@import\\s+url/', '@import url', $css); // replace any ws involving newlines with a single newline $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css); // separate common descendent selectors w/ newlines (to limit line lengths) $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "\$1\n\$2{", $css); // Use newline after 1st numeric value (to limit line lengths). $css = preg_replace('/ ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value \\s+ /x', "\$1\n", $css); $rewrite = false; if (isset($options['prependRelativePath'])) { self::$_tempPrepend = $options['prependRelativePath']; $rewrite = true; } elseif (isset($options['currentDir'])) { self::$_tempCurrentDir = $options['currentDir']; $rewrite = true; } if ($rewrite) { $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/', array(self::$className, '_urlCB'), $css); $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/', array(self::$className, '_urlCB'), $css); } self::$_tempPrepend = self::$_tempCurrentDir = ''; return trim($css); }