Quick and Dirty CSS Templating Engine

Baseline Typography PrototypeI recently posted about creating some Baseline Grid CSS for my web typography. The first iteration was hand-coded for a specific font-size and line-height. A reader mentioned that there are CSS templating engines available called LESS and SASS respectively. They both allow you to treat CSS more like a real programming language, with constants and functions and other extensions to make it suck less. SASS works on the server-side, requiring Ruby. LESS, however, runs on the client-side, and is implemented as a Javascript library that executes at runtime. There are some nice features in both packages, but I didn’t really want to require yet another Javascript library in my code or install Ruby.

Why not use PHP?

The alternative, of course, is using PHP. Most PHP tutorials I saw on the subject required loading a templating engine like Smarty or littering your CSS with stupid-looking PHP “ tags. I hate the way that looks, and it makes for awkward typing.

So I tried something a lot simpler.

Getting rid of those ugly <? tags ?>

I used the new-ish PHP5 __halt_compiler() command to make a single-file, self-contained templating system. The “constants” are defined above the template “engine”, which is basically 7 lines of PHP tucked between lines 14 and 23 (below). After the engine code is normal syntax CSS file, with the addition of the template constants.

Here’s an abbreviated exmample of my baseline.css.php file; it’s included in HTML as a stylesheet with the normal &lt;link rel=&#039;stylesheet&#039;... statement.

<?php 
// Basic Typographic Dimensions: 

$basefontSize   = 12;
$gridSize       = 18;

$substitutions = array(
    '@timestamp'    =>    date('Y-m-d h:i:s'),
    '@basefont'     =>    $basefontSize . 'px',
    '@grid'         =>    $gridSize . 'px',
    '@basecolor'    =>    '#444'
);

/** DO REPLACEMENT ************************************/
$fp = fopen(__FILE__,'r');
fseek($fp,__COMPILER_HALT_OFFSET__);
$output = stream_get_contents($fp);
foreach ($substitutions as $key=>$value) 
    $output = str_replace("[$key]",$value,$output);
header("Content-type: text/css");
print $output; 
__halt_compiler();
/** BEGIN CSS ** GENERATED OUTPUT ** [@timestamp] **/

body {
    font-size: [@basefont];
    line-spacing: [@grid];
    color: [@basecolor];
}    

In particular:

  • On line 7, you define an array of the values you want to substitute. For example, @basefont is matched with a string containing the value of $basefontSize and the letters px.

  • On line 23 is the beginning of the actual CSS. Anywhere there is a [@basefont] (note the brackets), the value defined above will be substituted.

<

p>That’s it!

How It Works

Here’s what the code does:

  • When the file is loaded by the browser, the PHP code opens ITSELF. The code uses the fseek() command to skip over the PHP to process the end of the file where my CSS code lives.
  • Everything after the __halt_compiler() command is read into the variable $output. This should have normal CSS code in it.
  • It uses the str_replace() function to substitute the keys (e.g. @basefont) in $substitutions with the associated values (12px, the result of the calculation).
  • Once all substitutions are done, the modified CSS is sent to the browser with the necessary Content-Type: Text/css HTTP header.

Since it’s PHP, you can write anything you want to pre-calculate anything you might need. With a little elbow grease, you could do more sophisticated parsing of the substitution keys, evaluate PHP code, or even call functions. All I really want for myself, though, is some simple arithmetic and maybe a few color definitions, so I think this is fine for now.

Drawbacks

It’s PHP, so that means if you make an error in the code, your CSS file will not load. And since the file is being fetched as a stylesheet file, you won’t see any errors unless you:

  • Enable PHP Error Reporting, if it’s not already on.
  • Go directly to the URL of the stylesheet in your browser so you can see the errors.

Or…

  • Inspect the PHP Error Log on your web server. This is what I do, as I have a browser-accessible error log (here’s how I set it up on my Plesk-based CentOS server).

You might also forget to include all the @keys, or forget the [ ] around them. This is just an arbitrary convention I am using…you could use { } or whatever you like that is “search and replace”-friendly.

One last irritation is that since this is a PHP file, my code editor doesn’t syntax-highlight or auto-complete the CSS parts. I might convert this into a generalized loader that processes existing .css files to resolve that, but that sort of gets away from the one-file ideal. UPDATE: Besides, this is even simpler.

Check It Out

You can check out my working prototype and click on a few values to see how it recalculates. The templating should be fast enough to use for development, but for a production server you probably would want to copy the output into a static .css file. My code emits a timestamp to help keep things straight.

There are still errors in the baseline calculations due to loss of numerical precision, but the general idea seems to be working. Now I can quickly experiment with font and line height combinations to establish a particular typographic color and scale, with a pretty good starting point for the typography. If you’d like to play with the source code, you can download it here. Enjoy!

  • Download ZIP archive of the baseline grid prototype, so you can see it working in a more complex example. Requires PHP5 on your webserver.
  • Read about the Baseline Grid CSS stuff I’ve been experimenting with.

Other Solutions

Much thanks to the more clued-in developers for sending me these links. These are much more powerful processors, implemented in different ways toward the same goal of extending CSS with useful programmer features:

  • SASS or “Semantically Awesome Stylesheets” is a server-side CSS processor written in Ruby.

  • LESS.js is a “Dynamic Stylesheet Language” written in Javascript.

  • Joe Lencioni pointed me to the CSS Crush Preprocessor, which is a PHP implementation that looks tasty.