CodeinWP CodeinWP

Maintainable CSS3 Using PHP

Update (Jan 1/2012): The content of this article was probably obsolete the day it was written. It was written before I had much knowledge about CSS Pre-processors, which are a way better option than this. This was just a simple proof of concept, and a hacky way to avoid using vendor prefixes with CSS3.

Maintainable CSS3 Using PHPOne of the primary challenges that arises when dealing with CSS3 properties is the maintenance of the different proprietary prefixes. At least one solution has been offered to help prevent the so-called “forking” that results.

I think there is another way to help maintain the various repetitive CSS3 properties. What I’m proposing here will prevent you from having to organize your proprietary properties and will solve the problem of having to repeat the same values over and over again.

Some of the maintenance issues that arise can be avoided if you use PHP to generate your CSS, and use PHP’s capabilities to abstract multiple lines of CSS3 into a single line.

PHP to Generate CSS

Using PHP to generate your CSS is nothing new, and it’s been discussed before.

In a nutshell, here is the required code to get this to work. In your HTML you would have something like this (your usual run-of-the-mill CSS file reference):

<link rel="stylesheet" type="text/css"
media="all" href="styles/style.php" />

The only thing different in this code from a normal CSS reference is that instead of referencing a file with the extension “.css”, you’re calling a PHP file. Now you just have to put the following at the top of your PHP file:

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

This tells the PHP file to deliver itself to the client as CSS. The obvious benefit here is that instead of a static CSS file, you have a PHP-generated CSS file that allows you to take advantage of PHP’s functionality (and of course, the same would apply if you’re using a different back-end language).

The Function to Generate the CSS3

I’ve written a simple function to build a section of CSS3 code that contains all the basic CSS3 proprietary prefixes. All that’s needed is to call the function wherever you want the CSS3 to be inserted. Just give it two arguments: (1) the standard property name, and (2) the full value (including any units).

Here’s the function:

function css3_props($property, $value) {
  $css3 = "-webkit-".$property.": ".$value.";\n"
  ."  -moz-".$property.": ".$value.";\n"
  ."  -o-".$property.": ".$value.";\n"
  ."  -khtml-".$property.": ".$value.";\n"
  ."  ".$property.": ".$value.";\n";
  
  echo $css3;
}

That function would, of course, be placed at the top of your PHP/CSS file (or else included externally), and your CSS would later contain something like this:

#box-shadow {
  width: 200px;
  height: 200px;
  padding: 20px;
  <?php css3_props("box-shadow", "#ccc 5px 5px 10px"); ?>
}

The first three lines (width, height, padding) are just examples, and could be anything. The key line is obviously the last one, which calls the css3_props function.

The css3_props function builds a string in a variable called $css3. The string includes correct indenting, spacing, and line breaks to make the CSS look normal when it’s viewed after it’s generated. In that string, all the proprietary prefixes are included. Whatever arguments are passed in will determine which CSS3 property set is built. The last line echoes the full value of the string, so you don’t have to do that for each function call.

Benefits to This Method

  • Easy to maintain because you only need to change the value in one place
  • Keeps all the proprietary properties in the same order for all CSS3 references in your CSS
  • Keeps the standard property last, which is best practice
  • Keeps the entire chunk of related CSS stuff together
  • If any proprietary prefixes need to be added, you can just alter the function to suit

Obvious Drawbacks

  • You need to know some basic PHP (although you could get by with just copying and pasting what I’ve used here)
  • To test or run it, you need to use a PHP-capable server
  • If you’re coding in PHP, your text editor might not allow CSS help and auto-complete functionality
  • This particular function only works with the straightforward CSS3 stuff that has a simple property/value pair, like border-radius or text-shadow (i.e. doesn’t work with gradients, animation, multiple backgrounds, etc.)
  • Not all proprietary prefixes are necessary for every CSS3 property, so a lot of extra stuff will be added to your code

Your Thoughts?

I was going to include a demo, but it’s pretty useless since you can’t see the PHP anyhow. You can easily take the code I’ve shown above and just create your own example.

Also, keep in mind that I’m not a PHP expert, so if there’s anything I’ve missed or drawbacks I haven’t mentioned, please comment below, and I’ll update the article.

I’m sure someone could build an all-encompassing PHP function that would include some of the other more complex CSS3 techniques. If you know of someone who’s written this type of code before, or if you want to improve on this one, let me know in the comments and I’ll include a link to it here.

37 Responses

  1. Jonathan says:

    Not bad at all, the only (super minor) thing I’d change is use a heredoc to build the string – even after 5 years that much concatenation always makes my eyes water, even when it’s as nicely formatted as possible.

    A heredoc would make it really easy for yourself (or some other dev) in future to very quickly work out what’s going on (I know it’s obvious in this case – more of a general dev point).

    As for a lot of extra stuff being added to the CSS, I don’t see this sort of thing as a big drawback any more – gzip, caching etc. is great, so why worry about a few Kb at all? Of course if it adds 100K then that’s another matter, but if I was using that much CSS3 I’d seriously wonder how bad the site would look in IE6/7/8.

    • You’re absolutely right about the extra kb in the CSS, but that’s not what I was concerned about in this article.

      The problem is that if you have a box shadow with a shadow color of “#ccc” and you want to change that shadow color to “#bbb”, with all the proprietary properties you have to change the color in 2 or more different places in the same chunk of code. That’s just annoying.

      So, to alleviate this problem, all the proprietary prefixes are abstracted from the main CSS into a function. This way, you only need one line in your CSS. So, it’s maintenance savings, and more readable CSS, as opposed to speed/kb savings.

  2. Ive been told before that doing some sort of “Add Lib” type program is one of the best ways to learn the concpet of php.

    Anyone know where I can get an Add Lib script that is commented very well?

    • Vidyut says:

      Try Hybrid theme for wordpress – Justin Taddlock writes solid code, documents it well and if you are willing to pay for support, $25 for a year to join the support forums will have him helping you understand coding in a way you haven’t imagined. He is a mind reader and has an incredible knack for helping people. It is the best money I have ever spent on any kind of learning in terms of real understanding learning and value for money. Ten times that would still be modest.

      http://themehybrid.com

      Even if you don’t buy support, just using any of his themes and reading the code will teach you a lot. he is systematic and documents *everything*

      Another good idea (particularly if you aren’t into wordpress) is downloading Paul Irish’s html5 boilerplate. No clue on support or help in learning it, but its a lot of incredible work totally focused on delivering quality to all visitors while keeping opportunities expanding. Also good in terms of understanding interaction between javascript and css and html.

      http://html5boilerplate.com

      Matt Taylor has some excellent work on fluid layouts http://matthewjamestaylor.com/

      CSS Playground has hundreds of code samples that are well tested and documented. http://www.cssplay.co.uk

      …. it all depends on what exactly it is that you’d like to learn and whose work appeals to you. Feel free to contact me. I’ve got a whole load of super-excellent bookmarks that will very likely help, since I’m a self-learned webmaster too.

  3. Nice php concept. I always use LESS CSS, but because I don’t know Ruby, I can’t extend it with my own ideas.

  4. André Farzat says:

    A good way can be look the client’s user-agent to send back only the “right” property to browser. And in case that you don’t know the browser or the right property to an unknown browser, just send back all the property like your function does.

  5. swape says:

    I use http://www.conditional-css.com/ that dose the job well and much easier to maintain.

  6. Steve Robillard says:

    One obvious drawback is that you are dynamically creating the file every time it is called. This means you can’t cache the file. Since Google is now counting page load speed in page rankings it could hurt your Google page rank. It will definitely have a negative effect on page load for your users. and add unnecessary stress to your server. I would definitely consider generating this file before deploying.

    • Ahmad Alfy says:

      I was about to say that… To use the script to generate and upload the CSS file later… Whenever you want to make changes you go back to the file, regenerate your CSS and redeploy it.

  7. Jorgen says:

    In order to keep vendor specific selectors out of your code I would opt to use eCSStender instead of a server side solution. In general I don’t like to use any server-side technology to generate client-side presentation code.

  8. Mladen says:

    I tried to code css with PHP, but I found more likable solution: Compas SASS. It has slightly different syntax, but you get a grip with it in matter of minutes, and once you start coding css that way, you’ll never wanna code plain css again.

    The only thing needed is Ruby server installed on your development machine, and after that it outputs standard css file.

  9. Michael Mior says:

    I’m surprised no one’s mentioned Turbine (http://turbine.peterkroener.de) which already this and alot more implemented. I haven’t used it on a project yet, but it looks great!

  10. Hey cool! I came up with a very similar solution in one of my class assignments a few weeks ago. Check it out: http://scott-christopherson.com/school/imd-410/research/part-4.php

  11. Scott says:

    A good start but I think those last two drawbacks are kind of major. Particularly with the “-o-” and “-khtml-” ones, as far as I know there are very few properties with those prefixes.

    I think a better solution would be to create one function per property. This has a few advantages:
    1. You can use necessary prefixes only.
    2. You can remove prefixes later if a browser starts supporting the native syntax.
    3. You can customize the functions per property. For example you could set up the border radius function to do either the main property or individual corners (border-topleft-radius etc).

    One other drawback is that you’re running PHP every time the file is requested. You can reduce this with caching of course, but a better solution would be a LESS/SASS-style system where you compile the CSS into a static file. I do something similar with YUI to condense the whitespace and save a few more bytes.

    • Actually, I think it would be better to use just one function, but spit out the correct code depending on an argument that’s passed in. For example, an optional “support” argument could offer the ability to tell the function that you want khtml and/or Opera support.

      Also, “khtml” (if I remember correctly) is used for Konquerer, so some people might want it included for the properties Konquerer supports.

  12. Tom says:

    I tried server side CSS3 generation some time ago (http://webdev4.us/?p=50) but then turned to Less.Js which can accomplish the same and even more.

  13. steve says:

    took the liberty of making your code alittle better options wise:

    
    function css3Make($property,$value,$browser) {
    	foreach($browser as $agent)	{
    		$css .= "\t".$agent . $property.":".$value.";\n";
    	}
    	echo $css;
    }
    
    //where browser is an array, and would get passed this:
    $brow = array( '-moz-', '-o-', '-khtml-' ,'');
    

    Now you just pick and choose the browsers you want to support. Also good for Opera because it supports many CSS3 features without the need for the -o prefex
    This way you don’t have extra markup for browsers you won’t use, and the actual php function is smaller and easier to maintain.

    As for what was said above about making the css on the fly, that is a downside to using this method, but with proper caching, and some logic in the top of the file:

    
    if(file_exists('style.css'))    { header('Location: style.css'); }
    else{
       write file using code above and regular css.....
    }
    

    you’ll be fine.

    I just did a simple example, it can be improved 10 fold i’m sure.

  14. JuniHH says:

    “If you’re coding in PHP, your text editor might not allow CSS help and auto-complete functionality”. I hate that :-(

  15. Why are you including the -khtml Vendor Prefix, but not the -ms- one? Even though they don’t have a lot of interesting prefixed properties right now (a large part of the CSS Flexible Box Model module was available in PP4), it’s a better choice than using -khtml.

    Reason behind this is that the KHTML rendering engine internally translates -webkit properties to -khtml. The other way around it’s also true: WebKit translates both “-khtml” as “-apple” to their own “-webkit” before parsing the actual CSS property. For that reason, -webkit-box-shadow works well in both WebKit as KHTML-based browsers.

    Furthermore, when Microsoft decides to add new properties, ones like “-ms-transform” and “-ms-transition” are quite likely to be on top of their wish-list, as they’re what developers are screaming for :)

  16. kl says:

    PHP breaks HTTP caching! It doesn’t support cache validation and won’t send Last-Modified/E-Tag (unless you manually do this and write mini web server in web server, yo dawg)

  17. Not just some blunt self-promotion but rather to fuel more discussions on maintainability (the topic deserves far more attention): maintainability guide for additional ways to work more efficiently.

  18. Lars Gunther says:

    I hate to rain on your parade, but your solution won’t work, except for the easiest properties. Since the prefixes mean “experimental”, use at your own risk, syntax is varied and subject to change. And indeed they do change. I’ll just give two brief examples:

    Webkit (who came 2nd to this party) does border radius in a different way than Gecko. W3C will not use Mozilla syntax, but the Webkit one.

    Gecko does gradients with a different syntax than Webkit. Now the roles are reversed. W3C will use the Mozilla syntax, not Webkit’s original one.

    Some properties also require prefixed values, some do not.
    In many cases this solution will also add lots of cruft. E.g. Microsoft and Opera won’t do an -ms-border-radius but go straight to the final standard. (It would not have become a standard unless there had been experimental implementations first.)

    For this solution to work, the PHP script must know about every such detail, and be updated very often. This solution (and all the variants in the comments) is simply too simplistic.

    • Hey, Lars. Thanks for your input.

      I completely understand what you’re saying, but I don’t really see how this solution “won’t work” as you put it. As you can see in the “obvious drawbacks” section, I said that one drawback was that this would only work for the basic properties. I also mentioned that there would likely be extra unnecessary code, and that gradients wouldn’t work.

      Nonetheless, in my opinion, if the caching issue and any other server-related issues are taken into consideration, from a maintainability standpoint, this solution is just as good, and probably better than hard-coding all of the properties.

      But, as others have mentioned, a better solution would be to use a JS library that does this kind of thing on the client side. But, as with any solution, even that has its drawbacks.

    • Vidyut says:

      If you’re thinking of the idea as a template, it will likely not work. However, if you’re willing to code, it will not only work, it will storm. Most of the time, we don’t use every property under the sky. Most designers have preferences in terms of their own aesthetic sense. These are further reduced by the theme itself – we don’t use everything we can just because we can.

      Most of the time, we are playing around with say shadows, or rounded corners, or transitions, etc. And of course, we know the variations, or we wouldn’t be coding. It is infinitely easier to have a function to copy and vary once and drop into the theme as many times as needed.

      In fact, I had made a theme for a client where I did exactly that. I was playing with transparencies, shadows, RGBA and uniformly rounded corners. My css code was something like.

      //NOT working code
      #content {

      }

      and so on. I hadn’t created functions for things I didn’t intend to use.

      I had about 12 color schemes I could switch between in a blink.

      Unfortunately, I lost my code in a crash, and am not on good terms with the client, but it saved my sanity with a difficult client who wanted theme colors changed every other day.

      Worked beyond my expectations. Really well.

  19. Paul Herz says:

    Although I find the PHP within CSS very interesting (like LESS without the compilation,) I never knew about header() hacks! This should be interesting to mess with.

  20. Paul Ouano says:

    Caching, anyone?

  21. Vidyut says:

    If you are using php, you might as well use variables for colors, so that changing color schemes is a matter of just a few values and you’re rock solid.

    Other possibilities may be outputting fallbacks. For example, a bomb-proof color/hex value, followed by IE style RGBA followed by the proper RGBA.

    Or for applying random backgrounds (for example)

    Or delivering non-critical css based on browser sniffing. As in, if its not crucial that your 1px shadow (and such like) be seen by absolutely everyone including people spoofing browser strings, you could opt for delivering conditional css based on the browser rather than FIVE variations of the same thing (Safari/Chrome, Firefox, Opera, IE, Konqueror and the standard property) or is that six? Think of the amount of clutter you’ll get rid of if you are using a lot of shadows and transitions, and transforms, etc. Not to mention updating all that code. Let the browser cache the file. Its contents are unlikely to change unless the browser string changes, which is next to not going to happen.

    Some effort could club it with javascript like Modernizr that can verify the identity of the browser/features and provide corrections as needed, on the off-chance that the string IS spoofed. With a backup like that, you can even deliver more crucial css conditionally.

    Including, combining, minimizing et al from one file? Possible.

    I could write on and on. Basically, this idea opens up a whole Alladin’s cave in terms of performance. I’ve got a theme I’m planning which does some of this kind of thing and is a very highly styled thing with an incredibly light footprint.

  22. pomeh says:

    As others have said before, this is bad for web performance optimization: unnecessary work on the server (need to generate the file, and to generate it every times !), this lead to more time to load the file, while having no browser caching. We could make some improvements to the script, such as (from worse to best):
    – create a rewrite rule to use the .css extension in your HTML code, and rewrite it to match the PHP file as needed
    – generate the file on the fly only once, and saves it to a .css file. In this case, we should use a workaround to make sure we regenerate it when the content changes (for example, MD5 the content of the file, and write it to “yourcssname.themd5string.css”,
    – generated the file once manually, and point your <link> element to the generated one. This is good because the on-the-fly generated file will always be the same (except if you do changes to handle browsers specificity, but I personally think it’s a false problem here), so you can generate once and only once

    If you’re annoyed by the “generate the file manually” step, you could use a mix of that and the “generate the file on the fly” technique with something like a parameter or whatever you want to switch between modes, and of course deactivate the on-fly behavior while running production code.

    While I think solutions like this one saves time and headaches during development phase, it has a lot of drawbacks, many of them are bad for the user experience, so they are bad for you as a web developer.

Comments for this post are now closed.

Read the latest articles and tutorials if you'd like to have your say.