views:

113

answers:

2

Here is an example of what I'd expect:

Input:

a {
    background: red;    
}

p {
    background: red;    
}

strong {
    background: red;
    color: green;
}

Output:

strong{color:green;}
a,p,strong{background:red;}

Most optimisers will output something like this:

strong{background:red;color:green;}
a,p{background:red;}

Notice how it hasn't picked up the fact that strong, although it contains color: green;, also contains background: red; thus it can be grouped with the others?

Any help you could provide would be greatly appreciated

All the best

Iain

+2  A: 

Maybe CSSTidy could help, here.

If you take a look at this CSS "before", you'll see this portion of code :

a:hover{
    color: #DD6900;
}

a.admin:hover,a.mod:hover{
    color: #DD6900;
}

In in the CSS "after", you'll get :

a:hover,a.admin:hover,a.mod:hover,a.topictitle:hover {
color:#DD6900
}

Not sure it'll deal with every possible case -- but in some situations, it seems it's doing what you're asking ;-)

Pascal MARTIN
Thanks for the reply Pascal. I've seen a few optimizers that do just this - and it can be very handy. However, what I'm after is an optimizer that can deal with situations where (for example) five selectors all have the same background color, but they all have different margin values. This optimizer would recognise that the five selectors share a background color, so it would create a new group to accomodate just the shared background color and leave the rest of the properties in each selector alone.
Iain Fraser
A: 

Okay, so it seems like what I was after either doesn't exist or is very hard to come by, so I wrote a script that solves my particular problem. I'm pasting it here in the hope that someone sometime might find it useful.

<?php

$css = file_get_contents('test.css');

//Strip comments and whitespace. Tabs to spaces
$css = preg_replace("/\s{2,}/e", ' ', $css);
$css = preg_replace("/\/\*.*?\*\//", '', $css);
$css = str_replace("\t", " ", $css);
$css = str_replace(": ", ":", $css);
$css = str_replace(" }", "}", $css);
$css = str_replace("{", "{", $css);
$css = str_replace(";}", "}", $css);

//Break each rule out onto a new line
$css = preg_replace("/}\s*/", "}\r\n", $css);

//Break @ rules out onto new lines
$css = preg_replace('/(@.*?;\s*)/', '\0'."\r\n", $css);


//Parse CSS Rules
$parsed = array();
$css = explode("\r\n", $css);
foreach($css as $line => $rule){
    if (preg_match('/(.*?)\{(.*?)\}/i', $rule, $regs)) {
        $clean_selectors =  preg_replace('/\s*,\s*/', ',', $regs[1]);
        $clean_selectors =  preg_replace('/,\s*$|\s$/', '', $clean_selectors);
        $parsed[$line]['selectors'] = explode(',', $clean_selectors);
        $parsed[$line]['properties'] = explode(';', $regs[2]);
    } elseif(trim($rule) != '') {
        $parsed[$line] = $rule;
    }   
}

//Group CSS by property
$groups =  array();
foreach($parsed as $line => $css){
    if(is_array($css)){
        foreach($css['properties'] as $pline => $property){
            if(isset($groups[$property])){
                $groups[$property] = array_merge($groups[$property], $css['selectors']);
            } else {
                $groups[$property] = $css['selectors'];
            }

        }
    } else {
        $groups[$line] = $css;  
    }
}

//Output CSS sorted by property
foreach($groups as $property => $selectors){
    if(is_array($selectors)){
        asort($selectors);
        echo implode(",\r\n", $selectors)." {\r\n\t".trim($property).";\r\n}\r\n\r\n";
    } else {
        echo $selectors."\r\n\r\n"; 
    }
}

?>

Now, a couple of cavaets.

  1. No, this is not the most beautiful code in the world, it was done quickly to solve one particular problem I was having once and it's tailored pretty heavily to the CSS I've been given to work with. That said, it should be generic enough to work with most CSS you throw at it.

  2. It is the nature of CSS that sometimes the order in which a rule appears is important to the rendering of the final document. It is likely that if you just run all your CSS through this script that your page won't render as you expect anymore. I'm just using this script to group page-specific css on a web application that I have no layout control over. As each rule applies to a particular element on a particular page, I'm not expecting huge amounts of dodgyness when I group in this way - it's just going to make the CSS more maintainable.

Iain Fraser