eDreamers Logo: a schematic face looking at 3 stars

Discover

the new eDare website, the commercial company providing services, projects and custom developments based on the eDreamers solutions.

PHP Enabled Stylesheets: Introduction to Skins

Author: Bertrand Potier
Last version: version 2 - Dec 03
Published on: PHPBuilder.com (v1.0), Canal HTML
Download Examples: ZIP (11 ko)

Introduction

This is the second edition of an article I posted on the website PHPBuilder.com in November 2002. Since then, the Dynamic Stylesheets principle was improved and simplified and this article is now updated to explain the new implementation.

CSS Stylesheets are a major improvement in the World Wide Web, allowing HTML to come back to its roots: a language to structure and publish content on the web, not to apply a visual formatting to that content. Unfortunately HTML and CSS have the same limitations: both are static languages!
From PERL to PHP, a lot of technologies are today available to move HTML to the dynamic age but why not, going even further and do the same with CSS? That's what I did when developing eDContainer (a container for web sites and web applications), having the following objectives in mind:

  1. To provide an external, user-friendly, skin file: the user doesn't have to edit the stylesheet, he may not be familiar with CSS and even if so, properly editing a stylesheet requires some experience.
  2. To not have to repeat general identical values like fonts and colors x times within the stylesheet: the value is defined once in the skin file and inserted automatically by PHP in the different locations within the stylesheet.
  3. To provide a solution to the implementation of skins or themes (similar to Winamp or Windows XP principles): several different Skins can be defined and dynamically switching from one to the other is possible.
  4. To be able to change some style behaviors dynamically, depending on some other non-skin or skin related configuration values (Contextual Behaviors).

If you're quite familiar with PHP and CSS, reading the above objectives will probably make you already think about some solutions to achieve them. When writing this article, I'm not saying that what is described here is the only way to do it. It's a way and do not hesitate to post comments: Let's start!

Principles

The main principle of this solution is that all the involved components, including the stylesheet, are PHP files that will be interpreted by the web server before being offered to the user. Each component will therefore be named with a .php file extension.
Illustrating this article requires the creation of the following files:

  1. a configuration file config.php defining the skin to use;
  2. The index index.php file that is our test file and will mainly contain HTML code using the styles defined in the stylesheet;
  3. Three skin files, each containing some skin configuration parameters as an array of key-value pairs (similar to the WINDOWS INI file way);
  4. The CSS stylesheet stylesheet.php file that is a normal CSS stylesheet but including some PHP code.

Less files could be created but you have to consider these as the skeleton of a bigger application. To avoid any confusion, in the scope of this article, these files are assumed to be stored in the same directory. The location of this directory is not important as long as it is located somewhere under the root of your web server. Let's move on to the definition of the files.

The Configuration File

Obvious enough, this file is meant to hold some configuration parameters, ease their management by externalising them from the main other files. In the scope of this article, we will only set one property defining the default skin to use when launching index.php.

<?php
// Default Skin
$CONFIG['defaultSkin'] = 'default'
?>

I usually use arrays with capital letters names to hold global parameters, meaning parameters also visible and used in other files than the one in which they are created.

The Index File

This file is the core of the demonstration as it not only holds the HTML code using the styles but also is the file including all the others:

  • the configuration file myConfig.php,
  • based on the skin variable, the skin file,
  • and the stylesheet stylesheet.php

First, the skin name defined in the configuration file is used to create the name of the skin file to load. This is giving us the opportunity to have the skin changed by providing a different name via an HTTP request for example. Some code is making sure that this is possible by only using the configuration file value in case no value is provided by either a parent script or an HTTP request (register_globals being OFF).

Then the PHP stylesheet is linked. It seems that the stylesheet is not interpreted when using the following code <style type="text/css" src="stylesheet.php"> so we will include the stylesheet definitions directly in the index file. I haven't managed to find a working solution to this problem since the version 1 of this article, even by using content-type headers as suggested by some readers, so any advice is welcomed.

The rest of the code is some pure HTML to test the styles and more explanations are provided later in this article.

<?php
// Loading Config File
require 'myConfig.php';

// Define which skin file to use
if ( isset( $_REQUEST['skin'] ) ) { 
    
$skin $_REQUEST['skin'];
} else if ( ! isset( 
$skin ) ) {
    
$skin  $CONFIG['defaultSkin']; 
}

// Loading the skin
require 'skin_'.$skin.'.php';

?>
<html>
 <head>
  <title>Sample Index File</title>
  <style type="text/css"><?php require 'stylesheet.php'?></style>
 </head>

 <body>
  
  <h1>Heading 1</h1>
  <p>
    Paragraph 1.1: Load <a href="index.php?skin=child">Child</a> or <a href="index.php">Default</a> Skin.
  </p>
  
  <h2>Heading 2</h2>
  <p>
   Paragraph 2.1
  </p>
  
  <h3>Heading 3</h3>
  <p>
   Paragraph 3.1
  </p>
  
  </body>

</html>

The Skin File

This file is meant for the end user who will configure the visual appearance of the application. Although being still a text/php file, its layout as well as the variables names are defined to be as user-friendly as possible. For this reason, I made the choice to not use variables but arrays that are giving the opportunity to name the different element in a very comprehensive way. Of course, an even more user-friendly solution is to provide some web screens to manage the skin parameters without having to edit the file but this is not the scope of this article.

The parameters that you want to make available via this Skin file are up to you. It fully depends on your stylesheet and what is the freedom that you want to give or not give to yourself or your end user. In the scope of this article, we will consider the following very simple example:

<?php
     
// Default Skin
     
$SKIN['page']['font'] = 'Verdana, Tahoma';
     
$SKIN['page']['fontsize'] = '10';
     
$SKIN['page']['fontunit'] = 'px';
     
$SKIN['page']['bgcolor'] = '#838383';
?>

I limited the number of visuals parameters to 4: font, font size, font unit and page background color. I recommend you that, when naming the first dimension of the $SKIN array, you link it to structural elements of your web site or application. Let's imagine that you define visual parameters for the footer section of your web site or application then declare a $SKIN['footer'] dimension. Another recommendation is to limit the number of dimensions to 2 to ease the management of the variables.

The skin_default.php file is now ready; let's move on to the stylesheet.

The CSS Stylesheet File

The PHP enabled stylesheet is nothing more that a CSS stylesheet with some PHP code in it. What is more interesting is the benefits of this association as, purely from a coding point of view, there's no complexity at all. Explanations will follow.

BODY, H1, H2, H3, H4, H5, H6, P { 
    font-family: <?php print($SKIN['page']['font']); ?>
    font-size: <?php echo $SKIN['page']['fontsize'].$SKIN['page']['fontunit']; ?>;
}

BODY {<?php echo 'background-color: '.$SKIN['page']['bgcolor'].';'?>}

<?php
 
for ( $i 1$i 6$i++ ) {
    echo 
'H'.$i.' { ';
    echo 
'font-size: '.( $SKIN['page']['fontsize'] + ( $i) ).$SKIN['page']['fontunit'].';';
    echo 
'font-weight: bold;';
    echo 
' }';
 }
?>

The Real Fun!

Let's now go through the benefits that this combination of PHP and CSS is providing us.

Code Generation

This is the most obvious use of PHP inside a CSS stylesheet but not the one with the highest added value. One example is the creation of repetitive style definitions like for the HTML headings, in/decreasing the font size automatically from the font size set in the Skin file:

<?php
 
for ( $i 1$i 6$i++ ) {
    echo 
'H'.$i.' { ';
    echo 
'font-size: '.( $SKIN['page']['fontsize'] + ( $i) ).$SKIN['page']['fontunit'].';';
    echo 
'font-weight: bold;';
    echo 
' }';
 }
?>

The main advantage is to not have to type the same thing over and over again. Now you also understand why we split the font size from the font unit in the skin. More seriously, this can automate the creation of style definitions in many various situations. To make this specific example even more useful, the "increase factor" of 6, here hardcoded, could also be put in a skin parameter.

Browser/Platform Based Behaviors

Usually, Javascript is being used in the index file of the web site in order to detect the browser/platform and load a different stylesheet. The following example will also show how to exchange variables between PHP and JavaScript, a question often seen in forums.

It happens that the difference between this and this browser/platform specific stylesheet are not so big and being able to adapt a unique stylesheet would ease everything. For example, font size (again) can be a problem depending on the Operating System (OS) of your visitor. Even at the same resolution as on your WINDOWS OS, the text will appear to be smaller on Linux and Mac OS platforms. I don't have the chance to own a MAC OS so the value tested may not be fully correct (code to be placed in the index.php file):

<script type="text/javascript" charset="ISO-8859-1"><!-- var browser = navigator.appName.toLowerCase(); var platform = navigator.platform.toLowerCase(); <?php echo 'var detect = '.$detect.';'; ?> if ( platform.indexOf("mac") != -1 && detect) { location.replace("index.php?detect=false&os=mac"); } </script>

Warning: Be careful, each browser on each platform reacts differently to those instructions and tests are required to make sure that your Javascript will behave as expected. Even the browser detection scripts on website such as Javascript.com cannot be considered as working correctly in all situations.

An easy way to make the $platform variable to the PHP code is to recall the index file with some parameters. This is almost invisible for the visitor but do not forget to include a $detect variable (initialised to true if not set) to avoid to enter a loop where the index file is replaced and replaced again. As soon as the parameter (here platform) is detected, the $detect variable is set to false.
The variable $platform is now available to the index file and therefore to the stylesheet. You can test it using a switch() { case: ; } block in the stylesheet.php file and, in our example, increase the font size by 2 in case a Mac based platform is detected (code to be placed in the stylesheet.php file):

BODY, H1, H2, h2, h3, h4, H6, P { 
    font-size:<?php 
        
switch( $os ) {
            case 
'mac';
               echo 
$SKIN['page']['fontsize'] + 2;
               break;
            default:
               echo 
$SKIN['page']['fontsize'];
            break;
        } 
        echo 
$SKIN['page']['fontunit'];
     
?>;
}

The value of this increment should depend on the font unit that you use (px, pt, em, etc.). This increment could also be declared as a new visual parameter to be included in your skin file as $SKIN['page']['fontIncrement'].

Contextual Behaviors

I call contextual behavior the capacity of a style or class within the stylesheet to depend on an external information that is, in most case, the value of another configuration or visual parameter. The code sample in the "Code Generation" section was demonstrating that kind of behavior by using the default text font size visual parameter to calculate the font size of the Headings in order to obtain a certain consistency between the different font sizes.
This is not the use of contextual behaviors I prefer. Contextual behaviors are a lot more interesting when used to make the stylesheet react on non visual parameters. Again, there can be hundreds of examples and choosing one is quite difficult so I will list some:

  • Adapt borders of an HTML table depending on the page layout: That's the main use I make of contextual behaviors in eDContainer. In eDContainer, the page layout can be easily customised by the web designer via the skin and, for example, the right menu column be displayed on the left instead. In this case, the column right border must now become a left border to comply with the new layout of the page. I implemented a simple test in the stylesheet that change the border depending on if this layout configuration parameter is set to 'left' or 'right'.
  • Adapt font size based on the length of a string: Let's imagine that the main title of your website or any other text is displayed from a PHP variable that you define in a configuration file or in your index file. This text is displayed in a specific area of your page and this area is limited in width. The longer this text is, the smaller the font size should be (still without certain boundaries) to be able to display it properly. PHP can easily be used in the stylesheet to determine the number of characters of this string and you can set the font size based on it.
  • Do not load unused styles: If you use a skin parameter to hide a zone of your site or application structure then the related CSS styles and class are of no use. You can use the same parameter turning off the display of the zone in the stylesheet file stylesheet.php to not output to the generated file the class(es) used for this zone. This optimises the generated stylesheet which therefore only contain the styles truly needed.
  • Anything that you could think of ... (post your ideas)

Skin Inheritance

New skins can be created and can inherit parameters defined by a parent skin. Let's create a new skin_child.php file, inherit from the parent skin and redefine only the parameters that we want to change. For example, let's increase the font size to increase readibility:

<?php
     
// inherit from parent skin
     
require_once 'skin_default.php'

     
// only redefine the values to be changed
     
$SKIN['page']['fontsize'] = '14';
     
$SKIN['page']['bgcolor'] = '#FFFF99';
?>

This new value simply overwrites the one stored in the parent skin loaded with the PHP require statement. You now have two methods to activate this skin: set it as default in the configuration file (see above) or create a link (in index.php) to specifically load it as follows:

<a href="index.php?skin=child">Load Child Skin</a>

Inheritance can help defining totally new skins from a parent one with just a few lines redefining some key parameters as illustrated below with the print skin.

Create Skin for Printing

How to make contents displayed through a website printable is a question that is coming back in the mind of many web developers and webmasters. Skins can offer a good answer to that, especially if you've used them to also influence your HTML code as suggested earlier. Skins inheritance is making it even easier. Taking the eDreamers website example, I will explain here how the solution to print the content pages was built based on the principles described in this article:

  1. In the index.php, several areas are created (header, body, sidebar, footer, etc. ) thanks to HTML tables and are all controlled via a skin parameter allowing them, or not, to be displayed.
  2. The configuration file sets the "eDreamers" skin as being the default one. The file skin_eDreamers.php is therefore defining the original look & feel of the site. This includes displaying all areas, limiting the width of the body zone, not underlining links etc.
  3. A new skin skin_print is created to specifically print the contents displayed in the body zone. It inherits from the skin_eDreamers.php to keep the basic parameters such as the font and redefines the following parameters: set header, sidebar, footer display to off, set body width to 100%, underline links, etc.
  4. A "Print page" link is created in the index.php and is available at the bottom of each content pages. This link simply calls the "print" skin as described in the previous section with the "child" skin example.

That's it, simple and quite efficient. You can test the result by using the "Print page" link on the bottom of this page. I've not developed these mechanisms specifically for the eDreamers website. I created the website thanks to eDContainer, which is what I call a container for web site and applications. It implements mechanisms described here (skins, print links, user stylesheet, etc. ) and make them available out-of-the-box.

Conclusion

Bringing the power of PHP inside the already powerful CSS stylesheets can bring you a lot of new opportunities and as many problems. The importance of a good design prior to development (or during a prototyping phase) is always essential and always more essential when dealing with technologies as rich as PHP and CSS, and this is all the more true when they are combined.

That the reason why making a clear distinction between the structure, the visual and the content related aspects of your web sites or web applications is an absolute must if you want to achieve good results. Skins should always provide a real added value compared to the CSS stylesheet: you'd better stop the moment you start to create parameters such as $SKIN['table']['borderWidth'].

Print page | all | view