Compress css files using php
Have you ever noticed the css files from giants like google, yahoo or facebook. If you look at them you will see they are very tightly coded no space, tabs or line breaks yet a very large css file. How they manage it to debug when it is not human friendly to view the code.
Get me first!
Before going on to any further discussion first download the codes what we are going to practice here now
They compress the css!
The fact is the dont code them like that. They have all those css in human friendly style with comments and line breaks. But some mechanism is used to remove those unused whitespaces and human friendly comments when sent to browser. On more, sometimes multiple css files are also merged into one programatically to reduce number of http requests.
What is the benifit?
When you have different css files you will need an extra http request to fetch that css file. Merging will reduce the number of http request. On other hand trimming whitespaces and comments will dramatically reduce the file size. Lets see by example of a page load using mozilla firebug plugin
STAGE 1: UNCOMPRESSED MULTIPLE CSS FILES
This page has 6 css file totalling to 30.8 KB. 2 secs required to load all and need 6 http request
STAGE 2: MERGED CSS FILE
I am using an php say css.php to include all css and merge them. Result says total load time remains same but onload greatly reduced. The number of total request is now 1
STAGE 3: MINIFIED CSS FILE
Now I have used regular expression to remove all css comments and whitespaces, linebreaks away. now it doesnt look human firendly but who cares since i have saved 9kb of bandwidth!
STAGE 4: gZip compressed css file
Now a days both servers and browsers support response to be send as gzip compressed format on fly. PHP uses zlib library for doing that on fly. What it generates is really a magic! lets see first
It has reduced the file size to only 4.5 KB from 21.2 kb saves 16.7 kb which is 79% !!!!
So by merging, minification and compression it saved a total of 85.3% bandwidth!!!
PITFALL
Although its saving a lots of bandwidth like a magic but it has a pitfall. That is its increasing cpu processing as its making many string operations. Although you can overcome it by output caching.
LETS CONTINUE TO CODING…
CSS Compression USING PHP
I have written a php class that will merge, minify and compress the css file. Optionaly it can also gzip the css using zlib. I am going to explain my coding here today.
class css {
private $css_files = array();
private $base_path = '';
$css files array includes all the link css files to include. the file must reside in your server. $base path defines the directory where you store all css files.
If you store all of your css files in http://www.yoursite.com/css then the base path is only“css“. Do not add trailing slash at the end of base path.
Constructor
/*
* Create css instance (Constructor)
* access: public
* @param $css_file: array() array of css files
* @param $base_apth: (optional) string, base path to css files
*/
public function __construct($css_files, $base_path = '') {
$this->base_path = $base_path;
$this->gz = $gz;
$this->add($css_files);
}
This functions takes all the css files as first parameter and base path parameter and stores them in class global array
when using use like this
$css_files = array(
'grid.css',
'ie.css',
'ie6.css',
'jquery.wysiwyg.css',
'printer.css',
'styles.css'
);
$css = new css($css_files, 'mlm/css');
to add a single css for minification just add as string
$css = new css('style.css', 'mlm/css');FUNCTION: ADD
/*
* Adds css files to array for compression
* @param $css_files: array() array of css files or single css file name
*/
public function add($css_files) {
// adds all css if array
if(is_array($css_files)) {
foreach($css_files as $css_file) {
$this->add($css_file);
}
}
else {
if(file_exists($this->base_path.'/'.$css_files))
$this->css_files[] = $this->base_path.'/'.$css_files;
}
}
This function add css files for processing. If any css file doesnot exist it excludes that file. If you need to add more css files you can use this like.
$css_files = array(
'grid.css',
'ie.css',
'ie6.css',
'jquery.wysiwyg.css',
'printer.css',
'styles.css'
);
$css->add($css_files);
to add a single css use like
$css = $css->add('another_css.css');
FUNCTION: OUTPUT
It generates the possible minified or gzipped output of css
/*
* Performs css compression and set output
* access: public
* @param $gz: (optional) boolean, if true compress output in gz format
*/
public function output($gz=false) {
/*
* callback for ob_start()
* Compress the css files using regular expression and return output
*/
function regx_removal($buffer) {
// remove comments
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
// remove tabs, spaces, newlines, etc.
$buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer);
return $buffer;
}
header('Content-type: text/css');
if($gz && extension_loaded('zlib'))
ob_start('ob_gzhandler');
ob_start("regx_removal");
foreach($this->css_files as $css_file)
include($css_file);
ob_end_flush();
}
Internal regx_removal function is callback of ob_start that uses regular expression to remove comment and unnecessary white spaces. It has one paramter which is set false by default. if set true it compress the css in gz format too. but it depends on zlib library support. Finally it includes all available css files to be processed and flush the output buffer.
To generate output without gzip compression use
$css->output();
To generate output with gzip compression use
$css->output(true);
FUNCTION: create_key
This function creates a uniqure string key by combining all css file names and using md5. It can be used for caching.
/*
* creates an md5 key for compressed css file
* that can be used for file name when cached
* retrun string
*/
public function create_key() {
$key = implode('', $this->css_files);
return md5($key);
}
FUNCTION: LINKS
Incase you don’t want to utilize this library. Instead want to add all css link rel tag, this function will generate the html for you
/*
* creates stylesheet link element to include all main files individually
* return string (formatted html)
* @param $media: css media type for all css files
*/
public function links($media='screen')
{
$out = '';
foreach($this->css_files as $css_file)
$out .= "\r\n";
return $out;
}
It has one parameter that is to tell the css media type. Default media type is screen.
Example use
$css_files = array(
'grid.css',
'ie.css',
'ie6.css',
'jquery.wysiwyg.css',
'printer.css',
'styles.css'
);
$css = new css($css_files, 'mlm/css');
echo $css->links();
It will produce
<link rel="stylesheet" type="text/css" href="mlm/css/grid.css" media="screen" /> <link rel="stylesheet" type="text/css" href="mlm/css/ie.css" media="screen" /> <link rel="stylesheet" type="text/css" href="mlm/css/ie6.css" media="screen" /> <link rel="stylesheet" type="text/css" href="mlm/css/jquery.wysiwyg.css" media="screen" /> <link rel="stylesheet" type="text/css" href="mlm/css/printer.css" media="screen" /> <link rel="stylesheet" type="text/css" href="mlm/css/styles.css" media="screen" />






Perfect!!!!!!!!
Thank you so much…
This is awesome, thanx for the great class. I wonder if this works with JavaScript as well…
Ofcourse you can, but for javascript I’ll suggest you to use jsminify also. Google for more info
What is the license that this script is released under ?
This is just a tutorial, so you don’t need to worry about any license restriction.