CSS with PHP

Last week I re-designed the home page of my personal website as the previous version was quite plain looking, mostly because I'd never gotten around to updating it. I had a visual theme for most of the sub-pages, a strong graphic as a background 'column' on the left and side, with the graphic differing by section. My idea was to reuse these graphics on the front page, except randomly select two of them each time the page loaded.

Since they were background images, I couldn't add a dynamic element in the page itself to contain them. I could perhaps have defined several new CSS classes to apply to the body element and then inserted a class name with PHP, but with six images, picking two, that means 30 class names which seemed inelegant, plus would be a bit of a pain if I later added an new section. So instead of making the page itself dynamic, I decided to make the CSS dynamic instead.

From a coding point of view the implementation is very straightforward. You rename your CSS file to be .php and make sure you return the correct content type in the header by adding this as your first line:

<?php header("Content-type: text/css"); ?>

I then just declared an array with all my images in and use a built in PHP function to give me two random images:

$bg_images = array('vertical_essays.jpg','vertical_default.jpg','vertical_books.jpg','vertical_football.jpg','vertical_writing.jpg','vertical_blog.jpg');
$bg_keys = array_rand($bg_images, 2);

Then in the CSS itself I just select the appropriate image:

html {
	background-image: url('/image/<?= $bg_images[$bg_keys[0]] ?>');
	background-repeat: no-repeat;
	background-attachment: fixed;
	background-position: bottom left;
body {
	background-image: url('/image/<?= $bg_images[$bg_keys[1]] ?>');
	background-repeat: no-repeat;
	background-attachment: fixed;
	background-position: bottom right;

After getting this working I then decided it would be fun to have my main navigation boxes have a background colour related to the images which are shown. The DeGraeve.com Color Palette Generator lets you generate a palette of colours from any image, so I put each of my background images into it and got a set of 'vibrant' and 'dull' colours for each image. I stuck this into another array, using the image names as keys and simply alternating vibrant and dull colours into an array value:

$colours = array(
    'vertical_essays.jpg' => array('#440','#553','#670','#332','#9b7','#eee'), 
    'vertical_default.jpg' => array('#560','#452','#02d','#36a','#8a7','#995'), 
    'vertical_books.jpg' => array('#720','#532','#d10','#a64','#d90','#a85'),
    'vertical_football.jpg' => array('#581','#564','#8a3','#785','#9c5','#eee'),
    'vertical_writing.jpg' => array('#644','#c73','#f20','#e82','#f30','#ded'),
    'vertical_blog.jpg' => array('#732','#644','#c30','#965','#c96','#cbb')

I could then set the background and border colours of the navigation boxes using the two random keys I'd already generated. To keep it simple I just had the left two boxes take colours from the left image, and the right box take colours from the right image:

#nav li.cv {
	background-color: <?= $colours[$bg_images[$bg_keys[0]]][0] ?>
	border-color: <?= $colours[$bg_images[$bg_keys[0]]][1] ?>
#nav li.writing {
	background-color: <?= $colours[$bg_images[$bg_keys[0]]][2] ?>
	border-color: <?= $colours[$bg_images[$bg_keys[0]]][3] ?>
#nav li.gameplan {
	background-color: <?= $colours[$bg_images[$bg_keys[1]]][4] ?>
	border-color: <?= $colours[$bg_images[$bg_keys[1]]][5] ?>

Here is the end result:

dotrob.com screenshot

As you can see, generating your CSS with PHP is just as easy as generating HTML with PHP. Even with my fairly simple minded implementation of the idea you can achieve some nice tricks. However, there are some drawbacks I ran into:

  • Because you're now editing a PHP file, you might have some trouble persuading your auto-completing CSS editor to recognise what's going on
  • You're now going to have to handle caching yourself, as your CSS is no longer a static file - not much of an issue for a small site like mine, but could be an unnecessary overhead on a large site
  • Once you've added background colours to the mix you have to consider your text and link foreground colours, I just settled for a light grey with light blue links which worked OK (but not great) on all the colours - could be a bit of a maintenance problem in the future (and a readability problem now)

Fortunately, there are possible ways round all these issues, especially if you were considering this technique for a serious site rather than a one page vanity domain &#58;&#41; You could always use your PHP to generate the appropriate set of colours for you from a given base colour - this saves you having to work out text, non-visited and visited link colours for each background colour. For bonus points, you could probably add the code which extract the base colour from the image in the first place to end up with a completely flexible solution. The first two issues both have the same solution - use an actual CSS file as a template, thus preserving the editor features, but use a server-side pre-processor to deliver the file to the web. This allows you, among other thing, to extend CSS with variables as well as taking care of all the cache issues for you.