Unfortunately, you can't define variables, constants, or use formulas in CSS. But with some PHP, it becomes possible. The only problem is that dynamic stylesheets can't be as fast as static files... But this method won't slow down your site because PHP is used to generate a static .css file: you work with a dynamic stylesheet during development, then you can use only the generated static stylesheet on your "live" site.

The HTML index.htm

Here is the basic HTML page used for the example:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

  <head>
    <title>PHP-generated stylesheet demo</title>
    <link rel="stylesheet" href="css/screen.css" type="text/css" media="screen" />
  </head>

  <body>
    <div id="page">

      <div id="hd">HEADER</div>

      <div id="bd">
        <div id="main">MAIN</div>
        <div id="sub">SUB</div>
      </div>

      <div id="ft">FOOTER</div>

    </div>
  </body>

</html>

the file screen.css

The above html file links to a screen.css, here comes the code:

@import url(project.css.php);
@import url(project.css);

It's the interesting part: if you open project.css.php in your browser, you will see a blank page.
But each request to project.css.php will create or overwrite the file "project.css".

So we only need to create the file project.css.php since the file project.css will be generated automagically.

the file "project.css.php"

Here is an example of what this file can look like:

<?php 
  //VARS
    $darkColor  = "#41455f";
    $lightColor = "#ccb0bf";
    $pageWidth  = "45em";
    $subWidth   = "60%";
    $mainWidth  = 100 - intval($subWidth) . "%";
    $mainFloat  = "left";
    $subFloat   = ($mainFloat == "left" ? "right" : "left");

  //CAPTURE OUTPUT AND WRITE INTO A FILE    
    function callback($buffer){ file_put_contents("project.css",$buffer); }
    ob_start("callback");
?>

/*STYLESHEET*/
  
  /*layout*/
  #page       { width: <?= $pageWidth ?>; margin: auto;}
  #bd         { overflow: hidden; }
  #main       { float: <?= $mainFloat ?>; width: <?= $mainWidth ?>}
  #sub        { float: <?= $subFloat ?>; width: <?= $subWidth ?>}
  
  #hd, #ft, 
  #main, #sub { padding: 2em 0 }
  
  /*borders*/
  div         { border: 0 solid <?= $darkColor ?>;}
  #hd, #ft    { border-width: 1px 0;}  

  /*colors*/
  body        { background: <?= $darkColor ?>}
  #page       { background: <?= $lightColor ?>;}
  #main       { border-width: <?= $mainFloat == "right" ? "0 0 0 1px" : "0 1px 0 0" ?>; margin-left: -1px;}

/* END STYLESHEET*/

<?php 
 //END CAPTURE OUTPUT
  ob_end_flush();
?>

Some interesting features in the above example:

  • the first part titled "VARS" allows to define some variables that will be used in the stylesheet, which can bring a lot of comfort by avoiding repetitive work.
  • the second part titled "CAPTURE OUTPUT AND WRITE INTO A FILE" and the last part titled "END CAPTURE OUTPUT" simply generate the final file project.css
  • the more useful feature is to compute values used in the layout by entering custom formulas: here the width of column #main is computed from the width of column "#sub".
  • Some logic is used for the floats: depending which side the column #main is floated (left or right), the column #sub will be floated at the opposite side. Plus a 1px border is added on the left or right side of the column, depending if it's floated left or right.

For this article, I have kept the example very simple, but this approach bring lots of possibilities.

Development phase

During the development, when you refresh your browser,

  • the HTML page loads screen.css which in turn loads the files:
    • project.css.php - returns nothing but creates (or updates) the file project.css
    • project.css - automatically updated by the previous request

So this method is 100% transparent: the update is made when you refresh your browser, so you don't have anything to do and you can work like always.

Online version

When development is finished, you simply remove the first line of screen.css like this:

@import url(project.css.php);
@import url(project.css);

You can erase the file project.css.php but it's better to keep it so you can benefit from this whole approach again when you will need to make some changes.

You will simply have to restore the line @import url(project.css.php); and remember to work on the file project.css.php only, and never touch the generated file ''project.css'.

I hope you will find this approach useful, don't hesitate to share you thoughts !