Pixelastic

You can cut our wings but we will always remember what it was like to fly.

CSS3 gradients with CSSTidy

Gradients are one of the new cool stuff CSS3 brought with it. Like the others cool things, it still suffer from a partial implementation and vendor-specific properties.

It also isn't correctly parsed by CSSTidy. Here I'll show you how to patch your CSSTidy to make it eat gradients correctly.

Quick and dirty patch

First, you'll need to edit the huge parse() method in csstidy.php. You'll have to add a condition to explictly tell CSSTidy not to discard -webkit-gradient and -moz-linear-gradient.

Just open your csstidy.php file, find the parse() method and locate the case 'instr' in the huge switch statement.

if (!($this->str_char === ')' && in_array($string{$i}, $GLOBALS['csstidy']['whitespace']) && !$this->str_in_str)) {
$this->cur_string .= $temp_add;
} else {
if ($this->sub_value=="-webkit-gradient" || $this->sub_value=="-moz-linear-gradient") {
$this->cur_string.=' ';
}
}

In bold, the else part to add. This will make sure your webkit and firefox gradient rules will get processed correctly.

I don't really understand WHY it work, but it does. The parse() method is a huge uncommented mess, it is quite difficult to understand it. There must be a better way, a more generic one than specifying some properties, but I didn't manage to come with anything better than that.

Fortunatly, the next part is cleaner.

Telling CSSTidy which properties not to merge

If you write a css like the following, only the latest (color:white) rule will get through CSSTidy.

body {
color:red;
color:white;
}

That's logical, because CSSTidy will remove any unused CSS declaration. Unfortunatly, this is not what we want, because we need to declare several background: rules, one for Webkit, and one for Firefox.

By looking at CSSTidy source code, we can find that it contain a quick fix to allow the cursor: property to be defined several time (to cope with the old cursor:pointer / cursor:hand issue).

I just extended this quick fix to work for other properties as well, and even managed to allow them to be passed as a config value.

Defining the config value

First, open the csstidy.php file, and around line 310 you should find a list of default config values. Just add the following :

$this->settings['multiple_properties'] = array('cursor', 'background');

This will define the default list of properties that are allowed to be defined several times in a css rule.

Next, we'll edit the set_cfg() method to allow the passing of array values. Just replace the else statement with this one :

else if(isset($this->settings[$setting]) && $value !== '') {
// Merging array settings
if (is_array($value) && is_array($this->settings[$setting])) {
$this->settings[$setting] = array_merge($this->settings[$setting], $value);
} else {
// Setting classic setting
$this->settings[$setting] = $value;
}

if ($setting === 'template') {
$this->_load_template($this->settings['template']);
}
return true;
}

You can now pass a list of properties to be added to the existing list by calling ->set_cfg('multiple_properties', array('property1', 'property2'));

Now, find the css_add_property() method, and around line 1066, change the if (strtolower($property) == 'cursor') if statement to this more generic one :

if (in_array($property, $this->get_cfg('multiple_properties')))

And now, in csstidy_print.php, find the _print() method, and replace the case PROPERTY block with this (more concise) one :

case PROPERTY:
// Converting back multiple properties
$multipleProperties = $this->parser->get_cfg('multiple_properties');
foreach($multipleProperties as $property) {
$propertyLength = strlen($property);
if (substr($token[1], 0, $propertyLength)==$property) $token[1] = $property;
}

// Applying correct casing
$caseProperties = $this->parser->get_cfg('case_properties');
if ($caseProperties==2) $token[1] = strtoupper($token[1]);
if ($caseProperties==1) $token[1] = strtolower($token[1]);

$out .= $template[4] . $this->_htmlsp($token[1], $plain) . ':' . $template[5];
break;

And that's it

You now can have gradients compressed with CSSTidy. Well sort of, because this is just a quick and dirty patch, as I'm not the creator of CSSTidy.

This could surely be improved in a less hacky way, for example by compressing the color code used in the gradients...

Comments

What version of CSSTidy are you using? I'm using version 1.3, and it has no 'csstidy.css' file nor does it contain many of the code refrences you are talking about here (for example, the string 'cursor' does not exist in any .php file).

http://sourceforge.net/projects/csstidy/files/CSSTidy%20%28PHP%2C%20stable%29/1.3/csstidy-1.3.zip/download is where I got the most recent version of csstidy...

thanks
ryanon 11/11/10
ryan
never mind you are using the SVN version...

You may want to check out the drupal version of csstidy:
http://drupal.org/project/csstidy

specifically the beta3 version. They do a nice job of adding css3 support to the data.inc.php file
ryanon 11/11/10
ryan
thanks by the way - your patch really saved me a ton of time.
ryanon 11/11/10
ryan
Thanks for your comments. I was indeed using the SVN version, but there seems to be a new version here : https://github.com/Cerdic/CSSTidy

I haven't tested it yet but will surely do it very soon.

I'll have a look at the Drupal module too.

(It seems that my automatic url parser/converter is having some issues on this comments... I'll fix that on the next commit)
Timon 15/11/10
Tim
Thanks for this tutorial Tim. This fix worked for me after I updated CSSTidy to the latest version available at https://github.com/Cerdic/CSSTidy... I'm having one problem with this that I'm hoping you may know how to address. If I set $this->settings['multiple-backgrounds'] = array('cursor', 'background')... then background properties are no longer being merged properly... if I have the rules:

#foo {
background-image: url(something.gif);
background-repeat: repeat-x;
}

CSSTidy results in #foo { background: repeat-x; }

When I comment out $this->settings['multiple-backgrounds'] = array('cursor', 'background'), it merges background properties properly again. I tried to turn off any css optimization too and that didn't fix the problem either. Do you get the same behavior?
Danon 16/11/10
Dan
I've never tried the multiple-background property myself so never ran into that issue.

I guess your best bet is to file a ticket for that on https://github.com/Cerdic/CSSTidy.
Timon 22/11/10
Tim
Dan or Tim
Did anything ever come with the problem Dan was having, because I'm having the same problem.
Ericon 7/3/11
Eric
Sorry, I still didn't try this. Did you file a ticket on the official GitHub repo ?
Timon 8/3/11
Tim
just ran into this issue ... through clicking around google i found http://reemcreations.com/javascript/css3-gradients/ ... look familiar?
simonon 7/4/11
simon
Whaaaouuu.

This guy took some of my articles and posted them on its own website, without even a source note.

Timon 8/4/11
Tim
The way I got things working was to download the drupal version, dump rules from data.inc & parse into my csstidy, then add the "quick and dirty" gradient patch. I also included some other gradient rules:

else {
if (
// Gradients
$this->sub_value=="-webkit-gradient" ||
$this->sub_value=="-moz-linear-gradient" ||
$this->sub_value=="-webkit-linear-gradient" ||
$this->sub_value=="-o-linear-gradient" ||
$this->sub_value=="-ms-linear-gradient" ||
$this->sub_value=="linear-gradient"
) {
$this->cur_string.=' ';
}
}

Then in the settings I added 'background' into 'multiple_properties'.

One last note on the gradient css: when including a fallback background color, declare 'background-color: #___;' rather than 'background: #___;' before the gradient rules.
Jeffon 28/9/11
Jeff
Well, for some reason this drupal version adds _0, _1, _2, etc... to multiple properties making them invalid, so only the first property works... So back to the drawing board.
Jeffon 29/9/11
Jeff
This guys seems to have worked it out: http://devilo.us
Jeffon 30/9/11
Jeff
Thanks for the update.

We shoud merge all our locals changes to a central repo.
The official CSSTidy repo does not seem to be maintained anymore, so I suggest we start submitting tickets and better, submitting patches to the one created by Cerdic : https://github.com/Cerdic/CSSTidy

Maybe @devilousdev would share his code too ? Have you contacted him ?
Timon 3/10/11
Tim
I've contacted @devilousdev, hopefully he'll share the source or at least how he did it! I'll keep you posted!
Jeffon 5/11/11
Jeff
... and 18 spam blocked

Adding a comment

Leave this field empty, it is only here to defeat spam bots
Will not be published