Out 10 2008
Easily Load Your Pages Faster With Compressed CSS
CSS brought us so many possibilities! Luckily, I’ve started my first HTML pages, back in 2004, using style sheets, so the old table based layout that old school designers still use these days simple because they stopped in time 10 years ago, are history.
Now that the possibilities are almost infinite, we started using more and more CSS in web design/(X)HTML structure. But most people forget the essentials, the page loading time and bandwidth spent.
OK, these days you probably don’t have much to worry about bandwidth, usually good web hosting provides “huge piles” of it, but what about page loading time?
Are your pages loading fast enough? Are you aware that if you are not cleaning your browser’s cache to test your site, your pages may load as a rocket for you, but take ages to load in your visitor’s browser?
All this is important, as it’s proved that globally most visitors leave your site if it takes more than 15 seconds to load (visually)… but things tend to go further, as DSL speed increases the waiting time decreases, which means that if a page won’t load in 5 seconds, the back button gets hit. This can be fatal for your internet presence.
There are several things you can do to improve your site’s performance, I might cover that in the future as well, but today let me talk you about CSS compressing (and uncompressing)!
On a style sheet, extra spaces, commentaries, tabs and line breaks makes it load slower, as it’s located at the head of an (X)HTML document (that’s where it should be!!), the whole CSS must load before you see something really happen and that made sense, as the page will be displayed progressively.
This will cost you more bandwidth spent, visitors that give up waiting and go away, and so on….
This is where the compressed style sheets come in, if we remove all unnecessary spaces, and everything that is not needed in our CSS, you site would definitely load faster. And this is more perceptible when you have many CSS rules, in fact you can spare thousands of extra characters and spaces.
So, I’ve made this class that really compresses your style sheet to the maximum.
Let’s take a look at a very simple example:
body { background: #fff url("imgs/bg.jpg"); color: #000; font-size: 12px; }
Now, how this would look like when compressed:
body{background:#fff url(imgs/bg.jpg);color:#000;font-size:12px}
You might be thinking, “OK but this will completely leave my CSS unrecognizable, I would take ages to find something in large style sheets“.
And I say, no it won’t, I’ve created a PHP class that not only compresses your CSS files, but also has the ability to revert any style sheet and uncompress it!
So it goes in both directions, you can compress and uncompress “on the fly” whenever you want.
The class has also the option to dump the results to a file, so you don’t even have to bother to past and copy your style sheets.
About reversing, of course, if you have your CSS with comments it won’t bring your comments back, but everything will be there in a “cleaned” and formatted style sheet.
Before I post the class, you probably want to look at real examples, so here it is a demonstration(opens in new window) of some of the capabilities of this class.
Now, without more delays, here is my CssShrink Class:
<?php /** * CssShrink * * @package CssShrink v1.0 - CSS Compressor & Uncompressor * @author João Romão (iceburn.info) * @version 2008 * @access public */ class CssShrink { // Alowed 'normal' CSS chars regex constant const chars_regex = '[^a-z0-9-_\{\}\>:;\*\.\#,\/\/\s\'\)\(\[\]!%@=\$\^]'; public static $css; /** * CssShrink::compressed() * * @return string */ public function compressed() { return self::filter($this->css); } /** * CssShrink::uncompressed() * * @return string */ public function uncompressed($str = null) { return self::reverse(self::prepare(is_null($str) ? $this->css : $str)); } /** * CssShrink::gain() * * @return int */ public function gain() { return (int)(strlen($this->css) - strlen(self::filter($this->css))); } /** * CssShrink::dump2file() * * @param mixed $filename * @param mixed $contents * @return bool */ public function dump2file($filename, $contents) { // Attempt to create file, if not exists if(!is_file($filename)) { touch($filename) or die('Attempt to create inexistent file failed!'); } // Attempt to chmod 777 before write chmod($filename, 0777); // Write to file if(file_put_contents($filename, $contents, LOCK_EX)) { chmod($filename, 0644); return true; } else { // chmod 644, even if cannot write to file chmod($filename, 0644); } return false; } /** * CssShrink::prepare() * * @param mixed $str * @return string */ private static function prepare($str) { // Globalize quotes format $str = str_replace('"', "'", $str); // Only process allowed CSS chars, and strip all others $str = preg_replace('/' . self::chars_regex . '/i', '', $str); // Remove CSS Comments $str = preg_replace('/(\/\*(.*?)\*\/)/s', '', $str); // Remove all unecessary spaces $str = preg_replace('/\s\s+/', ' ', $str); return $str; } /** * CssShrink::filter() * * @param mixed $css * @return string */ private static function filter($css) { $css = self::prepare($css); // Remove spaces around certain chars $css = preg_replace('/(\s)?(:|;|,|{|})(\s)?/s', '\\2', $css); /** * Final clean up: * - Semi-colon is not needed in last atribute * - In url() quotes are not needed */ $css = str_replace(array("('", "')", ';}'), array('(', ')', '}'), $css); return trim($css); } /** * CssShrink::reverse() * * @param mixed $css * @return string */ private static function reverse($css) { $css = self::prepare($css); // Remove unhandled line breaks and tabs $css = str_replace(array("\n", "\r", "\t"), ' ', $css); // Add spaces next to certain chars $css = preg_replace('/(\s)?(;|:|,|{|})(\s)?/s', '\\2 ', $css); // Some extra CSS beautify and cleanup $src = array('(', ')', ';}', "(''", "'')"); $rep = array("('", "')", '}', "('", "')"); $css = str_replace($src, $rep, $css); unset($src, $rep); // Add new lines after '{', ';' and '}' $src = array('{', '}', ';'); $rep = array(" {\n", ";}\n\n", ";\n"); $css = str_replace($src, $rep, $css); unset($src, $rep); // Temporary, turn the whole CSS into an array // TODO: Simplify the array process, and process everything as a string $css_array = array_map('ltrim', explode("\n", $css)); $ncss = array(); foreach ($css_array as $data) { if(!ereg('^;', $data)) { // Make indents $data = (preg_match('/({|}|,)/', $data) && !ereg('^(font)', $data)) ? str_replace(': ', ':', $data) : ' ' . $data; // Remove space after ':' in URL's $data = preg_replace("/(http:)(\s)/", '\\1', $data); // Add to new array $ncss[] = $data; // Free some memory unset($data); } } // Free some memory unset($css_array); // Correct selectors with no content (removes the ';' previously added) $css = preg_replace("/({)\n(\s){4};\n(})/s", "\\1 \\3", implode("\n", $ncss)); // Free some memory unset($ncss); return rtrim($css); } } // end of class 'CssShrink' ?>
Here are some usage examples:
<?php // Include our class require_once('./CssShrink.class.php'); // Initiate $css = new CssShrink(); // Input your CSS style sheet: $css->css = file_get_contents('./style.css'); echo '<fieldset>'; echo '<legend> Original CSS </legend>'; echo '<pre>',htmlspecialchars( $css->css ),'</pre >'; echo '</fieldset>'; // Compress it: $comp = $css->compressed(); // Echo it to the browser: echo '<fieldset>'; echo '<legend> Compressed CSS </legend>'; echo '<pre>',htmlspecialchars( $comp ),'</pre >'; // Verify the compressed gain over the input (the result is based on the chars diference) echo '<p><em>GAIN: <strong>', $css->gain(), '</strong></em></p>'; echo '</fieldset>'; // Optionally dump the compressed version to a file. //$css->dump2file('./new_style.css', $comp); // Uncompress (this works based on the css input) // In this case will only cleans up the original file... echo '<fieldset>'; echo '<legend> Original Uncompressed and cleaned CSS </legend>'; echo '<pre>',htmlspecialchars( $css->uncompressed() ), '</pre >'; echo '</fieldset>'; // ...but can be called to uncompress a previously compressed CSS echo '<fieldset>'; echo '<legend> Previous Compressed CSS Reverted (Uncompress operation)</legend>'; echo '<pre>',htmlspecialchars( $css->uncompressed($comp) ), '</pre >'; echo '</fieldset>'; ?>
UPDATE: I’ve also published this class at phpclasses.org.
You can download all the files, including documentation and usage example here.
Happy CSS compressing!
Não perca os meus artigos! Subscreva a minha feed RSS.

Outubro 14th, 2008 at 09:09
Nice blog and very nice article, I’ll give some good rating on phpclasses
Outubro 14th, 2008 at 14:51
Thanks David! I’m glad you like it.
Outubro 26th, 2008 at 22:23
Thanks the author of it blog! It is the present professional in PHP and optimization WWW. It has made many useful programs with which I use. Once again Thanks!
Excuse for my English
Junho 14th, 2009 at 14:05
I liked it but I think you could introduce in your system some other features like the tips you can read here: http://joaopedropereira.com/blog/2009/04/03/optimizacao-websites/ below the CSS title.