<?php
function minify_css($str){
# remove comments first (simplifies the other regex)
$re1 = <<<'EOS'
(?sx)
# quotes
(
"(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)
|
# comments
/\* (?> .*? \*/ )
EOS;
$re2 = <<<'EOS'
(?six)
# quotes
(
"(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)
|
# ; before } (and the spaces after it while we're here)
\s*+ ; \s*+ ( } ) \s*+
|
# all spaces around meta chars/operators
\s*+ ( [*$~^|]?+= | [{};,>~+-] | !important\b ) \s*+
|
# spaces right of ( [ :
( [[(:] ) \s++
|
# spaces left of ) ]
\s++ ( [])] )
|
# spaces left (and right) of :
\s++ ( : ) \s*+
# but not in selectors: not followed by a {
(?!
(?>
[^{}"']++
| "(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)*+
{
)
|
# spaces at beginning/end of string
^ \s++ | \s++ \z
|
# double spaces to single
(\s)\s+
EOS;
$str = preg_replace("%$re1%", '$1', $str);
return preg_replace("%$re2%", '$1$2$3$4$5$6$7', $str);
}
$in = <<<'EOS'
p * i , html
/* remove spaces */
/* " comments have no escapes \*/
body/* keep */ /* space */p,
p [ remove ~= " spaces " ] :nth-child( 3 + 2n ) > b span i , div::after
{
/* comment */
background : url( " /* string */ " ) blue !important ;
content : " escapes \" allowed \\" ;
width: calc( 100% - 3em + 5px ) ;
margin-top : 0;
margin-bottom : 0;
margin-left : 10px;
margin-right : 10px;
}
EOS;
$out = minify_css($in);
echo "input:\n";
var_dump($in);
echo "\n\n";
echo "output:\n";
var_dump($out);
?>
PD9waHAKCmZ1bmN0aW9uIG1pbmlmeV9jc3MoJHN0cil7CiAgICAjIHJlbW92ZSBjb21tZW50cyBmaXJzdCAoc2ltcGxpZmllcyB0aGUgb3RoZXIgcmVnZXgpCiAgICAkcmUxID0gPDw8J0VPUycKKD9zeCkKICAjIHF1b3RlcwogICgKICAgICIoPzpbXiJcXF0rK3xcXC4pKisiCiAgfCAnKD86W14nXFxdKyt8XFwuKSorJwogICkKfAogICMgY29tbWVudHMKICAvXCogKD8+IC4qPyBcKi8gKQpFT1M7CiAgICAKICAgICRyZTIgPSA8PDwnRU9TJwooP3NpeCkKICAjIHF1b3RlcwogICgKICAgICIoPzpbXiJcXF0rK3xcXC4pKisiCiAgfCAnKD86W14nXFxdKyt8XFwuKSorJwogICkKfAogICMgOyBiZWZvcmUgfSAoYW5kIHRoZSBzcGFjZXMgYWZ0ZXIgaXQgd2hpbGUgd2UncmUgaGVyZSkKICBccyorIDsgXHMqKyAoIH0gKSBccyorCnwKICAjIGFsbCBzcGFjZXMgYXJvdW5kIG1ldGEgY2hhcnMvb3BlcmF0b3JzCiAgXHMqKyAoIFsqJH5efF0/Kz0gfCBbe307LD5+Ky1dIHwgIWltcG9ydGFudFxiICkgXHMqKwp8CiAgIyBzcGFjZXMgcmlnaHQgb2YgKCBbIDoKICAoIFtbKDpdICkgXHMrKwp8CiAgIyBzcGFjZXMgbGVmdCBvZiApIF0KICBccysrICggW10pXSApCnwKICAjIHNwYWNlcyBsZWZ0IChhbmQgcmlnaHQpIG9mIDoKICBccysrICggOiApIFxzKisKICAjIGJ1dCBub3QgaW4gc2VsZWN0b3JzOiBub3QgZm9sbG93ZWQgYnkgYSB7CiAgKD8hCiAgICAoPz4KICAgICAgW157fSInXSsrCiAgICB8ICIoPzpbXiJcXF0rK3xcXC4pKisiCiAgICB8ICcoPzpbXidcXF0rK3xcXC4pKisnIAogICAgKSorCiAgICB7CiAgKQp8CiAgIyBzcGFjZXMgYXQgYmVnaW5uaW5nL2VuZCBvZiBzdHJpbmcKICBeIFxzKysgfCBccysrIFx6CnwKICAjIGRvdWJsZSBzcGFjZXMgdG8gc2luZ2xlCiAgKFxzKVxzKwpFT1M7CiAgICAKICAgICRzdHIgPSBwcmVnX3JlcGxhY2UoIiUkcmUxJSIsICckMScsICRzdHIpOwogICAgcmV0dXJuIHByZWdfcmVwbGFjZSgiJSRyZTIlIiwgJyQxJDIkMyQ0JDUkNiQ3JywgJHN0cik7Cn0KCgoKJGluID0gPDw8J0VPUycKCnAgKiBpICwgIGh0bWwgICAKLyogcmVtb3ZlIHNwYWNlcyAqLwoKLyogIiBjb21tZW50cyBoYXZlIG5vIGVzY2FwZXMgXCovCmJvZHkvKiBrZWVwICovIC8qIHNwYWNlICovcCwKcCAgWyByZW1vdmUgfj0gIiBzcGFjZXMgICIgXSAgOm50aC1jaGlsZCggMyArIDJuICkgID4gIGIgc3BhbiAgIGkgICwgICBkaXY6OmFmdGVyCgp7CiAgLyogY29tbWVudCAqLwogICAgYmFja2dyb3VuZCA6ICB1cmwoICAiICAvKiBzdHJpbmcgKi8gICIgKSAgIGJsdWUgICFpbXBvcnRhbnQgOwoJY29udGVudCAgOiAgIiBlc2NhcGVzIFwiIGFsbG93ZWQgXFwiIDsKICAgICAgd2lkdGg6IGNhbGMoIDEwMCUgLSAzZW0gKyA1cHggKSA7CiAgbWFyZ2luLXRvcCA6IDA7CiAgbWFyZ2luLWJvdHRvbSA6IDA7CiAgbWFyZ2luLWxlZnQgOiAxMHB4OwogIG1hcmdpbi1yaWdodCA6IDEwcHg7Cn0KCkVPUzsKCgokb3V0ID0gbWluaWZ5X2NzcygkaW4pOwoKZWNobyAiaW5wdXQ6XG4iOwp2YXJfZHVtcCgkaW4pOwoKZWNobyAiXG5cbiI7CmVjaG8gIm91dHB1dDpcbiI7CnZhcl9kdW1wKCRvdXQpOwoKPz4=
input:
string(435) "
p * i , html
/* remove spaces */
/* " comments have no escapes \*/
body/* keep */ /* space */p,
p [ remove ~= " spaces " ] :nth-child( 3 + 2n ) > b span i , div::after
{
/* comment */
background : url( " /* string */ " ) blue !important ;
content : " escapes \" allowed \\" ;
width: calc( 100% - 3em + 5px ) ;
margin-top : 0;
margin-bottom : 0;
margin-left : 10px;
margin-right : 10px;
}
"
output:
string(251) "p * i,html body p,p [remove~=" spaces "] :nth-child(3+2n)>b span i,div::after{background:url(" /* string */ ") blue!important;content:" escapes \" allowed \\";width:calc(100%-3em+5px);margin-top:0;margin-bottom:0;margin-left:10px;margin-right:10px}"