How To Generate Monochromatic CSS Stylesheets Within Seconds Using PHP

Posted by Tim Koschützki, on Jun 07, 2007 - in PHP & CakePHP » Other

Hi folks! As a follow-up to my previous article Control your CSS via PHP - Good Stuff I have tried to implement the techniques explained there to build monochromatic stylesheets within seconds. First off, I will explain to the ones, that do not know yet, what a monochromatic color scheme is.

What Is A Monochromatic Color Scheme?

The monochromatic color scheme uses variations in lightness and saturation of a single color. It looks clean and elegant. Monochromatic colors go well together, producing a soothing effect. The monochromatic scheme is very easy on the eyes, especially with blue or green hues.
You can use it to establish an overall mood, which we will do later with the css generation. The primary color can be integrated with neutral colors such as black, white, or gray. However, it can be difficult, when using this scheme, to highlight the most important elements.

The monochromatic color scheme is perfect for our task of generating CSS via PHP based on forming shades of a base color. First off, please download the PHP Script for generating CSS. Place it in any folder on your website or your local php installation.

Setting Up Our CSS Generation Environment

Next off we will borrow some XHTML / CSS code from my buddy Paul O'Brian, one of the greatest CSS Gurus on the net. His site features plenty of css goodness, tutorials and effects I am sure you haven't seen before. It is definately worth to check out! We will take the code of his universal three column layout that works in most browsers and allows any column to be the longest. Save that markup to a file named "test.html" in the same folder where you saved the php file. Now, in that same folder, create a file "css.php" where you insert the following CSS code:

php
  1.  
  2. // Tell the browser that this is CSS instead of HTML
  3. header("Content-type: text/css");
  4.  
  5. // Get the color generating code
  6. require_once("csscolor.php");
  7.  
  8. // Define a couple color palettes
  9. //$base = new CSS_Color('C9E3A6');
  10. $base = new CSS_Color('99E456');
  11.  
  12. // Trigger an error just to see what happens
  13. // $trigger = new CSS_Color('');
  14.  
css
  1. /* CSS Document */
  2. * {margin:0;padding:0}
  3. p {margin-bottom:1em}
  4. ul{margin-left:20px;margin-bottom:1em}
  5. /* commented backslash hack v2 \*/
  6. html, body{height:100%;}
  7. /* end hack */
  8.  
  9. body {
  10.   background:#<?php echo $base->bg['-2'] ?> repeat-y left top;
  11.   color: #FFF;
  12. }
  13. #outer{
  14.   margin-left:130px;
  15.   margin-right:130px;
  16.   background: #<?php echo $base->bg['0'] ?>;
  17.   border-left:1px solid #000;
  18.   border-right:1px solid #000;
  19.   margin-bottom:-52px;
  20.   min-height:100%
  21. }
  22. #header{
  23.   position:absolute;
  24.   top:0;
  25.   left:0;
  26.   width:100%;
  27.   height:70px;
  28.   background: #<?php echo $base->bg['-3'] ?>;
  29.   border-top:1px solid #000;
  30.   border-bottom:1px solid #000;
  31.   overflow:hidden;
  32. }
  33. #left {
  34.   position:relative;/*ie needs this to show float */
  35.   width:130px;
  36.   float:left;
  37.   margin-left:-129px;/*must be 1px less than width otherwise won't push footer down */
  38.   z-index:100;
  39.   left:-1px;
  40. }
  41. #left p,
  42. #right p {padding:3px}
  43. #right {
  44.   position:relative;/*ie needs this to show float */
  45.   width:130px;
  46.   float:right;
  47.   margin-right:-129px;/*must be 1px less than width otherwise won't push footer down */
  48.   left:1px;
  49.   color: #000;
  50. }
  51. #footer {
  52.   width:100%;
  53.   clear:both;
  54.   height:50px;
  55.   border-top:1px solid #000;
  56.   border-bottom:1px solid #000;
  57.   background-color: #<?php echo $base->bg['-4'] ?>;
  58.   text-align:center;
  59.   position:relative;
  60. }
  61. #clearheader{height:72px;}/*needed to make room for header*/
  62. #clearfooter{clear:both;height:52px;}/*needed to make room for footer*/
  63. * > html #clearfooter {float:left;width:100%;}/* ie mac styles */
  64. #centrecontent {
  65.   width:100%;
  66.   float:left;
  67.   position:relative;
  68.   z-index:1;
  69.   margin:0 -1px;/* moz fix*/
  70.   color: #000;
  71. }
  72. /* css stuff below is just for presentation and not needed for the demo */
  73. #centrecontent p { padding: 0 20px; }
  74. h1 {font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: lighter; font-size: 150%; padding: 20px;}
  75. #left span {
  76.   display:none
  77. } 
  78. #left a:hover {
  79.   text-decoration: none;
  80.   text-decoration: none;
  81.   color:#222;
  82.   background: #FFF;
  83. }
  84. #left a:hover span {
  85.   display:block;
  86.   position:absolute;
  87.   left:130px;
  88.   width:150px;
  89.   z-index:20;
  90.   background:#fff;
  91. }
  92. @media all and (min-width: 0px){
  93.   #left a:hover span {
  94.   top:150px;
  95.   }
  96. }
  97. #footer a, #left a { color:#FFF; }
  98. #footer span {
  99.   display:none
  100. } 
  101. #footer a:hover {
  102.   text-decoration: none;
  103.   color:#222;
  104.   background: #FFF;
  105. }
  106. #footer a:hover span {
  107.   display:block;
  108.   position:absolute;
  109.   top:-95px;
  110.   width:150px;
  111.   z-index:20;
  112.   background:#fff;
  113.   left:50%;
  114. }
  115. html>body #minHeight{float:right;width:0px;height:100%;margin-bottom:-52px;} /*safari wrapper */

What this does is simply using our css generation script to alter the code of the original css file from the universal three column layout. We create a base color ($base = new CSS_Color('99E456');) and form shade variations for the two navbars, the header and the footer:

css
  1. body {
  2.   background:#<?php echo $base->bg['-2'] ?> repeat-y left top;
  3.   color: #FFF;
  4. }
  5. #outer{
  6.   margin-left:130px;
  7.   margin-right:130px;
  8.   background: #<?php echo $base->bg['0'] ?>;
  9.   border-left:1px solid #000;
  10.   border-right:1px solid #000;
  11.   margin-bottom:-52px;
  12.   min-height:100%
  13. }
  14. #header{
  15.   position:absolute;
  16.   top:0;
  17.   left:0;
  18.   width:100%;
  19.   height:70px;
  20.   background: #<?php echo $base->bg['-3'] ?>;
  21.   border-top:1px solid #000;
  22.   border-bottom:1px solid #000;
  23.   overflow:hidden;
  24. }
  25. #footer {
  26.   width:100%;
  27.   clear:both;
  28.   height:50px;
  29.   border-top:1px solid #000;
  30.   border-bottom:1px solid #000;
  31.   background-color: #<?php echo $base->bg['-4'] ?>;
  32.   text-align:center;
  33.   position:relative;
  34. }

Now change the line

in your site.html file and then launch it via a browser. You should see something like this:

Picture of first generated layout

Changing The Base Color For Some Cool Results

It is not exactly pretty, but we can play around with the base color a bit:

$base = new CSS_Color('98ccac');
Picture of second generated layout

$base = new CSS_Color('ccac99');
Picture of thirdgenerated layout

$base = new CSS_Color('ccccff');
Picture of forth generated layout

What Other Uses For This Can We Think Of?

Now you could also add other colors to highlight some other parts, like singleing out the footer from the monochromatic scheme or always staying with white background for the main content column.

php
  1. $highlightFooter = new CSS_Color('973432');
  2. $outer = new CSS_Color('ffffff');
  3. ...

We could also generate a grayscale website using white or black as the base color. I am sure there are endless cool possibilities for this stuff, like different shades for list elements, headings, paragraphs and what not. I am eager to hear your ideas in the post comments below!

So How Does This PHP Thing Work?

When you look at the csscolor.php file, you will quickly notice that it is a very well-made object-oriented PHP script. The foundation of the magic is here:

php
  1. function CSS_Color($bgHex, $fgHex='')
  2.   {
  3.     // This is the constructor method for the class,
  4.     // which is called when a new object is created.
  5.  
  6.     // Initialize this PEAR object so I can
  7.     // use the PEAR error return mechanism
  8.     $this->PEAR();
  9.  
  10.     // Initialize the palette
  11.     $this->setPalette($bgHex, $fgHex);
  12.   }
  13.  
  14.   //==================================================
  15.   //==METHODS=========================================
  16.   //==================================================
  17.  
  18.   //--------------------------------------------------
  19.   function setPalette($bgHex, $fgHex = '')
  20.   {
  21.     // Initialize the color palettes
  22.  
  23.     // If a foreground color was not specified,
  24.     // just use the background color.
  25.     if (!$fgHex) {
  26.       $fgHex = $bgHex;
  27.     }
  28.  
  29.     // Clear the existing palette
  30.     $this->bg = array();
  31.     $this->fg = array();
  32.  
  33.     // Make sure we got a valid hex value
  34.     if (!$this->isHex($bgHex)) {
  35.       $this->raiseError("background color '$bgHex' is not a hex color value",
  36.       __FUNCTION__, __LINE__);
  37.       return false;
  38.     }
  39.  
  40.     // Set the bg color
  41.     $this->bg[0] = $bgHex;
  42.  
  43.     $this->bg['+1'] = $this->lighten($bgHex, .85);
  44.     $this->bg['+2'] = $this->lighten($bgHex, .75);
  45.     $this->bg['+3'] = $this->lighten($bgHex, .5);
  46.     $this->bg['+4'] = $this->lighten($bgHex, .25);
  47.     $this->bg['+5'] = $this->lighten($bgHex, .1);
  48.  
  49.     $this->bg['-1'] = $this->darken($bgHex, .85);
  50.     $this->bg['-2'] = $this->darken($bgHex, .75);
  51.     $this->bg['-3'] = $this->darken($bgHex, .5);
  52.     $this->bg['-4'] = $this->darken($bgHex, .25);
  53.     $this->bg['-5'] = $this->darken($bgHex, .1);
  54. ..

As you see, the bg-property's values are set via the CssColor::lighten() and CssColor::darken() methods. So, what are we waiting for? Let's look at them:

php
  1. function lighten($hex, $percent)
  2.   {
  3.     return $this->mix($hex, $percent, 255);
  4.   }
  5.  
  6.   //--------------------------------------------------
  7.   function darken($hex, $percent)
  8.   {
  9.     return $this->mix($hex, $percent, 0);
  10.   }

Hrm okay, nothing really here, escept that we now know the second parameter is treated as a percentage. This makes me think if it is possible to add more shades to choose from. We will look at that later. Let's look at the mix() method. I will leave out the error handling parts to preserve some space. :)

php
  1. function mix($hex, $percent, $mask)
  2.   {
  3.     // ...
  4.  
  5.     for ($i=0; $i&#lt;3; $i++) {
  6.       $rgb[$i] = round($rgb[$i] * $percent) + round($mask * (1-$percent));
  7.  
  8.       // In case rounding up causes us to go to 256
  9.       if ($rgb[$i] > 255) {
  10.   $rgb[$i] = 255;
  11.       }
  12.  
  13.     }
  14.     return $this->RGB2Hex($rgb);
  15.   }
  16.  
  17.   //--------------------------------------------------
  18.   function hex2RGB($hex)
  19.   {
  20.      // ...
  21.  
  22.     // Regexp for a valid hex digit
  23.     $d = '[a-fA-F0-9]';
  24.    
  25.     // Make sure $hex is valid
  26.     if (preg_match("/^($d$d)($d$d)($d$d)\$/", $hex, $rgb)) {
  27.      
  28.       return array(
  29.        hexdec($rgb[1]),
  30.        hexdec($rgb[2]),
  31.        hexdec($rgb[3])
  32.        );
  33.     }
  34.     if (preg_match("/^($d)($d)($d)$/", $hex, $rgb)) {
  35.      
  36.       return array(
  37.        hexdec($rgb[1] . $rgb[1]),
  38.        hexdec($rgb[2] . $rgb[2]),
  39.        hexdec($rgb[3] . $rgb[3])
  40.        );
  41.     }
  42.  
  43.     $this->raiseError("cannot convert hex '$hex' to RGB", __FUNCTION__, __LINE__);
  44.     return false;
  45.   }
  46.  
  47.   //--------------------------------------------------
  48.   function RGB2Hex($rgb)
  49.   {
  50.     // ...
  51.  
  52.     $hex = "";
  53.     for($i=0; $i < 3; $i++) {
  54.  
  55.       // Convert the decimal digit to hex
  56.       $hexDigit = dechex($rgb[$i]);
  57.  
  58.       // Add a leading zero if necessary
  59.       if(strlen($hexDigit) == 1) {
  60.   $hexDigit = "0" . $hexDigit;
  61.       }
  62.  
  63.       // Append to the hex string
  64.       $hex .= $hexDigit;
  65.     }
  66.  
  67.     // Return the complete hex string
  68.     return $hex;
  69.   }

Okay, here is the magic! We simply calculate an array of rgb values out of the supplied hex color string, alternate its contents via some cool math formula ($rgb[$i] = round($rgb[$i] * $percent) + round($mask * (1-$percent));) and convert it back to hex and return it! This is actually quite simple.

Let us implement more shades. In the CssColor::setPalette() change

php
  1. $this->bg['+1'] = $this->lighten($bgHex, .85);
  2.     $this->bg['+2'] = $this->lighten($bgHex, .75);
  3.     $this->bg['+3'] = $this->lighten($bgHex, .5);
  4.     $this->bg['+4'] = $this->lighten($bgHex, .25);
  5.     $this->bg['+5'] = $this->lighten($bgHex, .1);
  6.  
  7.     $this->bg['-1'] = $this->darken($bgHex, .85);
  8.     $this->bg['-2'] = $this->darken($bgHex, .75);
  9.     $this->bg['-3'] = $this->darken($bgHex, .5);
  10.     $this->bg['-4'] = $this->darken($bgHex, .25);
  11.     $this->bg['-5'] = $this->darken($bgHex, .1);

to

php
  1. $this->bg['+1'] = $this->lighten($bgHex, .95);
  2.     $this->bg['+2'] = $this->lighten($bgHex, .9);
  3.     $this->bg['+3'] = $this->lighten($bgHex, .85);
  4.     $this->bg['+4'] = $this->lighten($bgHex, .8);
  5.     $this->bg['+5'] = $this->lighten($bgHex, .75);
  6.     $this->bg['+6'] = $this->lighten($bgHex, .7);
  7.     $this->bg['+7'] = $this->lighten($bgHex, .65);
  8.     $this->bg['+8'] = $this->lighten($bgHex, .6);
  9.     $this->bg['+9'] = $this->lighten($bgHex, .55);
  10.     $this->bg['+10'] = $this->lighten($bgHex, .5);
  11.     $this->bg['+11'] = $this->lighten($bgHex, .45);
  12.     $this->bg['+12'] = $this->lighten($bgHex, .4);
  13.     $this->bg['+13'] = $this->lighten($bgHex, .35);
  14.     $this->bg['+14'] = $this->lighten($bgHex, .3);
  15.     $this->bg['+15'] = $this->lighten($bgHex, .25);
  16.     $this->bg['+16'] = $this->lighten($bgHex, .2);
  17.     $this->bg['+17'] = $this->lighten($bgHex, .15);    
  18.     $this->bg['+18'] = $this->lighten($bgHex, .1);
  19.     $this->bg['+19'] = $this->lighten($bgHex, .05);  
  20.    
  21.     $this->bg['-1'] = $this->darken($bgHex, .95);
  22.     $this->bg['-2'] = $this->darken($bgHex, .9);
  23.     $this->bg['-3'] = $this->darken($bgHex, .85);
  24.     $this->bg['-4'] = $this->darken($bgHex, .8);
  25.     $this->bg['-5'] = $this->darken($bgHex, .75);
  26.     $this->bg['-6'] = $this->darken($bgHex, .7);
  27.     $this->bg['-7'] = $this->darken($bgHex, .65);
  28.     $this->bg['-8'] = $this->darken($bgHex, .6);
  29.     $this->bg['-9'] = $this->darken($bgHex, .55);
  30.     $this->bg['-10'] = $this->darken($bgHex, .5);
  31.     $this->bg['-11'] = $this->darken($bgHex, .45);
  32.     $this->bg['-12'] = $this->darken($bgHex, .40);
  33.     $this->bg['-13'] = $this->darken($bgHex, .35);
  34.     $this->bg['-14'] = $this->darken($bgHex, .3);
  35.     $this->bg['-15'] = $this->darken($bgHex, .25);
  36.     $this->bg['-16'] = $this->darken($bgHex, .2);
  37.     $this->bg['-17'] = $this->darken($bgHex, .15);
  38.     $this->bg['-18'] = $this->darken($bgHex, .1);
  39.     $this->bg['-19'] = $this->darken($bgHex, .05);

This gives us a whole range of new shades! Here are some stylesheets I could come up with using them:

Picture of fifth generated layout

Picture of forth generated layout

Picture of seventh generated layout

Much credit goes to Patrick Fitzgerald for this very nice script!

Thanks for reading! Have a good one, all!