Tech Note: Make Web Pages Load Faster by Compressing CSS

Squeezing and concatenating
Technology • Views: 32,400

I originally started writing this Tech Note just to test our new source code formatting feature (powered by jQuery.Syntax), but it turned into more of a tech article than a note. I’ll be describing a technique for making pages load faster, that should be of interest to any web developer with experience in PHP and Linux shell script programming.

CSS Files Grow Up So Fast

Almost all modern websites use a technology named CSS (Cascading Style Sheets) to control the look of pages on the site. A CSS file is just an ordinary text file, consisting of rules that determine the appearance and position of page elements. For example, here are the rules that control the look of hyperlinks at LGF:

a {
    font-weight: bold;
    text-decoration: none;
    padding: 0 1px;
}
a:link {
    color: #06C;
}
a:visited {
    color: #09C;
}
a:hover {
    color: #FFF;
    background-color: #65BD54;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
}
a:active {
    color: #006600;
    background-color: transparent;
}

As you add more elements to your design, your CSS file (or files - there may be more than one) can get quite large, especially if you use lots of comments. The larger the file, the longer it takes to send over the Internet to a visitor’s browser, so optimizing CSS files can have a big payoff in terms of visitor experience.

You can do some basic optimization just by following good CSS coding practices, such as using shorthand rules and minimizing white space. But there’s a point at which further optimizations make the code difficult to read and modify; to name just one case, linefeeds are optional in a CSS file and can be completely eliminated, but removing all linefeeds means the entire file shows up on one monstrously long line. Browsers happily parse that monster line but it’s a nightmare scenario for human beings. Browser happy, but developer has a sad.

That’s where this Tech Note comes in.

The solution to the expanding CSS problem

I’m going to show you how to have the best of both worlds — fully commented, nicely readable and editable CSS code and highly optimized but almost unreadable (by humans) code that is much smaller and loads and executes faster. The key is to generate the optimized file whenever you make changes, leaving the editable, un-optimized version intact.

An alternative method is to dynamically generate the compressed version by embedding PHP code directly into the CSS file; but this incurs quite a bit of processing overhead every time the CSS file is loaded, and isn’t very scaleable as traffic increases. The method described here will generate a static CSS file with no extra overhead.

Squeeze it with PHP

Here’s the first step in the process; a short PHP script that optimizes CSS files by stripping out all comments and all unnecessary white space, including linefeeds and tabs. When I use this script to process LGF’s CSS file, the resulting file is about 20% smaller than the original; results will vary based on how many comments there are, what type of white space you use (tabs or spaces), etc.

We’ll name this script compress.php.

$css1 = array(
    "\r\n",
    "\r",
    "\n",
    "\t",
    '{ ',
    ' {',
    ' }',
    '; ',
    ';}',
    ': '
);
$css2 = array(
    '',
    '',
    '',
    '',
    '{',
    '{',
    '}',
    ';',
    '}',
    ':'
);
$input = '';
while (!feof(STDIN)) $input .= fgets(STDIN);
$input = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $input);
$input = str_replace($css1, $css2, $input);
echo $input;

The code’s pretty simple. Lines 2-25 define two arrays to use in replacing white space. The CSS file is read into the string variable $input in line 27, comments are removed (with a regular expression and preg_replace) in line 28, the white space is stripped out (with str_replace) in line 29, and then the resulting compressed string is sent to standard output with the echo command.

Calling PHP from the Linux command line

Those of you who speak PHP may notice that the script above never opens any files for reading or writing. Where is it getting the CSS code from? Where is it sending the optimized code to? How do it know?

The answer is that this little script is designed to run from a Linux command line (instead of the more common PHP environment, as a web page). It takes input from the system’s standard input stream, and sends output to, oddly enough, standard output. The global variable STDIN (in line 27) is an already-opened file handle to standard input, thoughtfully provided by PHP to save you the trouble of opening and closing the stream yourself.

This lets you use the Linux shell’s piping feature to send the PHP script the contents of a CSS file, and then send the processed output to another file, with a simple command like this:

cat styles.css | php /path/to/script/compress.php > styles.min.css

This line reads in the styles.css file, pipes it to the PHP compression script, then writes the output of the script to the file styles.min.css. (It assumes the current directory is where the CSS file resides.)

Putting it together with a shell script

OK, that’s pretty cool, but let’s take it to the next level by combining several optimized CSS files into one, thereby decreasing the loading time even more (since loading one file is exponentially faster than loading several files).

To do this, we’re going to write a bash shell script, so we’ll be able to generate a new optimized CSS file at any time just by typing the shell script’s name at the command line.

And to keep that typing to a minimum, we’ll name this script cssm (for “CSS Minimizer”):

#!/bin/bash

cd /path/to/cssfiles/

FILES="styles1
styles2
styles3"

for f in $FILES; do
    cat "$f.css" | php -q /path/to/script/compress.php | tr -d "\n" >> tmp.css
    echo -en "\n" >> tmp.css
done

mv -f tmp.css styles.min.css

If you actually use this script, of course, you’ll need to replace the paths and file names with the ones for your server, put the script somewhere in your bash include path, and give it executable permissions.

Then you can add the names of the CSS files (without the .css extensions) you want to compress/combine to the list variable FILES; the script loops through the filenames and compresses each one, then appends it to tmp.css, with a single line feed after each one just to make it easier to see where each compressed file starts. When the loop is finished, tmp.css is renamed to the actual file your web page will use, styles.min.css.

The safest way to replace web-visible files

Renaming the file this way is actually safer than directly creating a new version of styles.min.css — because if a user’s browser happens to be reading your previous styles.min.css while you’re writing to it, they’re likely to see a pretty screwed up web page or one with no styles at all. Creating a temporary file and then renaming it with the mv command solves this problem because it’s an “atomic” operation in Linux; any applications that are currently reading the file when it’s renamed won’t be interrupted. This is the best way to replace files that are heavily used in a web server environment.

Related

Jump to top

Create a PageThis is the LGF Pages posting bookmarklet. To use it, drag this button to your browser's bookmark bar, and title it 'LGF Pages' (or whatever you like). Then browse to a site you want to post, select some text on the page to use for a quote, click the bookmarklet, and the Pages posting window will appear with the title, text, and any embedded video or audio files already filled in, ready to go.
Or... you can just click this button to open the Pages posting window right away.
Last updated: 2023-04-04 11:11 am PDT
LGF User's Guide RSS Feeds

Help support Little Green Footballs!

Subscribe now for ad-free access!Register and sign in to a free LGF account before subscribing, and your ad-free access will be automatically enabled.

Donate with
PayPal
Cash.app
Recent PagesClick to refresh
The Pandemic Cost 7 Million Lives, but Talks to Prevent a Repeat Stall In late 2021, as the world reeled from the arrival of the highly contagious omicron variant of the coronavirus, representatives of almost 200 countries met - some online, some in-person in Geneva - hoping to forestall a future worldwide ...
Cheechako
3 days ago
Views: 120 • Comments: 0 • Rating: 1
Texas County at Center of Border Fight Is Overwhelmed by Migrant Deaths EAGLE PASS, Tex. - The undertaker lighted a cigarette and held it between his latex-gloved fingers as he stood over the bloated body bag lying in the bed of his battered pickup truck. The woman had been fished out ...
Cheechako
2 weeks ago
Views: 282 • Comments: 0 • Rating: 1