Raising the Bar with Adaptive Templates

Posted: April 28, 2008 Comments(3)

I recently completed work on a complete design and development overhaul. To generalize, the project involved a redesign of an online storefront catering to a specific professional. The company I work for was hired to redesign the storefront template as well as overhaul the front end. All the back end development would be taken on in house by the client and we’d team up to really improve the overall state of things.

I was excited about this project from the start, as was my team. We immediately started throwing ideas back and forth on what we could do to improve the customer experience for this particular storefront. A number of ideas were laid out on the table, some shelved for later phases of the project, and others tightly integrated into the overall design. I’d like to explain a bit about one feature in particular that ended up garnering quite a bit of the spotlight when the redesign was pushed live.

Color adaptation

I’d like to say that straight from the beginning the seed for this idea had been planted long ago with the publication of an article to A List Apart titled Super-Easy Blendy Backgrounds. Beginning with that article, my eyes had been opened to a new way of thinking when it came to Web design. While there were significant issues with PNGs in IE6, it was obvious to me that alpha transparency will indeed change things on the Web. That article, tied with a great piece written by Jeff Croft, Creative Use of PNG Transparency in Web Design, really got me hooked to the idea of using these unique advantages in upcoming projects.

The advantages of alpha transparency in the PNG image format are great in and of themselves, but for this project I thought we could take things one step further with CSS constants. I recalled reading a number of pieces on this specific subject and taking a liking to the idea. Quite a few designers feel that constants should be a built in feature of CSS, and I agree; it would be useful.

I had never implemented any CSS constant simulations prior to this project, but took comfort in the example with extensive documentation by Christian Heilmann. His sample was exactly what I was looking for.

I thought it would be completely awesome to tie these two features together; a color-changing template which uses a single color to ‘power’ the various shades and hues by taking advantage of alpha transparency by way of PNG.

When it came to the project I’d be working on, my company was merely in the discussion and planning phase with the client, I wasn’t 100% sure I’d be able to implement a feature such as this. I thought a bit about it and we decided it best to simply offer our proposal without specific mention of this feature. After successful test implementations, we’d mention to the client that we will be providing this additional functionality should there be interest.

I teamed with a single designer through the life of this project and he made the conscious effort to use only white and black in the design, but in transparent levels more often than not. He was able to use a solid color bottom-most layer in Photoshop to mimic how things would work in a Web browser. Our tests were quite successful and the idea was presented to the client. They fell in love with it and we began work. As you can imagine, cross-browser support was at times an issue, but I’ve got to say that overall the feature implementation was a very successful. Our client was able to offer an extremely versatile design to their clients, allowing them to customize the colors used throughout the redesign.

Extreme darks or lights

It became apparent almost immediately that we would need three separate variations of the same theme to account for variable choices on the part of our client’s clients. If a solid black background color were chosen, we’d need to make sure that all the design elements are equally visible throughout the design. The same applies for a solid white background color. At the end of the day, I ended up cutting three ‘sets’ of images: one for very dark background colors, one for very light background colors, and a third for mid-range colors.

The inclusion of this hurdle alone required some modifications to Christian Heilmann’s CSS constant simulation example; I had to account for the three ranges of color. The W3C published an algorithm to measure color visibility which I included in the CSS parser originally written by Christian Heilmann. I compared the color chosen as the background color to both black and white and measured the difference between. With some arbitrary testing, I included a tolerance variable which the client could adjust down the line if they’d like. The result came to be:

<?php
/*
	cssconst.php
	written by Chris Heilmann (http://icant.co.uk)
	allows constants to be used in the css
	file sent in the get variable c
	constant format:
	$foo='bar';

	Modification by Jonathan Christopher () to
	include a function to measure the color contrast of a variable set
	in the CSS. That value then sets another variable for use with image
	filenames.
*/

$background 	= '#8094b2';
$mainText 	= '#fff';
$altText 	= '#000';
$tolerance 	= 100;

$white = (hexrgb('ffffff'));
$black = (hexrgb('000000'));

function hexrgb($hexstr) {
    $int = hexdec($hexstr);
    return array("red" => 0xFF & ($int >> 0x10), "green" => 0xFF & ($int >> 0x8), "blue" => 0xFF & $int);
}

header('content-type:text/css');
//header("Expires: ".gmdate("D, d M Y H:i:s", (time()+900)) . " GMT");
$c=$_GET['c'];
$css=load($c);
if($css=='') { die('File not Found, sorry!'); }
preg_match_all("/\\$(\w+).*=.*\'(.*)\'/",$css,$constants);


// ---------------------------------
// determine color difference
// ---------------------------------

$targetHex = $background;

if(strlen($targetHex)==4) {
	$hexArray = str_split($targetHex);
	$targetHex  = $hexArray[1];
	$targetHex .= $hexArray[1];
	$targetHex .= $hexArray[2];
	$targetHex .= $hexArray[2];
	$targetHex .= $hexArray[3];
	$targetHex .= $hexArray[3];
} elseif(strlen($targetHex)!=7) {
	$targetHex = '#8094b2';						// worse case: use default
}

$color = (hexrgb($targetHex));

// Determine how different the color is from white
$whiteDiff  = max($color["red"],$white["red"])-min($color["red"],$white["red"]);
$whiteDiff += max($color["green"],$white["green"])-min($color["green"],$white["green"]);
$whiteDiff += max($color["blue"],$white["blue"])-min($color["blue"],$white["blue"]);

// Determine how different the color is from black
$blackDiff  = max($color["red"],$black["red"])-min($color["red"],$black["red"]);
$blackDiff += max($color["green"],$black["green"])-min($color["green"],$black["green"]);
$blackDiff += max($color["blue"],$black["blue"])-min($color["blue"],$black["blue"]);

if(!isset($image_suffix)){
if($whiteDiff<$tolerance) {
	$image_suffix 	= '-light';
} elseif($blackDiff<$tolerance) {
	$image_suffix 	= '-dark';
	} else {
	$image_suffix 	= '';
}}


// ---------------------------------
// apply background
// ---------------------------------
$css=preg_replace('/\\$background/',$background,$css);


// ---------------------------------
// apply suffix
// ---------------------------------
$css=preg_replace('/\\$image_suffix/',$image_suffix,$css);


// ---------------------------------
// apply mainText
// ---------------------------------
$css=preg_replace('/\\$mainText/',$mainText,$css);


// ---------------------------------
// apply altText
// ---------------------------------
$css=preg_replace('/\\$altText/',$altText,$css);


// ---------------------------------
// finish it up and echo
// ---------------------------------
$css=preg_replace("/\\#.*=.*?;\s+/s",'',$css);
echo $css;

/*
	Function load($file)
	reads the content of the file that you send and returns it
*/
function load($filelocation)
{
	if (file_exists($filelocation))
	{
		$newfile = fopen($filelocation,"r");
		$file_content = fread($newfile, filesize($filelocation));
		fclose($newfile);
		return $file_content;
	}
}
?>

If you’ll note, there are four variables to consider when using the above script. These variables were stored in a database and saved as a session variable server side. The $background variable controlled the overall color scheme used in the design by using it as the background color for the body as well as a few other strategic places where it was needed. $mainText was the primary text color used in the design, $altText was used in those certain circumstances where another color spiced things up a bit, and the $tolerance variable controlled how close a color had to be to either white or black before it was decided which background images were to be used to ensure proper contrast.

To implement the variables in the CSS, you simply add them as PHP variables:

body { background-color:$background; color:$mainText; }

The way I was able to distinguish which ‘set’ of images to use was partially twofold. My first step was to name each image accordingly. Much of the time, the same image itself could be, but there were other times were a black gradient on an image needed to me changed to a white gradient when a very dark background color was chosen. To get around the issue, I added a suffix to the filename of applicable images. For example, bg-body.png would have two additional images; bg-body-light.png and bg-body-dark.png. I was able to take advantage of this naming structure in both the CSS as well as the parser by referencing the images as something like:

div#example { background:$background url(../images/bg-body$image_suffix.png) no-repeat; }

All of my bases were covered. If the background was too dark, one suffix would be added in the parser, another suffix added if the color were too light, and the suffix would simply be empty if the color was middle of the line.

I hope it's useful to someone else

The inclusion of this feature turned out to be extremely useful in this case, and I hope others are able to take advantage of the idea. I'm sure there are endless ways to improve this specific implementation, so certainly feel free to offer both your thoughts and critiques.

Get my newsletter

Receive periodic updates right in the mail!
  • This field is for validation purposes and should be left unchanged.

Comments

  1. @Michael: I’m glad you may find it useful at some point! Unfortunately I’m not able to publicly post a link to the project, but I will spend some time this evening (or tomorrow evening) putting together a stripped-down example which you may find useful. Stay tuned!

Leave a Reply

Your email address will not be published. Required fields are marked *