Using CSS to power up a website is a requisite in the contemporary web for non-Flash websites - and for good reason. CSS is powerful. It can make or break a website (although usually IE6 is doing the breaking). Even with its usefulness, designers and developers alike have have wished for more out of the language since its inception over twelve years ago with the CSS Level 1 Recommendation. Today, we're going to review some ways to Supercharge Your CSS With PHP Under The Hood.
Setting Things Up
Before the supercharging begins, we have to ensure that you have the proper requirements for doing so. We are going to go over two methods of making your CSS work with PHP, one that is short and sweet, and one that is a bit more elegant and less noticeable to the user. Both of these have the same basic requirement of a server running PHP. The more elegant version requires a bit more:
- Apache (running PHP, obviously)
- An editable .htaccess file
Setting Up the Simple Method
Web browsers are not that picky about file extensions when dealing with the HTML link tag. What they are picky about is the header data that it receives for that file. What that means is that you can link a *.php file with the proper header data in the place of a *.css file, and the browser will interpret the result just like standard CSS. To do so, add the PHP header that tells Apache to output the file as CSS:
- <?php header("Content-type: text/css; charset: UTF-8"); ?>
Then, just link to the PHP file like you normally would:
- <link rel="stylesheet" href="css/supercharged.php" media="screen">
Now that you have done this, you can--in theory--skip to the next section of the tutorial dealing with CSS variables and constants, if you would like; however, anyone who views your source is going to see that you have a PHP file where a CSS file should be. Additionally, just because the browser will interpret the result properly does not mean that it will necessarily do other things like caching the file in the browser. To fix this, we move on to the slightly more elegant version.
Setting Up the Elegant Method
Apache comes with a large number of .htaccess tricks. This is one of them. We are going to tell Apache to interpret all CSS files in a certain folder as PHP files, and the web browser (and your users) will, generally speaking, not know that you are doing so. First thing to do is to put the header data in your CSS file, just like the Simple Method:
- "Content-type: text/css; charset: UTF-8"); ?>
Then, instead of saving the CSS file as a *.php file, you save it as a *.css file, and you place it in a folder for CSS (in our example, ~/css/). Once you have done this, create a *.htaccess file in that folder and add the following:
AddHandler application/x-httpd-php .css<br />
This snippet tells Apache to interpret all CSS files in the folder with the *.htaccess file with the PHP script handler. If you do not have the ability to add this to a single folder or if you need this to be serverwide, you can also add this to the httpd.conf server configuration file for Apache. To do so, you would want to add the previous snippet right below the group of AddType and AddHandler declarations (like these from one of my servers):
- AddType application/x-httpd-php .php .php3 .php4 .php5
- AddType application/x-httpd-php-source .phps
- AddHandler cgi-script .cgi .pl
Just remember that if you do add this to your httpd.conf server configuration file that EVERY *.css file on the server now must have the PHP header for text/css prepended to it. This is why my recommendation is to add it via .htaccess
Start the Engine with CSS Variables
We ran a test on the top 100 blogs for external CSS files and total size. The average top 100 blog uses 4 external CSS files (@imports included) with an average total file size of 43.1K (uncompressed). The number of external CSS files ranged from 1 to 18. The total size of CSS ranged from to 0.2K to a whopping 307K. Note that this analysis does not include internal CSS within (X)HTML files. It does include nested CSS files called with @import directives.
That is a lot of CSS. Why is this? A lot of times it is because the CSS is being delivered uncompressed and not optimized. The more likely suspect is CSS bloat and poorly maintained code. One popular option to improving code maintainability is to implement CSS Variables through PHP.
What this means is that instead of having CSS like this (yes, this would produce an aberration of design, but it's good at illustrating the point):
- body {
- color: #000;
- background: #fff;
- font-size: 10px;
- }
- div#content {
- background: #ccc;
- font-size: 1.1em;
- }
- div#sidebar {
- color: #fff;
- background: #000;
- font-size: 1.0em;
- }
- div#footer {
- color: #555;
- background: #ccc;
- }
You could have CSS like this:
- $primaryTextColor = '#000';
- $secondaryTextColor = '#fff';
- $tertiaryTextColor = '#555';
- $primaryBGColor = '#fff';
- $secondaryBGColor = '#ccc';
- $tertiaryBGColor = '#000';
- $primaryTextSize = '10'; //pixels
- ?>
- body {
- color: $primaryTextColor?>;
- background: $primaryBGColor?>;
- font-size: $primaryTextSize?>px;
- }
- div#content {
- background: $secondaryBGColor?>;
- font-size: echo 1.1*$primaryTextSize ?>px;
- }
- div#sidebar {
- color: $secondaryTextColor?>;
- background: $tertiaryBGColor?>;
- font-size: $primaryTextSize;?>px;
- }
- div#footer {
- color: $tertiaryTextColor?>;
- background: $secondaryBGColor?>;
- }
Note that the long variable names is for illustration purposes only. Obviously, these variables can be as long as or as short as you like, and shorter variables make for smaller file sizes.
In the example above, we have used basic variables to set up a monochrome color scheme that could then be used throughout the website in other styles. These variables could easily have been interchanged with $color01, $color02, $color03, etc to produce similar effects. Often, designers and front-end web developers get asked by clients "Hey, can you make all of the text a little darker?" or "Can you make all of the text just a little bigger?" While using variables like this will not always be the best solution, it often would reduce the maintenance time when using many templating systems and blogging platforms (WordPress, Moveable Type, Expression Engine, etc) or corporate CMSes (Drupal, Joomla, Bitrix, etc).
An alternative method of storing the variables is to store the data in associate arrays (which is my preferred method), which produces code more like the following:
- $defaultCSS = array(
- 'color01' => '#000',
- 'color02' => '#fff',
- 'color03' => '#ccc',
- 'color04' => '#555',
- 'baseTextSize' => '10'
- );
- ?>
- body {
- color: $defaultCSS['color01']?>;
- background: $defaultCSS['color02']?>;
- font-size: $defaultCSS['baseTextSize']?>px;
- }
- div#content {
- background: $defaultCSS['color03']?>;
- font-size: echo 1.1*$defaultCSS['baseTextSize']; ?>px;
- }
- div#sidebar {
- color: $defaultCSS['color02']?>;
- background: $defaultCSS['color01']?>;
- font-size: $defaultCSS['baseTextSize'];?>px;
- }
- div#footer {
- color: $defaultCSS['color04']?>;
- background: $defaultCSS['color03']?>;
- }
Calculations in CSS
Once you have set things up for using PHP with your CSS, you can then do some neat things like calculations. Let's assume that you want to set up a system in you provide a bunch of DIVs on screen, each with a different type of element inside. Each element type (i.e. img, p, blockquote, etc) has a unique height and width controlled via CSS, and you want the amount of margin to be based off these values like so:
In this scenario, you want to set up a standardized grid that contains three different types of elements (img, p, and blockquote) encapsulated in two different containers (div and li). Every DIV has to be 550px wide and 250px tall, every LI has to be 600px wide and 300px tall, and each of the element types has a different height and width. The positioning of the elements on the inside must be dead center. Over time, the heights and widths of the different DIVs/LIs and elements will likely need to be changed. You could manual enter the amount of margin for each of the different elements and/or use extra class information on the container DIVs to add the appropriate amount of padding, but this is not that useful for quick changes, like those wanted by someone who is prototyping in the browser or who has 200 of these different elements for which they would have to modify data.
Step 1 - The Structure
First, we set up the XHTML content that we are going to style like so:
- <div><p>Lorem ipsum dolor sit amet tellus.p>div>
- <div><blockquote>Etiam quis nulla pretium et.blockquote>div>
- <div><img src="images/inset.png" alt="Inset Image" />div>
- <ul>
- <li><p>Lorem ipsum dolor sit amet tellus.p>li>
- <li><blockquote>Etiam quis nulla pretium et.blockquote>li>
- <li><img src="images/inset.png" alt="Inset Image" />li>
- ul>
Step 2 - The PHP Header and Variable Declarations
Next, we set up the PHP/CSS file that we are going to use to style the XHTML. This is where we declare the standard sizes of the different elements for use throughout the page.
- header("Content-type: text/css; charset: UTF-8");
- $divData = array(
- 'width' => '550',
- 'height' => '250',
- );
- $liData = array(
- 'width' => '600',
- 'height' => '300',
- );
- $blockquoteData = array(
- 'width' => '440',
- 'height' => '100'
- );
- $imgData = array(
- 'width' => '450',
- 'height' => '150'
- );
- $pData = array(
- 'width' => '480',
- 'height' => '130'
- );
- ?>
Step 3 - The CSS with Variables and PHP Calculations
Next, we continue the PHP file from Step 2 and utilize the variables that we set in calculations. Additionally, we set the calculated MarginX and MarginY values of the different elements to reduce the number of calculations necessary.
- div {
- width: $divData['width']?>px;
- height: $divData['height']?>px;
- }
- li {
- width: $liData['width']?>px;
- height: $liData['height']?>px;
- }
- div blockquote {
- width: $blockquoteData['width']?>px;
- height: $blockquoteData['height']?>px;
- $blockquoteData['divMarginX'] = $divData['width']-$blockquoteData['width'];
- $blockquoteData['divMarginY'] = $divData['height']-$blockquoteData['height'];
- ?>
- margin: echo blockquoteData['divMarginY']/2; ?>px echo blockquoteData['divMarginX']/2; ?>px;
- }
- div img {
- width: $imgData['width']?>px;
- height: $imgData['height']?>px;
- $imgData['divMarginX'] = $divData['width']-$imgData['width'];
- $imgData['divMarginY'] = $divData['height']-$imgData['height'];
- ?>
- margin: echo imgData['divMarginY']/2; ?>px echo imgData['divMarginX']/2; ?>px;
- }
- div p {
- width: $pData['width']?>px;
- height: $pData['height']?>px;
- $pData['divMarginX'] = $divData['width']-$pData['width'];
- $pData['divMarginY'] = $divData['height']-$pData['height'];
- ?>
- margin: echo pData['divMarginY']/2; ?>px echo pData['divMarginX']/2; ?>px;
- }
- li blockquote {
- width: $blockquoteData['width']?>px;
- height: $blockquoteData['height']?>px;
- $blockquoteData['liMarginX'] = $liData['width']-$blockquoteData['width'];
- $blockquoteData['liMarginY'] = $liData['height']-$blockquoteData['height'];
- ?>
- margin: echo blockquoteData['liMarginY']/2; ?>px echo blockquoteData['liMarginX']/2; ?>px;
- }
- li img {
- width: $imgData['width']?>px;
- height: $imgData['height']?>px;
- $imgData['liMarginX'] = $liData['width']-$imgData['width'];
- $imgData['liMarginY'] = $liData['height']-$imgData['height'];
- ?>
- margin: echo imgData['liMarginY']/2; ?>px echo imgData['liMarginX']/2; ?>px;
- }
- li p {
- width: $pData['width']?>px;
- height: $pData['height']?>px;
- $pData['liMarginX'] = $liData['width']-$pData['width'];
- $pData['liMarginY'] = $liData['height']-$pData['height'];
- ?>
- margin: echo pData['liMarginY']/2; ?>px echo pData['liMarginX']/2; ?>px;
- }
What this allows us to do now is to change the size of elements once at the top of the file and not recalculate 12 margin values (24 if the margin values were asymmetric). Understand that I am not suggesting this will be used in every one of your projects going forward, but this kind of technique has definite advantages over the standard "static" CSS method.
Shrink that CSS
As mentioned earlier, CSS can get pretty big. One thing that you can do to reduce CSS size is to automatically gzipping your CSS files. To do this, you have two options on how to do so: straight from Apache using mod_gzip / mod_deflate or use PHP's built-in compression methods, which we'll do here.
Step One - Set Up The Gzipping Snippet
Inside of our CSS file, we already have a snippet of PHP that sets up the header:
- "Content-type: text/css; charset: UTF-8"); ?>
All we have to do now, is add a single line of code setting an output buffer to use ob_gzhandler before the header declaration like so:
- ob_start("ob_gzhandler");
- header("Content-type: text/css; charset: UTF-8");
- ?>
It should be noted that there are other ways of doing gzip compression and they all have their benefits and shortcomings. My preferred method is using mod_deflate as mentioned earlier, but not all designers and developers have that option.
If($usingPHP==TRUE) { return 'Happiness'; }
Adding programming logic to a style sheet language is nothing new. Many websites determine what stylesheets they use based on URL, login status, or even the date. Here's a simple example that can be applied easily to blogs and e-commerce sites (amongst others). Let's assume that you have a h1 tag that is replaced using the Phark image replacement method described by the following CSS:
- h1 {
- width: 300px;
- height: 80px;
- text-indent: -9999px;
- background: url(images/logo.png) no-repeat;
- }
By adding a little PHP in the mix to determine the date when the CSS is loaded, you can then specify a different image for a holiday like Google often does with its Google Doodles (although they use a different technology solution to do so):
- $month = date('m');
- $day = date('d');
- if($month=='12' && $day=='25') {
- $logoSrc = 'images/holidayLogo.png';
- } else {
- $logoSrc = 'images/logo.png';
- }
- ?>
- h1 {
- width: 300px;
- height: 80px;
- text-indent: -9999px;
- background: url($logoSrc?>) no-repeat;
- }
This is just a super simple example. Your CSS is just waiting to be amped up by PHP. What you do with it can vary from person to person. One of my personal uses is to use it as a way of obscuring and embedding @font-face files using data URI strings and checking the referer requesting the file similar to parts of the technology that Typekit uses:
- <?php
- // This function grabs the file and converts it to a URI string
- function data_url($file, $mime) {
- $contents = file_get_contents($file);
- $base64 = base64_encode($contents);
- return ('data:' . $mime . ';base64,' . $base64);
- }
- $checkReferer = $_SERVER['HTTP_REFERER'];
- $checkMatch = preg_match('/yourdomain\.com/',$checkReferer);
- if($checkMatch) {
- ?>
- @font-face {
- font-family: FontName;
- src: local("FontName"), url(<?php echo data_url('FontFileName.otf','font/otf'); ?>) format("opentype");
- }
- <?php
- } else {
- /* This @font-face asset is unavailable */
- }
Subscribe to post feed