<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.0.3" -->
<rss version="2.0" 
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>Corunet. El blog</title>
	<link>http://blog.corunet.com</link>
	<description>Diseño web</description>
	<pubDate>Thu, 21 Jun 2007 19:06:13 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.0.3</generator>
	<language>en</language>
			<item>
		<title>Automatic CSS: The stylizator</title>
		<link>http://blog.corunet.com/english/automatic-css-the-stylizator</link>
		<comments>http://blog.corunet.com/english/automatic-css-the-stylizator#comments</comments>
		<pubDate>Wed, 20 Jun 2007 20:15:15 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
	<category>English</category>
	<category>CSS and Javascript</category>
		<guid isPermaLink="false">http://blog.corunet.com/english/automatic-css-the-stylizator</guid>
		<description><![CDATA[Writing CSS is good fun, but analyzing an html document to find how the page is structured us, at the very least, tiring. If you have ever had to write CSS for a blog or CMS template, you already know how time-consuming is to find every ID and CLASS in a large document. We&#8217;re going [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/uploads/stylizator/stylizator_p.png" align="left" title="The stylizator" width="150" height="100" border="0" hspace="3" vspace="3">Writing CSS is good fun, but analyzing an html document to find how the page is structured us, at the very least, tiring. If you have ever had to write CSS for a blog or CMS template, you already know how time-consuming is to find every ID and CLASS in a large document. We&#8217;re going to write a simple script that takes an HTML file as input and gives us two things: </p>
<ul>
<li>First, some CSS and Javascript to generate a visual structure with all the names like the one that can be seen at the top image </em>(and a javascript only version!!)</em>.</li>
<li> Second, a CSS file without any rules, but with every ID and class in the document.</li>
</ul>
<p> Let&#8217;s go:<br />
<a id="more-14"></a></p>
<h2>The tools</h2>
<p>We need to use any scripting language to read the HTML and act accordingly. This time we&#8217;re going to use perl, since it&#8217;s a simple and powerful language for text managing. It&#8217;s available in most operating systems and for windows users, it&#8217;s downloadable from <a href="http://activestate.com/">http://activestate.com/ </a>. </p>
<p>It should be possible to write in ruby, python, java or any other programming language. Take it as a guideline or, if you just want to use it, <a href="/uploads/stylizator/stylizator.zip">grab the code</a><br />
We&#8217;re going to use some CSS and Javascript too. Let&#8217;s get wet&#8230;</p>
<h2>Reading and parsing HTML</h2>
<p>First of all, we need an HTML document to be parsed. As I&#8217;ll recall later, I used HTML code from <a href="http://csszengarden.com">csszengarden</a> to try the code.<br />
First thing to do is read the html from a file. The script we&#8217;re going starts the following way:</p>
<div class="foldingcode"><a href="javascript:showme('3925_1');"> Code: <b>stylizator.1.pl</b></a><br />
<div style="display: none; background:white;" id=3925_1>
<pre class="perl"><span style="color: #808080; font-style: italic;">#!/usr/bin/perl</span>
<span style="color: #000000; font-weight: bold;">use</span> strict;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$file</span>=<a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span style="color: #000066;">shift</span></a>;
<a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span style="color: #000066;">die</span></a> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"HTML file missing"</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">unless</span> <span style="color: #0000ff;">$file</span>=~/\.html?$/;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$filename</span>=<span style="color: #0000ff;">$file</span>;
<span style="color: #0000ff;">$filename</span>=~<a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>/\.html?$//;
<a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> <span style="color: #ff0000;">"$filename<span style="color: #000099; font-weight: bold;">\n</span>"</span>;
<a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span style="color: #000066;">open</span></a> <span style="color: #66cc66;">&#40;</span>HTML,<span style="color: #0000ff;">$file</span><span style="color: #66cc66;">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span style="color: #000066;">die</span></a> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"HTML file can't be opened"</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@html</span>=<span style="color: #009999;">&lt;HTML&gt;</span>;
<a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span style="color: #000066;">close</span></a> <span style="color: #66cc66;">&#40;</span>HTML<span style="color: #66cc66;">&#41;</span>;
<a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span style="color: #000066;">open</span></a><span style="color: #66cc66;">&#40;</span>CSS,<span style="color: #ff0000;">"&gt;$filename.css"</span><span style="color: #66cc66;">&#41;</span>;
<a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span style="color: #000066;">open</span></a><span style="color: #66cc66;">&#40;</span>HTML, <span style="color: #ff0000;">"&gt;$filename.structure.html"</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$html</span>=<a href="http://www.perldoc.com/perl5.6/pod/func/join.html"><span style="color: #000066;">join</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">''</span>,<span style="color: #0000ff;">@html</span><span style="color: #66cc66;">&#41;</span>;</pre>
</div>
</div>
<p>This first part opens a file, reads it and assign the contents to a variable. Now, we need to find all the id&#8217;s present in the file. To do that we could use a full-fledged HTML parser, but since many documents in the real world are not correct and our necessities are quite easy, there&#8217;s a simpler solution. So, regular expressions to the rescue.<br />
Regular expressions find patterns in a file. We can tell perl to find things like /\w+/ and it will match alphanumeric characters. Probably to find named elements it should be enough to write:</p>
<p><code><br />
/id=\"?\w+\"?/i</p>
<p></code></p>
<p>Where &#8220;id=&#8221; means exactly that, \&#8221;? means a possible quotation mark, (\w+) is a group of letters or numbers, another possible quote and the last &#8220;i&#8221; tells us to ignore the case of the text. In this particular case, we&#8217;re going to use a slightly more complicated expression, to take into acount possible missing quotes and so on:</p>
<p><code><br />
/id\s*=\s*"?([^"\s>]+)/<br />
</code></p>
<h2>Creating the CSS template</h2>
<p>We&#8217;re going to write an empty CSS file. I like to use a previously written template that includes links to my CSS-reset file and some more files I always use. Then, for every named element, we need a line:</p>
<p><code><br />
#namedelement{</p>
<p>}</p>
<p></code></p>
<div class="foldingcode"><a href="javascript:showme('3925_2');"> Code: <b>stylizator.2.pl</b></a><br />
<div style="display: none; background:white;" id=3925_2>
<pre class="perl"><a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> CSS <span style="color: #ff0000;">"<span style="color: #000099; font-weight: bold;">\@</span>import url(zero.css);<span style="color: #000099; font-weight: bold;">\n</span>body{<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>}<span style="color: #000099; font-weight: bold;">\n</span>"</span>;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@id</span> = <span style="color: #0000ff;">$html</span> =~ /id\<a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>*=\<a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>*<span style="color: #ff0000;">"?([^"</span>\s&gt;<span style="color: #66cc66;">&#93;</span>+<span style="color: #66cc66;">&#41;</span>/gis;
<span style="color: #b1b100;">foreach</span> <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$id</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">@id</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	<a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> <span style="color: #ff0000;">"id -&gt; $id<span style="color: #000099; font-weight: bold;">\n</span>"</span>;
	<a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> CSS <span style="color: #ff0000;">"#"</span>.<span style="color: #0000ff;">$id</span>.<span style="color: #ff0000;">"{<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\t</span><span style="color: #000099; font-weight: bold;">\n</span>}<span style="color: #000099; font-weight: bold;">\n</span>"</span>;
<span style="color: #66cc66;">&#125;</span></pre>
</div>
</div>
<p>and every time we find a class, since they are not unique, we need to filter it, creating a hash (associative array) with its name. And then, the same thing we&#8217;ve done with the IDs. Some more code:</p>
<div class="foldingcode"><a href="javascript:showme('3925_3');"> Code: <b>stylizator.3.pl</b></a><br />
<div style="display: none; background:white;" id=3925_3>
<pre class="perl"><span style="color: #b1b100;">my</span> <span style="color: #0000ff;">%class</span>;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@classes</span> = <span style="color: #0000ff;">$html</span> =~ /class\<a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>*=\<a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>*<span style="color: #ff0000;">"?([^"</span>\s&gt;<span style="color: #66cc66;">&#93;</span>+<span style="color: #66cc66;">&#41;</span>/gis;
<span style="color: #b1b100;">foreach</span> <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$class</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">@classes</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	<span style="color: #0000ff;">$class</span><span style="color: #66cc66;">&#123;</span><span style="color: #0000ff;">$class</span><span style="color: #66cc66;">&#125;</span>=<span style="color: #ff0000;">"class"</span>;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #b1b100;">while</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">my</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$key</span>, <span style="color: #0000ff;">$value</span><span style="color: #66cc66;">&#41;</span>=<a href="http://www.perldoc.com/perl5.6/pod/func/each.html"><span style="color: #000066;">each</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">%class</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	<a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> <span style="color: #ff0000;">"$value -&gt; $key<span style="color: #000099; font-weight: bold;">\n</span>"</span>;
	<a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> CSS <span style="color: #ff0000;">".$key"</span>.<span style="color: #ff0000;">"{<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>}<span style="color: #000099; font-weight: bold;">\n</span>"</span>
<span style="color: #66cc66;">&#125;</span></pre>
</div>
</div>
<p>With all that code, we already have a CSS template. You could start right now editing it to suit your needs. But we don&#8217;t know yet what the structure is. Why don&#8217;t we create a new HTML file that shows us how the document is laid? OK. Let&#8217;s write some more code</p>
<h2>Javascript: The magic</h2>
<p>Here is where the fun begins. Probably, I&#8217;ll need to wite another post about this piece of code, since there are a couple of sleights of hand, but, briefly, the following piece of code removes all the stylesheets and the inline CSS rules, then  takes all the elements in the dom and finds the ones that have an ID, and adds a P element with the ID name to each one. </p>
<div class="foldingcode"><a href="javascript:showme('3925_4');"> Code: <b>stylizator.js</b></a><br />
<div style="display: none; background:white;" id=3925_4>
<pre class="javascript"><span style="color: #003366; font-weight: bold;">function</span> removeSheets<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>document.<span style="color: #006600;">styleSheets</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> c = document.<span style="color: #006600;">styleSheets</span>.<span style="color: #006600;">length</span>;
    <span style="color: #000066; font-weight: bold;">for</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i=<span style="color: #CC0000;">0</span>;i&lt;c;i++<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		document.<span style="color: #006600;">styleSheets</span><span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">disabled</span>=<span style="color: #003366; font-weight: bold;">true</span>;
    <span style="color: #66cc66;">&#125;</span>
  <span style="color: #66cc66;">&#125;</span>
  findNamedElements<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #003366; font-weight: bold;">function</span> findNamedElements<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	allElements = document.<span style="color: #006600;">getElementsByTagName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'*'</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #000066; font-weight: bold;">for</span><span style="color: #66cc66;">&#40;</span>i=<span style="color: #CC0000;">0</span>;i&lt;allElements.<span style="color: #006600;">length</span>;i++<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		allElements<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">cssText</span> = <span style="color: #3366CC;">''</span>;
		<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>allElements<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">id</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
			allElements<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">position</span> = <span style="color: #3366CC;">'relative'</span>;
			allElements<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">border</span> = <span style="color: #3366CC;">'1px solid silver'</span>;
			allElements<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">padding</span> = <span style="color: #3366CC;">'20px'</span>;
			allElements<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">margin</span> = <span style="color: #3366CC;">'10px'</span>;
			p=document.<span style="color: #006600;">createElement</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'p'</span><span style="color: #66cc66;">&#41;</span>;
			sometext = document.<span style="color: #006600;">createTextNode</span><span style="color: #66cc66;">&#40;</span>allElements<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">id</span><span style="color: #66cc66;">&#41;</span>;
			p.<span style="color: #006600;">appendChild</span><span style="color: #66cc66;">&#40;</span>sometext<span style="color: #66cc66;">&#41;</span>;
			p.<span style="color: #006600;">className</span> = <span style="color: #3366CC;">'sign'</span>;
			allElements<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">appendChild</span><span style="color: #66cc66;">&#40;</span>p<span style="color: #66cc66;">&#41;</span>;
		<span style="color: #66cc66;">&#125;</span>
	<span style="color: #66cc66;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>window.<span style="color: #006600;">innerWidth</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		<span style="color: #003366; font-weight: bold;">var</span> styleText = <span style="color: #3366CC;">'.sign{border:1px dashed red;position:absolute;top:0;left:0;padding:2px;background-color:#fff}'</span>;
		<span style="color: #003366; font-weight: bold;">var</span> head=document.<span style="color: #006600;">getElementsByTagName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">"head"</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#93;</span>;
		<span style="color: #003366; font-weight: bold;">var</span> styleNode = document.<span style="color: #006600;">createElement</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">"style"</span><span style="color: #66cc66;">&#41;</span>;
		styleNode.<span style="color: #006600;">appendChild</span><span style="color: #66cc66;">&#40;</span>document.<span style="color: #006600;">createTextNode</span><span style="color: #66cc66;">&#40;</span>styleText<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
		head.<span style="color: #006600;">appendChild</span><span style="color: #66cc66;">&#40;</span>styleNode<span style="color: #66cc66;">&#41;</span>;
	<span style="color: #66cc66;">&#125;</span><span style="color: #000066; font-weight: bold;">else</span><span style="color: #66cc66;">&#123;</span>
		<span style="color: #003366; font-weight: bold;">var</span> newStyle = document.<span style="color: #006600;">createStyleSheet</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
		newStyle.<span style="color: #006600;">addRule</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'.sign'</span>,<span style="color: #3366CC;">'border:1px dashed red;position:absolute;top:0;left:0;padding:2px;background-color:#fff'</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
removeSheets<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;</pre>
</div>
</div>
<p>As you can see, there are only two functions. The first one, removeSheets(), disables every stylesheet included from the HTML, and then calls the other one, findNamedElements(), This function gets all the elements in the DOM (getElementsByTagName(&#8217;*')) and iterates over them, doing a couple of things:</p>
<ul>
<li>First, remove inline style elements (allElements[i].style.cssText = &#8216;&#8217;)</li>
<li>For the elements with an ID, some styles are added (a silver box around them)</li>
<li>A child P tag with the ID text is created too, giving it a class &#8217;sign&#8217;</li>
</ul>
<p>Then, we create a new stylesheet only for that class. We have to code a different way for Explorer and Firefox/Opera/Others because of compatibility issues.<br />
Last, the function is called with removesheets(). You can even save the code as a bookmarklet and apply it to any website. It&#8217;s truly portable.</p>
<p>Now we need some perl code to insert the javascript into the HTML file, just before the &lt;/body&gt;: tag.<br />
<strong>Update:</strong> My pal Félix has just tol me that I need to add an &#8220;s&#8221; in the javascript substitution, to cope with multi-line javascript. Thanks, Félix</p>
<div class="foldingcode"><a href="javascript:showme('3925_5');"> Code: <b>stylizator.4.pl</b></a><br />
<div style="display: none; background:white;" id=3925_5>
<pre class="perl"><span style="color: #0000ff;">$html</span>=~<a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>/&lt;script.*?&lt;\/script&gt;//sg;
<a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span style="color: #000066;">open</span></a> <span style="color: #66cc66;">&#40;</span>JS,<span style="color: #ff0000;">"stylizator.js"</span><span style="color: #66cc66;">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span style="color: #000066;">die</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"You also need the file stylizator.js in the same folder"</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@js</span>=<span style="color: #009999;">&lt;JS&gt;</span>;
<a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span style="color: #000066;">close</span></a> <span style="color: #66cc66;">&#40;</span>JS<span style="color: #66cc66;">&#41;</span>;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$js</span>=<span style="color: #ff0000;">'&lt;script type=&quot;text/javascript&quot;&gt;'</span>.<a href="http://www.perldoc.com/perl5.6/pod/func/join.html"><span style="color: #000066;">join</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">""</span>,<span style="color: #0000ff;">@js</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #ff0000;">'&lt;/script&gt;&lt;/body&gt;'</span>;
<span style="color: #0000ff;">$html</span>=~<a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>/&lt;\/body&gt;/<span style="color: #0000ff;">$js</span>/e;
<a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> HTML <span style="color: #0000ff;">$html</span>;
<a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span style="color: #000066;">close</span></a> <span style="color: #66cc66;">&#40;</span>CSS<span style="color: #66cc66;">&#41;</span>;
<a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span style="color: #000066;">close</span></a> <span style="color: #66cc66;">&#40;</span>HTML<span style="color: #66cc66;">&#41;</span>;</pre>
</div>
</div>
<p>When you run the full script, another HTML file will be generated, that shows how the document is laid.</p>
<h2>Trying it out </h2>
<p>The best example I can think of is <a href="http://csszengarden.com/">CSSzengarden,</a> a site where a default layout is given to designers to skin it the better they can. I downloaded the HTML code (<acronym title="Creative commons, Attribution-NonCommercial-ShareAlike">CC license, by-nc-sa</acronym>) and called he script over it:</p>
<p><code><br />
$&gt; perl stylizator.pl csszengarden.html</p>
<p></code></p>
<p>And I got a csszengarden CSS file, with all the named tags, and a csszengarden.structure.html file with the visual structure of the site.</p>
<div class="foldingcode"><a href="javascript:showme('3925_6');"> Code: <b>csszengarden.html</b></a><br />
<div style="display: none; background:white;" id=3925_6>
<pre>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;
	&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; &gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=iso-8859-1&quot; /&gt;
	&lt;meta name=&quot;author&quot; content=&quot;Dave Shea&quot; /&gt;
	&lt;meta name=&quot;keywords&quot; content=&quot;design, css, cascading, style, sheets, xhtml, graphic design, w3c, web standards, visual, display&quot; /&gt;
	&lt;meta name=&quot;description&quot; content=&quot;A demonstration of what can be accomplished visually through CSS-based design.&quot; /&gt;
	&lt;meta name=&quot;robots&quot; content=&quot;all&quot; /&gt;
	&lt;title&gt;css Zen Garden: The Beauty in CSS Design&lt;/title&gt;
&nbsp;
	&lt;!-- to correct the unsightly Flash of Unstyled Content. http://www.bluerobot.com/web/css/fouc.asp --&gt;
	&lt;script type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&nbsp;
	&lt;style type=&quot;text/css&quot; title=&quot;currentStyle&quot; media=&quot;screen&quot;&gt;
		@import &quot;/001/001.css&quot;;
	&lt;/style&gt;
	&lt;link rel=&quot;Shortcut Icon&quot; type=&quot;image/x-icon&quot; href=&quot;http://www.csszengarden.com/favicon.ico&quot; /&gt;
	&lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS&quot; href=&quot;http://www.csszengarden.com/zengarden.xml&quot; /&gt;
&lt;/head&gt;
&nbsp;
&lt;!--
&nbsp;
&nbsp;
	This xhtml document is marked up to provide the designer with the maximum possible flexibility.
	There are more classes and extraneous tags than needed, and in a real world situation, it's more
	likely that it would be much leaner.
&nbsp;
	However, I think we can all agree that even given that, we're still better off than if this had been
	built with tables.
&nbsp;
&nbsp;
--&gt;
&nbsp;
&lt;body id=&quot;css-zen-garden&quot;&gt;
&lt;div id=&quot;container&quot;&gt;
	&lt;div id=&quot;intro&quot;&gt;
		&lt;div id=&quot;pageHeader&quot;&gt;
			&lt;h1&gt;&lt;span&gt;css Zen Garden&lt;/span&gt;&lt;/h1&gt;
			&lt;h2&gt;&lt;span&gt;The Beauty of &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; Design&lt;/span&gt;&lt;/h2&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;quickSummary&quot;&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;A demonstration of what can be accomplished visually through &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;-based design. Select any style sheet from the list to load it into this page.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;Download the sample &lt;a href=&quot;/zengarden-sample.html&quot; title=&quot;This page's source HTML code, not to be modified.&quot;&gt;html file&lt;/a&gt; and &lt;a href=&quot;/zengarden-sample.css&quot; title=&quot;This page's sample CSS, the file you may modify.&quot;&gt;css file&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;preamble&quot;&gt;
			&lt;h3&gt;&lt;span&gt;The Road to Enlightenment&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;Littering a dark and dreary road lay the past relics of browser-specific tags, incompatible &lt;acronym title=&quot;Document Object Model&quot;&gt;DOM&lt;/acronym&gt;s, and broken &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; support.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;Today, we must clear the mind of past practices. Web enlightenment has been achieved thanks to the tireless efforts of folk like the &lt;acronym title=&quot;World Wide Web Consortium&quot;&gt;W3C&lt;/acronym&gt;, &lt;acronym title=&quot;Web Standards Project&quot;&gt;WaSP&lt;/acronym&gt; and the major browser creators.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p3&quot;&gt;&lt;span&gt;The css Zen Garden invites you to relax and meditate on the important lessons of the masters. Begin to see with clarity. Learn to use the (yet to be) time-honored techniques in new and invigorating fashion. Become one with the web.&lt;/span&gt;&lt;/p&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&nbsp;
	&lt;div id=&quot;supportingText&quot;&gt;
		&lt;div id=&quot;explanation&quot;&gt;
			&lt;h3&gt;&lt;span&gt;So What is This About?&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;There is clearly a need for &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; to be taken seriously by graphic artists. The Zen Garden aims to excite, inspire, and encourage participation. To begin, view some of the existing designs in the list. Clicking on any one will load the style sheet into this very page. The code remains the same, the only thing that has changed is the external .css file. Yes, really.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;&lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; allows complete and total control over the style of a hypertext document. The only way this can be illustrated in a way that gets people excited is by demonstrating what it can truly be, once the reins are placed in the hands of those able to create beauty from structure. To date, most examples of neat tricks and hacks have been demonstrated by structurists and coders. Designers have yet to make their mark. This needs to change.&lt;/span&gt;&lt;/p&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;participation&quot;&gt;
			&lt;h3&gt;&lt;span&gt;Participation&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;Graphic artists only please. You are modifying this page, so strong &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; skills are necessary, but the example files are commented well enough that even &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; novices can use them as starting points. Please see the &lt;a href=&quot;http://www.mezzoblue.com/zengarden/resources/&quot; title=&quot;A listing of CSS-related resources&quot;&gt;&lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; Resource Guide&lt;/a&gt; for advanced tutorials and tips on working with &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;You may modify the style sheet in any way you wish, but not the &lt;acronym title=&quot;HyperText Markup Language&quot;&gt;HTML&lt;/acronym&gt;. This may seem daunting at first if you&amp;#8217;ve never worked this way before, but follow the listed links to learn more, and use the sample files as a guide.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p3&quot;&gt;&lt;span&gt;Download the sample &lt;a href=&quot;/zengarden-sample.html&quot; title=&quot;This page's source HTML code, not to be modified.&quot;&gt;html file&lt;/a&gt; and &lt;a href=&quot;/zengarden-sample.css&quot; title=&quot;This page's sample CSS, the file you may modify.&quot;&gt;css file&lt;/a&gt; to work on a copy locally. Once you have completed your masterpiece (and please, don&amp;#8217;t submit half-finished work) upload your .css file to a web server under your control. &lt;a href=&quot;http://www.mezzoblue.com/zengarden/submit/&quot; title=&quot;Use the contact form to send us your CSS file&quot;&gt;Send us a link&lt;/a&gt; to the file and if we choose to use it, we will spider the associated images. Final submissions will be placed on our server.&lt;/span&gt;&lt;/p&gt;
					&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;benefits&quot;&gt;
			&lt;h3&gt;&lt;span&gt;Benefits&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;Why participate? For recognition, inspiration, and a resource we can all refer to when making the case for &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;-based design. This is sorely needed, even today. More and more major sites are taking the leap, but not enough have. One day this gallery will be a historical curiosity; that day is not today.&lt;/span&gt;&lt;/p&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;requirements&quot;&gt;
			&lt;h3&gt;&lt;span&gt;Requirements&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;We would like to see as much &lt;acronym title=&quot;Cascading Style Sheets, version 1&quot;&gt;CSS1&lt;/acronym&gt; as possible. &lt;acronym title=&quot;Cascading Style Sheets, version 2&quot;&gt;CSS2&lt;/acronym&gt; should be limited to widely-supported elements only. The css Zen Garden is about functional, practical &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; and not the latest bleeding-edge tricks viewable by 2% of the browsing public. The only real requirement we have is that your &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; validates.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;Unfortunately, designing this way highlights the flaws in the various implementations of &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;. Different browsers display differently, even completely valid &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; at times, and this becomes maddening when a fix for one leads to breakage in another. View the &lt;a href=&quot;http://www.mezzoblue.com/zengarden/resources/&quot; title=&quot;A listing of CSS-related resources&quot;&gt;Resources&lt;/a&gt; page for information on some of the fixes available. Full browser compliance is still sometimes a pipe dream, and we do not expect you to come up with pixel-perfect code across every platform. But do test in as many as you can. If your design doesn&amp;#8217;t work in at least IE5+/Win and Mozilla (run by over 90% of the population), chances are we won&amp;#8217;t accept it.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p3&quot;&gt;&lt;span&gt;We ask that you submit original artwork. Please respect copyright laws. Please keep objectionable material to a minimum; tasteful nudity is acceptable, outright pornography will be rejected.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p4&quot;&gt;&lt;span&gt;This is a learning exercise as well as a demonstration. You retain full copyright on your graphics (with limited exceptions, see &lt;a href=&quot;http://www.mezzoblue.com/zengarden/submit/guidelines/&quot;&gt;submission guidelines&lt;/a&gt;), but we ask you release your &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; under a Creative Commons license identical to the &lt;a href=&quot;http://creativecommons.org/licenses/by-nc-sa/1.0/&quot; title=&quot;View the Zen Garden's license information.&quot;&gt;one on this site&lt;/a&gt; so that others may learn from your work.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p5&quot;&gt;&lt;span&gt;Bandwidth graciously donated by &lt;a href=&quot;http://www.dreamfirestudios.com/&quot;&gt;DreamFire Studios&lt;/a&gt;. Now available: &lt;a href=&quot;http://www.amazon.com/exec/obidos/ASIN/0321303474/mezzoblue-20/&quot;&gt;Zen Garden, the book&lt;/a&gt;.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;footer&quot;&gt;
			&lt;a href=&quot;http://validator.w3.org/check/referer&quot; title=&quot;Check the validity of this site&amp;#8217;s XHTML&quot;&gt;xhtml&lt;/a&gt; &amp;nbsp;
			&lt;a href=&quot;http://jigsaw.w3.org/css-validator/check/referer&quot; title=&quot;Check the validity of this site&amp;#8217;s CSS&quot;&gt;css&lt;/a&gt; &amp;nbsp;
			&lt;a href=&quot;http://creativecommons.org/licenses/by-nc-sa/1.0/&quot; title=&quot;View details of the license of this site, courtesy of Creative Commons.&quot;&gt;cc&lt;/a&gt; &amp;nbsp;
			&lt;a href=&quot;http://www.contentquality.com/mynewtester/cynthia.exe?Url1=http:%2F%2Fcsszengarden.com%2F&quot; title=&quot;Check the accessibility of this site according to U.S. Section 508&quot;&gt;508&lt;/a&gt; &amp;nbsp;
			&lt;a href=&quot;http://mezzoblue.com/zengarden/faq/#aaa&quot; title=&quot;Check the accessibility of this site according to Web Content Accessibility Guidelines 1.0&quot;&gt;aaa&lt;/a&gt;
		&lt;/div&gt;
&nbsp;
	&lt;/div&gt;
&nbsp;
&nbsp;
	&lt;div id=&quot;linkList&quot;&gt;
		&lt;div id=&quot;linkList2&quot;&gt;
			&lt;div id=&quot;lselect&quot;&gt;
				&lt;h3 class=&quot;select&quot;&gt;&lt;span&gt;Select a Design:&lt;/span&gt;&lt;/h3&gt;
				&lt;ul&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/202/202.css&amp;amp;page=0&quot; title=&quot;AccessKey: a&quot; accesskey=&quot;a&quot;&gt;Retro Theater&lt;/a&gt; by &lt;a href=&quot;http://space-sheeps.info/&quot; class=&quot;c&quot;&gt;Eric Rog&amp;eacute;&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/201/201.css&amp;amp;page=0&quot; title=&quot;AccessKey: b&quot; accesskey=&quot;b&quot;&gt;Lily Pond&lt;/a&gt; by &lt;a href=&quot;http://www.tulips4rose.com&quot; class=&quot;c&quot;&gt;Rose Thorogood&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/200/200.css&amp;amp;page=0&quot; title=&quot;AccessKey: c&quot; accesskey=&quot;c&quot;&gt;Icicle Outback&lt;/a&gt; by &lt;a href=&quot;http://www.timovirtanen.com/&quot; class=&quot;c&quot;&gt;Timo Virtanen&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/199/199.css&amp;amp;page=0&quot; title=&quot;AccessKey: d&quot; accesskey=&quot;d&quot;&gt;Zen Army&lt;/a&gt; by &lt;a href=&quot;http://www.niceguy.com/&quot; class=&quot;c&quot;&gt;Carl Desmond&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/198/198.css&amp;amp;page=0&quot; title=&quot;AccessKey: e&quot; accesskey=&quot;e&quot;&gt;The Original&lt;/a&gt; by &lt;a href=&quot;http://www.bluejam.com/&quot; class=&quot;c&quot;&gt;Joachim Shotter&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/197/197.css&amp;amp;page=0&quot; title=&quot;AccessKey: f&quot; accesskey=&quot;f&quot;&gt;Floral Touch&lt;/a&gt; by &lt;a href=&quot;http://www.jahmasta.com/&quot; class=&quot;c&quot;&gt;Jadas Jimmy&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/196/196.css&amp;amp;page=0&quot; title=&quot;AccessKey: g&quot; accesskey=&quot;g&quot;&gt;Elegance in Simplicity&lt;/a&gt; by &lt;a href=&quot;http://www.manisheriar.com/blog/&quot; class=&quot;c&quot;&gt;Mani Sheriar&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/195/195.css&amp;amp;page=0&quot; title=&quot;AccessKey: h&quot; accesskey=&quot;h&quot;&gt;Dazzling Beauty&lt;/a&gt; by &lt;a href=&quot;http://blog.denysri.com/&quot; class=&quot;c&quot;&gt;Deny Sri Supriyono&lt;/a&gt;&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;
&nbsp;
			&lt;div id=&quot;larchives&quot;&gt;
				&lt;h3 class=&quot;archives&quot;&gt;&lt;span&gt;Archives:&lt;/span&gt;&lt;/h3&gt;
				&lt;ul&gt;
					&lt;li&gt;&lt;a href=&quot;/?cssfile=/001/001.css&amp;amp;page=1&quot; title=&quot;View next set of designs. AccessKey: n&quot; accesskey=&quot;n&quot;&gt;&lt;span class=&quot;accesskey&quot;&gt;n&lt;/span&gt;ext designs &amp;raquo;&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/alldesigns/&quot; title=&quot;View every submission to the Zen Garden. AccessKey: w&quot; accesskey=&quot;w&quot;&gt;Vie&lt;span class=&quot;accesskey&quot;&gt;w&lt;/span&gt; All Designs&lt;/a&gt;&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;
&nbsp;
			&lt;div id=&quot;lresources&quot;&gt;
				&lt;h3 class=&quot;resources&quot;&gt;&lt;span&gt;Resources:&lt;/span&gt;&lt;/h3&gt;
				&lt;ul&gt;
					&lt;li&gt;&lt;a href=&quot;/001/001.css&quot; title=&quot;View the source CSS file for the currently-viewed design, AccessKey: v&quot; accesskey=&quot;v&quot;&gt;&lt;span class=&quot;accesskey&quot;&gt;V&lt;/span&gt;iew This Design&amp;#8217;s &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;&lt;/a&gt;&lt;/li&gt;					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/resources/&quot; title=&quot;Links to great sites with information on using CSS. AccessKey: r&quot; accesskey=&quot;r&quot;&gt;&lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; &lt;span class=&quot;accesskey&quot;&gt;R&lt;/span&gt;esources&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/faq/&quot; title=&quot;A list of Frequently Asked Questions about the Zen Garden. AccessKey: q&quot; accesskey=&quot;q&quot;&gt;&lt;acronym title=&quot;Frequently Asked Questions&quot;&gt;FA&lt;span class=&quot;accesskey&quot;&gt;Q&lt;/span&gt;&lt;/acronym&gt;&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/submit/&quot; title=&quot;Send in your own CSS file. AccessKey: s&quot; accesskey=&quot;s&quot;&gt;&lt;span class=&quot;accesskey&quot;&gt;S&lt;/span&gt;ubmit a Design&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/translations/&quot; title=&quot;View translated versions of this page. AccessKey: t&quot; accesskey=&quot;t&quot;&gt;&lt;span class=&quot;accesskey&quot;&gt;T&lt;/span&gt;ranslations&lt;/a&gt;&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&nbsp;
&nbsp;
&lt;/div&gt;
&nbsp;
&lt;!-- These extra divs/spans may be used as catch-alls to add extra imagery. --&gt;
&lt;div id=&quot;extraDiv1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id=&quot;extraDiv2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id=&quot;extraDiv3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
XXXX
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
</div>
<div class="foldingcode"><a href="javascript:showme('3925_7');"> Code: <b>csszengarden.structure.html</b></a><br />
<div style="display: none; background:white;" id=3925_7>
<pre>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;
	&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; &gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=iso-8859-1&quot; /&gt;
	&lt;meta name=&quot;author&quot; content=&quot;Dave Shea&quot; /&gt;
	&lt;meta name=&quot;keywords&quot; content=&quot;design, css, cascading, style, sheets, xhtml, graphic design, w3c, web standards, visual, display&quot; /&gt;
	&lt;meta name=&quot;description&quot; content=&quot;A demonstration of what can be accomplished visually through CSS-based design.&quot; /&gt;
	&lt;meta name=&quot;robots&quot; content=&quot;all&quot; /&gt;
	&lt;title&gt;css Zen Garden: The Beauty in CSS Design&lt;/title&gt;
&nbsp;
	&lt;!-- to correct the unsightly Flash of Unstyled Content. http://www.bluerobot.com/web/css/fouc.asp --&gt;
&nbsp;
&nbsp;
	&lt;style type=&quot;text/css&quot; title=&quot;currentStyle&quot; media=&quot;screen&quot;&gt;
		@import &quot;/001/001.css&quot;;
	&lt;/style&gt;
	&lt;link rel=&quot;Shortcut Icon&quot; type=&quot;image/x-icon&quot; href=&quot;http://www.csszengarden.com/favicon.ico&quot; /&gt;
	&lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS&quot; href=&quot;http://www.csszengarden.com/zengarden.xml&quot; /&gt;
&lt;/head&gt;
&nbsp;
&lt;!--
&nbsp;
&nbsp;
	This xhtml document is marked up to provide the designer with the maximum possible flexibility.
	There are more classes and extraneous tags than needed, and in a real world situation, it's more
	likely that it would be much leaner.
&nbsp;
	However, I think we can all agree that even given that, we're still better off than if this had been
	built with tables.
&nbsp;
&nbsp;
--&gt;
&nbsp;
&lt;body id=&quot;css-zen-garden&quot;&gt;
&lt;div id=&quot;container&quot;&gt;
	&lt;div id=&quot;intro&quot;&gt;
		&lt;div id=&quot;pageHeader&quot;&gt;
			&lt;h1&gt;&lt;span&gt;css Zen Garden&lt;/span&gt;&lt;/h1&gt;
			&lt;h2&gt;&lt;span&gt;The Beauty of &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; Design&lt;/span&gt;&lt;/h2&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;quickSummary&quot;&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;A demonstration of what can be accomplished visually through &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;-based design. Select any style sheet from the list to load it into this page.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;Download the sample &lt;a href=&quot;/zengarden-sample.html&quot; title=&quot;This page's source HTML code, not to be modified.&quot;&gt;html file&lt;/a&gt; and &lt;a href=&quot;/zengarden-sample.css&quot; title=&quot;This page's sample CSS, the file you may modify.&quot;&gt;css file&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;preamble&quot;&gt;
			&lt;h3&gt;&lt;span&gt;The Road to Enlightenment&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;Littering a dark and dreary road lay the past relics of browser-specific tags, incompatible &lt;acronym title=&quot;Document Object Model&quot;&gt;DOM&lt;/acronym&gt;s, and broken &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; support.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;Today, we must clear the mind of past practices. Web enlightenment has been achieved thanks to the tireless efforts of folk like the &lt;acronym title=&quot;World Wide Web Consortium&quot;&gt;W3C&lt;/acronym&gt;, &lt;acronym title=&quot;Web Standards Project&quot;&gt;WaSP&lt;/acronym&gt; and the major browser creators.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p3&quot;&gt;&lt;span&gt;The css Zen Garden invites you to relax and meditate on the important lessons of the masters. Begin to see with clarity. Learn to use the (yet to be) time-honored techniques in new and invigorating fashion. Become one with the web.&lt;/span&gt;&lt;/p&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&nbsp;
	&lt;div id=&quot;supportingText&quot;&gt;
		&lt;div id=&quot;explanation&quot;&gt;
			&lt;h3&gt;&lt;span&gt;So What is This About?&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;There is clearly a need for &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; to be taken seriously by graphic artists. The Zen Garden aims to excite, inspire, and encourage participation. To begin, view some of the existing designs in the list. Clicking on any one will load the style sheet into this very page. The code remains the same, the only thing that has changed is the external .css file. Yes, really.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;&lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; allows complete and total control over the style of a hypertext document. The only way this can be illustrated in a way that gets people excited is by demonstrating what it can truly be, once the reins are placed in the hands of those able to create beauty from structure. To date, most examples of neat tricks and hacks have been demonstrated by structurists and coders. Designers have yet to make their mark. This needs to change.&lt;/span&gt;&lt;/p&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;participation&quot;&gt;
			&lt;h3&gt;&lt;span&gt;Participation&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;Graphic artists only please. You are modifying this page, so strong &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; skills are necessary, but the example files are commented well enough that even &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; novices can use them as starting points. Please see the &lt;a href=&quot;http://www.mezzoblue.com/zengarden/resources/&quot; title=&quot;A listing of CSS-related resources&quot;&gt;&lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; Resource Guide&lt;/a&gt; for advanced tutorials and tips on working with &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;You may modify the style sheet in any way you wish, but not the &lt;acronym title=&quot;HyperText Markup Language&quot;&gt;HTML&lt;/acronym&gt;. This may seem daunting at first if you&amp;#8217;ve never worked this way before, but follow the listed links to learn more, and use the sample files as a guide.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p3&quot;&gt;&lt;span&gt;Download the sample &lt;a href=&quot;/zengarden-sample.html&quot; title=&quot;This page's source HTML code, not to be modified.&quot;&gt;html file&lt;/a&gt; and &lt;a href=&quot;/zengarden-sample.css&quot; title=&quot;This page's sample CSS, the file you may modify.&quot;&gt;css file&lt;/a&gt; to work on a copy locally. Once you have completed your masterpiece (and please, don&amp;#8217;t submit half-finished work) upload your .css file to a web server under your control. &lt;a href=&quot;http://www.mezzoblue.com/zengarden/submit/&quot; title=&quot;Use the contact form to send us your CSS file&quot;&gt;Send us a link&lt;/a&gt; to the file and if we choose to use it, we will spider the associated images. Final submissions will be placed on our server.&lt;/span&gt;&lt;/p&gt;
					&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;benefits&quot;&gt;
			&lt;h3&gt;&lt;span&gt;Benefits&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;Why participate? For recognition, inspiration, and a resource we can all refer to when making the case for &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;-based design. This is sorely needed, even today. More and more major sites are taking the leap, but not enough have. One day this gallery will be a historical curiosity; that day is not today.&lt;/span&gt;&lt;/p&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;requirements&quot;&gt;
			&lt;h3&gt;&lt;span&gt;Requirements&lt;/span&gt;&lt;/h3&gt;
			&lt;p class=&quot;p1&quot;&gt;&lt;span&gt;We would like to see as much &lt;acronym title=&quot;Cascading Style Sheets, version 1&quot;&gt;CSS1&lt;/acronym&gt; as possible. &lt;acronym title=&quot;Cascading Style Sheets, version 2&quot;&gt;CSS2&lt;/acronym&gt; should be limited to widely-supported elements only. The css Zen Garden is about functional, practical &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; and not the latest bleeding-edge tricks viewable by 2% of the browsing public. The only real requirement we have is that your &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; validates.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p2&quot;&gt;&lt;span&gt;Unfortunately, designing this way highlights the flaws in the various implementations of &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;. Different browsers display differently, even completely valid &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; at times, and this becomes maddening when a fix for one leads to breakage in another. View the &lt;a href=&quot;http://www.mezzoblue.com/zengarden/resources/&quot; title=&quot;A listing of CSS-related resources&quot;&gt;Resources&lt;/a&gt; page for information on some of the fixes available. Full browser compliance is still sometimes a pipe dream, and we do not expect you to come up with pixel-perfect code across every platform. But do test in as many as you can. If your design doesn&amp;#8217;t work in at least IE5+/Win and Mozilla (run by over 90% of the population), chances are we won&amp;#8217;t accept it.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p3&quot;&gt;&lt;span&gt;We ask that you submit original artwork. Please respect copyright laws. Please keep objectionable material to a minimum; tasteful nudity is acceptable, outright pornography will be rejected.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p4&quot;&gt;&lt;span&gt;This is a learning exercise as well as a demonstration. You retain full copyright on your graphics (with limited exceptions, see &lt;a href=&quot;http://www.mezzoblue.com/zengarden/submit/guidelines/&quot;&gt;submission guidelines&lt;/a&gt;), but we ask you release your &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; under a Creative Commons license identical to the &lt;a href=&quot;http://creativecommons.org/licenses/by-nc-sa/1.0/&quot; title=&quot;View the Zen Garden's license information.&quot;&gt;one on this site&lt;/a&gt; so that others may learn from your work.&lt;/span&gt;&lt;/p&gt;
			&lt;p class=&quot;p5&quot;&gt;&lt;span&gt;Bandwidth graciously donated by &lt;a href=&quot;http://www.dreamfirestudios.com/&quot;&gt;DreamFire Studios&lt;/a&gt;. Now available: &lt;a href=&quot;http://www.amazon.com/exec/obidos/ASIN/0321303474/mezzoblue-20/&quot;&gt;Zen Garden, the book&lt;/a&gt;.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
		&lt;/div&gt;
&nbsp;
		&lt;div id=&quot;footer&quot;&gt;
			&lt;a href=&quot;http://validator.w3.org/check/referer&quot; title=&quot;Check the validity of this site&amp;#8217;s XHTML&quot;&gt;xhtml&lt;/a&gt; &amp;nbsp;
			&lt;a href=&quot;http://jigsaw.w3.org/css-validator/check/referer&quot; title=&quot;Check the validity of this site&amp;#8217;s CSS&quot;&gt;css&lt;/a&gt; &amp;nbsp;
			&lt;a href=&quot;http://creativecommons.org/licenses/by-nc-sa/1.0/&quot; title=&quot;View details of the license of this site, courtesy of Creative Commons.&quot;&gt;cc&lt;/a&gt; &amp;nbsp;
			&lt;a href=&quot;http://www.contentquality.com/mynewtester/cynthia.exe?Url1=http:%2F%2Fcsszengarden.com%2F&quot; title=&quot;Check the accessibility of this site according to U.S. Section 508&quot;&gt;508&lt;/a&gt; &amp;nbsp;
			&lt;a href=&quot;http://mezzoblue.com/zengarden/faq/#aaa&quot; title=&quot;Check the accessibility of this site according to Web Content Accessibility Guidelines 1.0&quot;&gt;aaa&lt;/a&gt;
		&lt;/div&gt;
&nbsp;
	&lt;/div&gt;
&nbsp;
&nbsp;
	&lt;div id=&quot;linkList&quot;&gt;
		&lt;div id=&quot;linkList2&quot;&gt;
			&lt;div id=&quot;lselect&quot;&gt;
				&lt;h3 class=&quot;select&quot;&gt;&lt;span&gt;Select a Design:&lt;/span&gt;&lt;/h3&gt;
				&lt;ul&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/202/202.css&amp;amp;page=0&quot; title=&quot;AccessKey: a&quot; accesskey=&quot;a&quot;&gt;Retro Theater&lt;/a&gt; by &lt;a href=&quot;http://space-sheeps.info/&quot; class=&quot;c&quot;&gt;Eric Rog&amp;eacute;&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/201/201.css&amp;amp;page=0&quot; title=&quot;AccessKey: b&quot; accesskey=&quot;b&quot;&gt;Lily Pond&lt;/a&gt; by &lt;a href=&quot;http://www.tulips4rose.com&quot; class=&quot;c&quot;&gt;Rose Thorogood&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/200/200.css&amp;amp;page=0&quot; title=&quot;AccessKey: c&quot; accesskey=&quot;c&quot;&gt;Icicle Outback&lt;/a&gt; by &lt;a href=&quot;http://www.timovirtanen.com/&quot; class=&quot;c&quot;&gt;Timo Virtanen&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/199/199.css&amp;amp;page=0&quot; title=&quot;AccessKey: d&quot; accesskey=&quot;d&quot;&gt;Zen Army&lt;/a&gt; by &lt;a href=&quot;http://www.niceguy.com/&quot; class=&quot;c&quot;&gt;Carl Desmond&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/198/198.css&amp;amp;page=0&quot; title=&quot;AccessKey: e&quot; accesskey=&quot;e&quot;&gt;The Original&lt;/a&gt; by &lt;a href=&quot;http://www.bluejam.com/&quot; class=&quot;c&quot;&gt;Joachim Shotter&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/197/197.css&amp;amp;page=0&quot; title=&quot;AccessKey: f&quot; accesskey=&quot;f&quot;&gt;Floral Touch&lt;/a&gt; by &lt;a href=&quot;http://www.jahmasta.com/&quot; class=&quot;c&quot;&gt;Jadas Jimmy&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/196/196.css&amp;amp;page=0&quot; title=&quot;AccessKey: g&quot; accesskey=&quot;g&quot;&gt;Elegance in Simplicity&lt;/a&gt; by &lt;a href=&quot;http://www.manisheriar.com/blog/&quot; class=&quot;c&quot;&gt;Mani Sheriar&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;?cssfile=/195/195.css&amp;amp;page=0&quot; title=&quot;AccessKey: h&quot; accesskey=&quot;h&quot;&gt;Dazzling Beauty&lt;/a&gt; by &lt;a href=&quot;http://blog.denysri.com/&quot; class=&quot;c&quot;&gt;Deny Sri Supriyono&lt;/a&gt;&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;
&nbsp;
			&lt;div id=&quot;larchives&quot;&gt;
				&lt;h3 class=&quot;archives&quot;&gt;&lt;span&gt;Archives:&lt;/span&gt;&lt;/h3&gt;
				&lt;ul&gt;
					&lt;li&gt;&lt;a href=&quot;/?cssfile=/001/001.css&amp;amp;page=1&quot; title=&quot;View next set of designs. AccessKey: n&quot; accesskey=&quot;n&quot;&gt;&lt;span class=&quot;accesskey&quot;&gt;n&lt;/span&gt;ext designs &amp;raquo;&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/alldesigns/&quot; title=&quot;View every submission to the Zen Garden. AccessKey: w&quot; accesskey=&quot;w&quot;&gt;Vie&lt;span class=&quot;accesskey&quot;&gt;w&lt;/span&gt; All Designs&lt;/a&gt;&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;
&nbsp;
			&lt;div id=&quot;lresources&quot;&gt;
				&lt;h3 class=&quot;resources&quot;&gt;&lt;span&gt;Resources:&lt;/span&gt;&lt;/h3&gt;
				&lt;ul&gt;
					&lt;li&gt;&lt;a href=&quot;/001/001.css&quot; title=&quot;View the source CSS file for the currently-viewed design, AccessKey: v&quot; accesskey=&quot;v&quot;&gt;&lt;span class=&quot;accesskey&quot;&gt;V&lt;/span&gt;iew This Design&amp;#8217;s &lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt;&lt;/a&gt;&lt;/li&gt;					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/resources/&quot; title=&quot;Links to great sites with information on using CSS. AccessKey: r&quot; accesskey=&quot;r&quot;&gt;&lt;acronym title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/acronym&gt; &lt;span class=&quot;accesskey&quot;&gt;R&lt;/span&gt;esources&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/faq/&quot; title=&quot;A list of Frequently Asked Questions about the Zen Garden. AccessKey: q&quot; accesskey=&quot;q&quot;&gt;&lt;acronym title=&quot;Frequently Asked Questions&quot;&gt;FA&lt;span class=&quot;accesskey&quot;&gt;Q&lt;/span&gt;&lt;/acronym&gt;&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/submit/&quot; title=&quot;Send in your own CSS file. AccessKey: s&quot; accesskey=&quot;s&quot;&gt;&lt;span class=&quot;accesskey&quot;&gt;S&lt;/span&gt;ubmit a Design&lt;/a&gt;&lt;/li&gt;
					&lt;li&gt;&lt;a href=&quot;http://www.mezzoblue.com/zengarden/translations/&quot; title=&quot;View translated versions of this page. AccessKey: t&quot; accesskey=&quot;t&quot;&gt;&lt;span class=&quot;accesskey&quot;&gt;T&lt;/span&gt;ranslations&lt;/a&gt;&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&nbsp;
&nbsp;
&lt;/div&gt;
&nbsp;
&lt;!-- These extra divs/spans may be used as catch-alls to add extra imagery. --&gt;
&lt;div id=&quot;extraDiv1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id=&quot;extraDiv2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id=&quot;extraDiv3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
function removeSheets(){
  if(document.styleSheets){
    var c = document.styleSheets.length;
    for(var i=0;i&lt;c;i++){
		document.styleSheets[i].disabled=true;
    }
  }
  findNamedElements();
}
function findNamedElements(){
	allElements = document.getElementsByTagName('*');
	for(i=0;i&lt;allElements.length;i++){
		allElements[i].style.cssText = '';
		if(allElements[i].id){
			allElements[i].style.position = 'relative';
			allElements[i].style.border = '1px solid silver';
			allElements[i].style.padding = '20px';
			allElements[i].style.margin = '10px';
			p=document.createElement('p');
			sometext = document.createTextNode(allElements[i].id);
			p.appendChild(sometext);
			p.className = 'cartel';
			allElements[i].appendChild(p);
		}
	}
	if (window.innerWidth){
		var styleText = '.cartel{border:1px dashed red;position:absolute;top:0;left:0;padding:2px;background-color:#fff}';
		var head=document.getElementsByTagName(&quot;head&quot;)[0];
		var styleNode = document.createElement(&quot;style&quot;);
		styleNode.appendChild(document.createTextNode(styleText));
		head.appendChild(styleNode);
	}else{
		var newStyle = document.createStyleSheet();
		newStyle.addRule('.cartel','border:1px dashed red;position:absolute;top:0;left:0;padding:2px;background-color:#fff');
	}
}
removeSheets();
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
</div>
<div class="foldingcode"><a href="javascript:showme('3925_8');"> Code: <b>csszengarden.css</b></a><br />
<div style="display: none; background:white;" id=3925_8>
<pre>@import url(zero.css);body{text-align:center;}#css-zen-garden{

}
#container{

}
#intro{

}
#pageHeader{

}
#quickSummary{

}
#preamble{

}
#supportingText{

}
#explanation{

}
#participation{

}
#benefits{

}
#requirements{

}
#footer{

}
#linkList{

}
#linkList2{

}
#lselect{

}
#larchives{

}
#lresources{

}
#extraDiv1{

}
#extraDiv2{

}
#extraDiv3{

}
.supportingText{

}
.benefits{

}
.extraDiv3{

}
.extraDiv2{

}
.lselect{

}
.footer{

}
.larchives{

}
.lresources{

}
.linkList{

}
.intro{

}
.preamble{

}
.container{

}
.requirements{

}
.css-zen-garden{

}
.quickSummary{

}
.explanation{

}
.pageHeader{

}
.extraDiv1{

}
.linkList2{

}
.participation{

}
&nbsp;</pre>
</div>
</div>
<p>Something like this. Click to expand(PNG 239KB):<br />
<a href="/uploads/stylizator/stylizator.large.png"><img src="/uploads/stylizator/stylizator.large_p.png"></a></p>
<h2>The code</h2>
<p>Download <a href="/uploads/stylizator/stylizator.zip">this file</a>, unzip it in the same folder and call it via >perl stylizator.pl yourhtmlfile.html<br />
It&#8217;ll create a file named yourhtmlfile.css and another one called yourhtmlfile.structure.html</p>
<h2>Further work</h2>
<p>There&#8217;s so much to be done. It could be possible to create a firefox extension that gives us the same visual result at the press of a button, or a system that keeps only structural CSS, discarding type and colors. The regular expressions could be better, too, to allow not-so-well-defined documents.  If you have any further questions, drop me a line to <a href="mailto:david@corunet.com">david@corunet.com</a>. </p>
<p>Have fun.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.corunet.com/english/automatic-css-the-stylizator/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Three column layout with full page height</title>
		<link>http://blog.corunet.com/english/three-column-layout-with-full-page-height</link>
		<comments>http://blog.corunet.com/english/three-column-layout-with-full-page-height#comments</comments>
		<pubDate>Thu, 14 Jun 2007 19:36:56 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
	<category>English</category>
	<category>CSS and Javascript</category>
		<guid isPermaLink="false">http://blog.corunet.com/english/three-column-layout-with-full-page-height</guid>
		<description><![CDATA[Sometimes I wish I could do things that were easily done with table-based layouts but quite hard using just CSS.
Following a couple of posts in a CSS related Spanish mailing list (Ovillo),  a guy called Zafonic showed me how to use negative margins and positive paddings to make equal sized columns. With a couple [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/uploads/threecolumns/3.png" align="left" title="The final layout" width="150" height="100" border="0" hspace="3" vspace="3">Sometimes I wish I could do things that were easily done with table-based layouts but quite hard using just CSS.<br />
Following a couple of posts in a CSS related Spanish mailing list (Ovillo),  a guy called Zafonic showed me how to use negative margins and positive paddings to make equal sized columns. With a couple javascript functions, I patched it to fill the full browser window. Let&#8217;s see how&#8230;<br />
<strong>Update:</strong> Error in code solved. Thanks to the testers<a id="more-13"></a></p>
<h2>The problem</h2>
<p>We&#8217;re going to write a three-column plus footer layout that covers all the browser space. The requisites are the following:</p>
<ul>
<li>The three columns will have different background colors</li>
<li>We&#8217;re not going to use background images (so, no <a href="http://alistapart.com/articles/fauxcolumns/">faux-columns</a>)</li>
<li>We want the page to cover the full height of the browser. So, the footer will be at the bottom of the screen.</li>
<li>The layout has to degrade gracefully for javascript disabled browsers</li>
<li>All the code has to be valid and accesible</li>
</ul>
<h2>The beginning</h2>
<p>The first part is simple. We need some html that defines three columns and a footer. Lets wrap the three columns within a div (called, by the way, container) and call the three columns col1, col2 and col3. The html code will be something like:</p>
<div class="foldingcode"><a href="javascript:showme('8729_1');"> Code: <b>body.html</b></a><br />
<div style="display: none; background:white;" id=8729_1>
<pre>&lt;body&gt;
	&lt;div id=&quot;container&quot;&gt;
		&lt;div id=&quot;col1&quot;&gt;
			first column&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;
		&lt;/div&gt;
		&lt;div id=&quot;col2&quot;&gt;
			second column&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-
		&lt;/div&gt;
		&lt;div id=&quot;col3&quot;&gt;
			third column&lt;br /&gt;-&lt;br /&gt;-
		&lt;/div&gt;
	&lt;/div&gt;
	 &lt;div id=&quot;footer&quot;&gt;footer&lt;br /&gt;-&lt;/div&gt;
&lt;/body&gt;
&nbsp;</pre>
</div>
</div>
<p>We need to give the columns a width and float them to the left. The css would be:</p>
<div class="foldingcode"><a href="javascript:showme('8729_2');"> Code: <b>first.css</b></a><br />
<div style="display: none; background:white;" id=8729_2>
<pre class="css">body<span style="color: #66cc66;">&#123;</span>
	margin<span style="color: #3333ff;">:<span style="color: #cc66cc;">0</span> </span>auto;
<span style="color: #66cc66;">&#125;</span>
#col1<span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">background-color</span>:<span style="color: #993333;">red</span>;
	<span style="color: #000000; font-weight: bold;">width</span>:<span style="color: #cc66cc;">20</span>%;
	<span style="color: #000000; font-weight: bold;">float</span>:<span style="color: #000000; font-weight: bold;">left</span>;
<span style="color: #66cc66;">&#125;</span>
#col2<span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">background-color</span>:<span style="color: #000000; font-weight: bold;">blue</span>;
	<span style="color: #000000; font-weight: bold;">width</span>:<span style="color: #cc66cc;">60</span>%;
	<span style="color: #000000; font-weight: bold;">float</span>:<span style="color: #000000; font-weight: bold;">left</span>;
<span style="color: #66cc66;">&#125;</span>
#col3<span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">background-color</span>:<span style="color: #993333;">yellow</span>;
	<span style="color: #000000; font-weight: bold;">width</span>:<span style="color: #cc66cc;">20</span>%;
	<span style="color: #000000; font-weight: bold;">float</span>:<span style="color: #000000; font-weight: bold;">left</span>;
<span style="color: #66cc66;">&#125;</span>
#footer<span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">height</span>:40px;
	<span style="color: #000000; font-weight: bold;">clear</span>:<span style="color: #993333;">both</span>;
	<span style="color: #000000; font-weight: bold;">background-color</span>:<span style="color: #000000; font-weight: bold;">black</span>;
	<span style="color: #000000; font-weight: bold;">color</span>:<span style="color: #993333;">white</span>;
	<span style="color: #000000; font-weight: bold;">width</span>:<span style="color: #cc66cc;">100</span>%;
<span style="color: #66cc66;">&#125;</span></pre>
</div>
</div>
<p>So, we already have a three column layout, but each column has a diferent height and the footer is far from the bottom:</p>
<p><img src="/uploads/threecolumns/1.png" alt="first version" /></p>
<h2>Negative margins to the rescue</h2>
<p>As I already told you, I had&#8217;t heard about creating layouts using negative margins (I should have read <a href="http://alistapart.com/articles/negativemargins">this article from A List Apart</a> some time ago). In a nutshell, it says that you can use a large negative margin and the opposite positive padding to &#8220;make room for the columns&#8221;. I recommend to read it if you haven&#8217;t, it&#8217;s very useful.<br />
So, let&#8217;s go on the code. We&#8217;re going to add a -5000 pixel margin-bottom and a 5000 pixel padding-bottom to each column:</p>
<div class="foldingcode"><a href="javascript:showme('8729_3');"> Code: <b>second.css</b></a><br />
<div style="display: none; background:white;" id=8729_3>
<pre class="css">body<span style="color: #66cc66;">&#123;</span>
	margin<span style="color: #3333ff;">:<span style="color: #cc66cc;">0</span> </span>auto;
<span style="color: #66cc66;">&#125;</span>
#col1<span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">background-color</span>:<span style="color: #993333;">red</span>;
	<span style="color: #000000; font-weight: bold;">width</span>:<span style="color: #cc66cc;">20</span>%;
	<span style="color: #000000; font-weight: bold;">float</span>:<span style="color: #000000; font-weight: bold;">left</span>;
	<span style="color: #000000; font-weight: bold;">margin-bottom</span>:-5000px;
 	<span style="color: #000000; font-weight: bold;">padding-bottom</span>:5000px;
<span style="color: #66cc66;">&#125;</span>
#col2<span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">background-color</span>:<span style="color: #000000; font-weight: bold;">blue</span>;
	<span style="color: #000000; font-weight: bold;">width</span>:<span style="color: #cc66cc;">60</span>%;
	<span style="color: #000000; font-weight: bold;">float</span>:<span style="color: #000000; font-weight: bold;">left</span>;
	<span style="color: #000000; font-weight: bold;">margin-bottom</span>:-5000px;
 	<span style="color: #000000; font-weight: bold;">padding-bottom</span>:5000px;
<span style="color: #66cc66;">&#125;</span>
#col3<span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">background-color</span>:<span style="color: #993333;">yellow</span>;
	<span style="color: #000000; font-weight: bold;">width</span>:<span style="color: #cc66cc;">20</span>%;
	<span style="color: #000000; font-weight: bold;">float</span>:<span style="color: #000000; font-weight: bold;">left</span>;
	<span style="color: #000000; font-weight: bold;">margin-bottom</span>:-5000px;
 	<span style="color: #000000; font-weight: bold;">padding-bottom</span>:5000px;
<span style="color: #66cc66;">&#125;</span>
#footer<span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">height</span>:40px;
	<span style="color: #000000; font-weight: bold;">clear</span>:<span style="color: #993333;">both</span>;
	<span style="color: #000000; font-weight: bold;">background-color</span>:<span style="color: #000000; font-weight: bold;">black</span>;
	<span style="color: #000000; font-weight: bold;">color</span>:<span style="color: #993333;">white</span>;
	<span style="color: #000000; font-weight: bold;">width</span>:<span style="color: #cc66cc;">100</span>%;
	<span style="color: #000000; font-weight: bold;">margin-bottom</span>:-5000px;
 	<span style="color: #000000; font-weight: bold;">padding-bottom</span>:5000px;
<span style="color: #66cc66;">&#125;</span></pre>
</div>
</div>
<p>This way we get same height columns. This looks much better:</p>
<p><img src="/uploads/threecolumns/2.png" alt="second version" /></p>
<p>but we don&#8217;t have 100% height yet. Internet explorer supports 100% height but all the other browsers don&#8217;t. So, we&#8217;ll need to use javascript to solve it:</p>
<h2>Filling the screen - Here comes Javascript</h2>
<p>The first thing we need is to find the height of the browser window. I use a small javascript function that takes into account the diferent behaviours of the different browsers:</p>
<div class="foldingcode"><a href="javascript:showme('8729_4');"> Code: <b>height.js</b></a><br />
<div style="display: none; background:white;" id=8729_4>
<pre class="javascript"><span style="color: #003366; font-weight: bold;">function</span> windowHeight<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	<span style="color: #003366; font-weight: bold;">var</span> alto= <span style="color: #CC0000;">0</span>;
	<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span> <span style="color: #000066; font-weight: bold;">typeof</span><span style="color: #66cc66;">&#40;</span> window.<span style="color: #006600;">innerWidth</span> <span style="color: #66cc66;">&#41;</span> == <span style="color: #3366CC;">'number'</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
		alto= window.<span style="color: #006600;">innerHeight</span>;
	<span style="color: #66cc66;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span> document.<span style="color: #006600;">documentElement</span> &amp;&amp; <span style="color: #66cc66;">&#40;</span> document.<span style="color: #006600;">documentElement</span>.<span style="color: #006600;">clientWidth</span> || document.<span style="color: #006600;">documentElement</span>.<span style="color: #006600;">clientHeight</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
		alto= document.<span style="color: #006600;">documentElement</span>.<span style="color: #006600;">clientHeight</span>;
	<span style="color: #66cc66;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span> document.<span style="color: #006600;">body</span> &amp;&amp; <span style="color: #66cc66;">&#40;</span> document.<span style="color: #006600;">body</span>.<span style="color: #006600;">clientWidth</span> || document.<span style="color: #006600;">body</span>.<span style="color: #006600;">clientHeight</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
		alto= document.<span style="color: #006600;">body</span>.<span style="color: #006600;">clientHeight</span>;
	<span style="color: #66cc66;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">return</span> alto;
<span style="color: #66cc66;">&#125;</span></pre>
</div>
</div>
<p>This function returns the height of the browser window. It does one thing and does it well&#8230; Using this new knokledge, we can set the height of the columns, making them the browser&#8217;s window height minus the footer, to fill the screen completely. The other function we&#8217;ll need is:</p>
<div class="foldingcode"><a href="javascript:showme('8729_5');"> Code: <b>fill.js</b></a><br />
<div style="display: none; background:white;" id=8729_5>
<pre class="javascript"><span style="color: #003366; font-weight: bold;">function</span> fillthescreen<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	winH = windowHeight<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #009900; font-style: italic;">//This returns the screen heigth</span>
	heightNeeded=winH<span style="color: #CC0000;">-40</span>; <span style="color: #009900; font-style: italic;">//We need to substract the footer height</span>
	<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span> <span style="color: #000066; font-weight: bold;">typeof</span><span style="color: #66cc66;">&#40;</span> window.<span style="color: #006600;">innerWidth</span> <span style="color: #66cc66;">&#41;</span> != <span style="color: #3366CC;">'number'</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #009900; font-style: italic;">//Explorer doesn't recognize minHeight</span>
		document.<span style="color: #006600;">getElementById</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'co11'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">height</span>=heightNeeded+<span style="color: #3366CC;">'px'</span>; <span style="color: #009900; font-style: italic;">//So, we use height (and explroer bug)</span>
	<span style="color: #66cc66;">&#125;</span>
	document.<span style="color: #006600;">getElementById</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'col1'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">minHeight</span>=heightNeeded+<span style="color: #3366CC;">'px'</span>; <span style="color: #009900; font-style: italic;">//For every other browser, we use minHeight</span>
<span style="color: #66cc66;">&#125;</span></pre>
</div>
</div>
<p>This function works by calling the last one (windowHeight) and substracting the footer size. If we&#8217;re in Explorer, we use style.height to modify the height of the columns and in all other browsers, minHeight, since Explorer doesn&#8217;t support that attribute. We&#8217;re going to call that function via onload.<br />
And we get this:</p>
<p><img src="/uploads/threecolumns/3.png" alt="third version" /></p>
<p>If the window is not tall enough to fit the column height, the page behaves normally:</p>
<p><img src="/uploads/threecolumns/4.png" alt="small screen" /></p>
<h2>The full code</h2>
<p>Putting all together, this is what we get:</p>
<div class="foldingcode"><a href="javascript:showme('8729_6');"> Code: <b>3.html</b></a><br />
<div style="display: none; background:white;" id=8729_6>
<pre>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;Demo three columns&lt;/title&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
	function fillthescreen(){
		winH = windowHeight(); //This returns the screen heigth
		heightNeeded=winH-40; //We need to substract the footer height
		if( typeof( window.innerWidth ) != 'number' ) { //Explorer doesn't recognize minHeight
			document.getElementById('col1').style.height=heightNeeded+'px'; //So, we use height (and explroer bug)
		}
		document.getElementById('col1').style.minHeight=heightNeeded+'px'; //For every other browser, we use minHeight
	}
&nbsp;
	function windowHeight(){
		var alto= 0;
		if( typeof( window.innerWidth ) == 'number' ) {
			alto= window.innerHeight;
		} else if( document.documentElement &amp;&amp; ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
			alto= document.documentElement.clientHeight;
		} else if( document.body &amp;&amp; ( document.body.clientWidth || document.body.clientHeight ) ) {
			alto= document.body.clientHeight;
		}
		return alto;
	}
&lt;/script&gt;
&lt;style type=&quot;text/css&quot;&gt;
body{
	margin:0 auto;
}
#container{
 overflow:hidden;
}
#col1{
 background-color:red;
 width:20%;
 float:left;
margin-bottom:-5000px;
 padding-bottom:5000px;
 }
#col2{
 background-color:blue;
 width:60%;
 float:left;
margin-bottom:-5000px;
 padding-bottom:5000px;
 }
#col3{
 background-color:yellow;
 width:20%;
 float:left;
margin-bottom:-5000px;
 padding-bottom:5000px;
 }
#footer{
	height:40px;
 clear:both;
 float:none;
 background-color:black;
 color:white;
 width:100%;
}
&nbsp;
&lt;/style&gt;
&lt;/head&gt;
&nbsp;
&lt;body onload=&quot;fillthescreen()&quot;&gt;
	&lt;div id=&quot;container&quot;&gt;
		&lt;div id=&quot;col1&quot;&gt;
			first column&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;
		&lt;/div&gt;
		&lt;div id=&quot;col2&quot;&gt;
			second column&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-&lt;br /&gt;-
		&lt;/div&gt;
		&lt;div id=&quot;col3&quot;&gt;
			third column&lt;br /&gt;-&lt;br /&gt;-
		&lt;/div&gt;
	&lt;/div&gt;
	 &lt;div id=&quot;footer&quot;&gt;footer&lt;br /&gt;-&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
</div>
<p>If you use it in a production environment, it&#8217;d be wise to split the javascript and the CSS into their own files, and review all the code, since it&#8217;s done in a quick and dirty way. </p>
<p>You can download the code using <a href="/uploads/threecolumns/3.zip">this link</a>. People without javascript don&#8217;t get the full height but the site is equally usable and visually pleasant. I you have any further questions or just want to talk, drop me a line to <a href="maito:david@corunet.com">david@corunet.com</a></p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.corunet.com/english/three-column-layout-with-full-page-height/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Clickmaps in sourceforge</title>
		<link>http://blog.corunet.com/english/clickmaps-in-sourceforge</link>
		<comments>http://blog.corunet.com/english/clickmaps-in-sourceforge#comments</comments>
		<pubDate>Mon, 21 Aug 2006 16:55:49 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
	<category>English</category>
	<category>Usability</category>
		<guid isPermaLink="false">http://blog.corunet.com/english/clickmaps-in-sourceforge</guid>
		<description><![CDATA[Today, all the code for creating clickmaps has been uploaded to sourceforge and made public under a GPL license. You can find it at http://sourceforge.net/projects/clickmaps
Thanks to jerret, the code now uses RMagick calls and it&#8217;s usable with logs sporting more than ten thousand clicks per page.

]]></description>
			<content:encoded><![CDATA[<p>Today, all the code for creating clickmaps has been uploaded to sourceforge and made public under a GPL license. You can find it at <a href="http://sourceforge.net/projects/clickmaps">http://sourceforge.net/projects/clickmaps</a></p>
<p>Thanks to jerret, the code now uses RMagick calls and it&#8217;s usable with logs sporting more than ten thousand clicks per page.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.corunet.com/english/clickmaps-in-sourceforge/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>The definitive heatmap</title>
		<link>http://blog.corunet.com/english/the-definitive-heatmap</link>
		<comments>http://blog.corunet.com/english/the-definitive-heatmap#comments</comments>
		<pubDate>Wed, 16 Aug 2006 18:39:21 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
	<category>English</category>
	<category>Usability</category>
		<guid isPermaLink="false">http://blog.corunet.com/english/the-definitive-heatmap</guid>
		<description><![CDATA[The definitive guide to open source clickmaps, including all software under a MIT license]]></description>
			<content:encoded><![CDATA[<p><img src="/uploads/heatmaps/thumbnail.png" align="left" title="The final heatmap" border="0" hspace="3" vspace="3">After the interest shown about the clickmaps / heatmaps articles, I&#8217;ve decided to gather all the information into an easy to use system. What we are going to make is a complete solution that allows collecting, analyzing and showing the click information our users give us. Now, it works in web pages not center aligned and is quite a bit more robust. Read on&#8230;<a id="more-8"></a></p>
<h2>What?<br />
</h2>
<p>If you are a webmaster, you had probably thought about what do users do in your website. Beyond usual statistics, clickmaps allow you to find where your users are clicking. This is quite useful to find areas in needing of change, layouts that don&#8217;t work as intended or anchors that aren&#8217;t being understood as you would like. </p>
<p>You&#8217;re going to be able to find every single click your users make in your website, being over a link or even in blank areas. We are going to do it the following way:</p>
<h2>The proccess<br />
</h2>
<p>We need to divide the full proccess into some manageable steps that use some open source tools. Since I work both in windows and linux systems, I&#8217;ll be <strong>OS agnostic </strong>and use only tools available in most systems, including Mac OSX.<br />
The main steps and the tools they use are the following:</p>
<ol>
<li>The collecting (javascript and apache)</li>
<li>The processing (ruby and imageMagick)</li>
<li>The showing (javascript)</li>
</ol>
<h2>The collecting</h2>
<p>We are going to use  a small snippet of unobtrusive javascript to allow the client to tell our server the click positions. Just place this small javascript file at the very end of your template, right before the closing &lt;body&gt; tag:</p>
<div class="foldingcode"><a href="javascript:showme('3730_1');"> Code: <b>registerclicks.js</b></a><br />
<div style="display: none; background:white;" id=3730_1>
<pre class="javascript"><span style="color: #009900; font-style: italic;">/**
 * @author David Pardo: Corunet
 * Run after loading
 */</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> xOffset,yOffset;
<span style="color: #003366; font-weight: bold;">var</span> tempX = <span style="color: #CC0000;">0</span>;
<span style="color: #003366; font-weight: bold;">var</span> tempY = <span style="color: #CC0000;">0</span>;
&nbsp;
<span style="color: #009900; font-style: italic;">//detect browser</span>
<span style="color: #003366; font-weight: bold;">var</span> IE = document.<span style="color: #006600;">all</span>?<span style="color: #003366; font-weight: bold;">true</span>:<span style="color: #003366; font-weight: bold;">false</span>
<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>!IE<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
	document.<span style="color: #006600;">captureEvents</span><span style="color: #66cc66;">&#40;</span>Event.<span style="color: #006600;">MOUSEMOVE</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#125;</span>
<span style="color: #009900; font-style: italic;">//find the position of the first item on screen and store offsets</span>
	<span style="color: #009900; font-style: italic;">//find the first item on screen (after body)</span>
	<span style="color: #003366; font-weight: bold;">var</span> firstElement=document.<span style="color: #006600;">getElementsByTagName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">childNodes</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #66cc66;">&#93;</span>;
	<span style="color: #009900; font-style: italic;">//find the offset coordinates</span>
	xOffset=findPosX<span style="color: #66cc66;">&#40;</span>firstElement<span style="color: #66cc66;">&#41;</span>;
	yOffset=findPosY<span style="color: #66cc66;">&#40;</span>firstElement<span style="color: #66cc66;">&#41;</span>;
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>IE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span> <span style="color: #009900; font-style: italic;">// In IE there's a default margin in the page body. If margin's not defined, use defaults</span>
		<span style="color: #003366; font-weight: bold;">var</span> marginLeftExplorer  = parseInt<span style="color: #66cc66;">&#40;</span>document.<span style="color: #006600;">getElementsByTagName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">marginLeft</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #003366; font-weight: bold;">var</span> marginTopExplorer   = parseInt<span style="color: #66cc66;">&#40;</span>document.<span style="color: #006600;">getElementsByTagName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">marginTop</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #009900; font-style: italic;">/*assume default 10px/15px margin in explorer*/</span>
		<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>isNaN<span style="color: #66cc66;">&#40;</span>marginLeftExplorer<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>marginLeftExplorer=<span style="color: #CC0000;">10</span>;<span style="color: #66cc66;">&#125;</span>
		<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>isNaN<span style="color: #66cc66;">&#40;</span>marginTopExplorer<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>marginTopExplorer=<span style="color: #CC0000;">15</span>;<span style="color: #66cc66;">&#125;</span>
		xOffset=xOffset+marginLeftExplorer;
		yOffset=yOffset+marginTopExplorer;
	<span style="color: #66cc66;">&#125;</span>
<span style="color: #009900; font-style: italic;">/*attach a handler to the onmousedown event that calls a function to store the values*/</span>
document.<span style="color: #006600;">onmousedown</span> = getMouseXY;
&nbsp;
&nbsp;
&nbsp;
<span style="color: #009900; font-style: italic;">/*Functions*/</span>
<span style="color: #009900; font-style: italic;">/*Find positions*/</span>
<span style="color: #003366; font-weight: bold;">function</span> findPosX<span style="color: #66cc66;">&#40;</span>obj<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	<span style="color: #003366; font-weight: bold;">var</span> curleft = <span style="color: #CC0000;">0</span>;
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>obj.<span style="color: #006600;">offsetParent</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">while</span> <span style="color: #66cc66;">&#40;</span>obj.<span style="color: #006600;">offsetParent</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
			curleft += obj.<span style="color: #006600;">offsetLeft</span>
			obj = obj.<span style="color: #006600;">offsetParent</span>;
		<span style="color: #66cc66;">&#125;</span>
	<span style="color: #66cc66;">&#125;</span><span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>obj.<span style="color: #006600;">x</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		curleft += obj.<span style="color: #006600;">x</span>;
	<span style="color: #66cc66;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">return</span> curleft;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">function</span> findPosY<span style="color: #66cc66;">&#40;</span>obj<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	<span style="color: #003366; font-weight: bold;">var</span> curtop = <span style="color: #CC0000;">0</span>;
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>obj.<span style="color: #006600;">offsetParent</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">while</span> <span style="color: #66cc66;">&#40;</span>obj.<span style="color: #006600;">offsetParent</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
			curtop += obj.<span style="color: #006600;">offsetTop</span>
			obj = obj.<span style="color: #006600;">offsetParent</span>;
		<span style="color: #66cc66;">&#125;</span>
	<span style="color: #66cc66;">&#125;</span><span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>obj.<span style="color: #006600;">y</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
		curtop += obj.<span style="color: #006600;">y</span>;
	<span style="color: #66cc66;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">return</span> curtop;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #003366; font-weight: bold;">function</span> getMouseXY<span style="color: #66cc66;">&#40;</span>e<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>IE<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
		tempX = event.<span style="color: #006600;">clientX</span> + document.<span style="color: #006600;">body</span>.<span style="color: #006600;">scrollLeft</span>
		tempY = event.<span style="color: #006600;">clientY</span> + document.<span style="color: #006600;">body</span>.<span style="color: #006600;">scrollTop</span>
	<span style="color: #66cc66;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #66cc66;">&#123;</span>
		tempX = e.<span style="color: #006600;">pageX</span>
		tempY = e.<span style="color: #006600;">pageY</span>
	<span style="color: #66cc66;">&#125;</span>
	tempX-=xOffset;
	tempY-=yOffset;
	<span style="color: #003366; font-weight: bold;">var</span> url=<span style="color: #3366CC;">'guardacoordenadas.pl?x='</span>+tempX+<span style="color: #3366CC;">'&amp;y='</span>+tempY;
	guardar<span style="color: #66cc66;">&#40;</span>url<span style="color: #66cc66;">&#41;</span>;
	<span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">true</span>;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #003366; font-weight: bold;">function</span> guardar<span style="color: #66cc66;">&#40;</span>url<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
	<span style="color: #003366; font-weight: bold;">var</span> xmlDoc = <span style="color: #003366; font-weight: bold;">null</span> ;
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">typeof</span> window.<span style="color: #006600;">ActiveXObject</span> != <span style="color: #3366CC;">'undefined'</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
		xmlDoc = <span style="color: #003366; font-weight: bold;">new</span> ActiveXObject<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'Microsoft.XMLHTTP'</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #66cc66;">&#125;</span><span style="color: #000066; font-weight: bold;">else</span> <span style="color: #66cc66;">&#123;</span>
		xmlDoc = <span style="color: #003366; font-weight: bold;">new</span> XMLHttpRequest<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #66cc66;">&#125;</span>
	xmlDoc.<span style="color: #000066;">open</span><span style="color: #66cc66;">&#40;</span> <span style="color: #3366CC;">'GET'</span>, url, <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #66cc66;">&#41;</span>;
	xmlDoc.<span style="color: #006600;">send</span><span style="color: #66cc66;">&#40;</span> <span style="color: #003366; font-weight: bold;">null</span> <span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span></pre>
</div>
</div>
<p>The code adds a onMouseDown handler to the document, executes a function for every click and returns true, since we want the user to follow the normal navigation. Then, when the user clicks any part of the page, a tiny request is going to get sent on the background to our server. The script has to calculate the offsett of the first element inside the &lt;body&gt; tag, because most pages arent aligned to the top-right corner. In <strong>liquid layouts </strong>the system is <strong>not going to work </strong>at all</p>
<p>The request is sent via a HttpRequest object that calls a file in the server. In last version, I used a small GCI written in perl to log the request and return an empty document, but since we want to serve so many request, there&#8217;s a better method to apply. Using a perl CGI, in a modern server, we get the following results benchmarking with apache bench (100 requests, 10 concurrent ones):</p>
<p><code><br />
Concurrency Level:      10<br />
Time taken for tests:   6.537187 seconds<br />
Complete requests:      100<br />
Failed requests:        0<br />
Write errors:           0<br />
Total transferred:      17100 bytes<br />
HTML transferred:       0 bytes<br />
Requests per second:    15.30 [#/sec] (mean)<br />
Time per request:       653.719 [ms] (mean)<br />
Time per request:       65.372 [ms] (mean, across ...)<br />
Transfer rate:          2.45 [Kbytes/sec] received<br />
</code></p>
<h2>Mod_imap</h2>
<p>Apache has some <em>modules</em> that work the following way:<br />
You define a handler and what you want to do with it. Some of them are well known, like mod_perl or mod_cgi, but a lesser known one, called mod_imap, does exactly what we want. It&#8217;s a module meant to return server-side image maps, but if we use an empty map file, all we get is a 204 status (no data) and a logged transaction. The difference is quite significative. Using Apache Bench with the same configuration, this is what we get:</p>
<p><code><br />
Concurrency Level:      10<br />
Time taken for tests:   0.106316 seconds<br />
Complete requests:      100<br />
Failed requests:        0<br />
Write errors:           0<br />
Total transferred:      36464 bytes<br />
HTML transferred:       20246 bytes<br />
Requests per second:    940.59 [#/sec] (mean)<br />
Time per request:       10.632 [ms] (mean)<br />
Time per request:       1.063 [ms] (mean, across ...)<br />
Transfer rate:          329.21 [Kbytes/sec] received<br />
</code></p>
<p>That&#8217;s 950 requests per second vs 15 with the CGI method!!! <strong>We are almost a hundred times faster with this approach!</strong>The only thing we have to do to use this mod_imap is to touch a little bit the apache configuration file. Do it carefully because it can hurt your entire server. In the relevant section add the following lines:</p>
<p><code><br />
AddHandler mod_imap .map<br />
CustomLog /tmp/clicklog clicklog #or modify according to your system<br />
</code></p>
<p>And define a custom log in the same file adding this:<br />
<code><br />
LogFormat "%q,%{Referer}i" clicklog<br />
</code></p>
<p>This way, everything ending in .map is going to be treated as a server-side map, and since the map is empty, it&#8217;s not taking your user anywhere. But it logs it, in file /tmp/clicklog (YMMV). </p>
<h2>The log analysis</h2>
<p>Since we used a logFormat apache directive to write our log, the format should be easy to parse. The query string is written in the log as it comes, and the full lines should be in the following format:</p>
<p><code><br />
?x=483&#038;y=32&#038;dx10&#038;dy15,http://demo.html<br />
?x=461&#038;y=177&#038;dx10&#038;dy15,http://demo.html<br />
?x=408&#038;y=40&#038;dx10&#038;dy15,http://demo.html<br />
(...)<br />
</code></p>
<p>I decided to write a Ruby script to parse the file and generate the final images, because I hadn&#8217;t used ruby before and thought it would be a good way to approach the problem. Last time I had written an structured perl script, but I think that object-oriented is the way to go in this particular situation, since the objects should be well-defined and dividing the program among several coders should be easier too.</p>
<p><em><strong>Update:</strong>Thanks to Jerret, this part has been enhanced using RMagick. Part of the code below can be updated and works some 50 times faster. On top of that, a new sourceforge project has been started at http://sourceforge.net/projects/clickmaps/ under a GPL license. Of course, if you don&#8217;t want to install/use RMagick you can still download the original version at the end of this post.</em></p>
<p>I´ll try to explain the model. It uses five classes:</p>
<dl>
<dt>Conf: </dt>
<dd>Sets some configuration variables and returns them as a hash. This way, every configuration variable is set in this class and it&#8217;s easy to get them later on</dd>
</dl>
<div class="foldingcode"><a href="javascript:showme('3730_2');"> Code: <b>conf.rb</b></a><br />
<div style="display: none; background:white;" id=3730_2>
<pre class="ruby"><span style="color:#9966CC; font-weight:bold;">class</span> Conf
	<span style="color:#9966CC; font-weight:bold;">def</span> initialize
	@data = <span style="color:#006600; font-weight:bold;">&#123;</span>
		'logfile' =&gt; 'log.<span style="color:#9900CC;">txt</span>',
		'dotimage' =&gt; 'bolilla.<span style="color:#9900CC;">png</span>',
		'<span style="color:#CC0066; font-weight:bold;">format</span>' =&gt; 'png',
		'colorimage' =&gt; 'colors.<span style="color:#9900CC;">png</span>',
		'opacity' =&gt; <span style="color:#996600;">"0.50"</span>,
		'dotwidth' =&gt; <span style="color:#006666;">64</span>
	<span style="color:#006600; font-weight:bold;">&#125;</span>
	<span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">"log file not found"</span> \
	<span style="color:#9966CC; font-weight:bold;">unless</span> File.<span style="color:#9900CC;">exist</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>@data<span style="color:#006600; font-weight:bold;">&#91;</span>'logfile'<span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
	<span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">"dot image not found"</span> \
	<span style="color:#9966CC; font-weight:bold;">unless</span> File.<span style="color:#9900CC;">exist</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>@data<span style="color:#006600; font-weight:bold;">&#91;</span>'dotimage'<span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
	<span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">"color image not found"</span> \
	<span style="color:#9966CC; font-weight:bold;">unless</span> File.<span style="color:#9900CC;">exist</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>@data<span style="color:#006600; font-weight:bold;">&#91;</span>'colorimage'<span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
	<span style="color:#9966CC; font-weight:bold;">end</span>
	attr_reader :data
<span style="color:#9966CC; font-weight:bold;">end</span></pre>
</div>
</div>
<dl>
<dt>Readparsefile</dt>
<dd>Reads and parses the file defined as logfile in the conf object. For each log line, it stores it into a click object and append it to an array. There are two methods that return all the URLs in the log file (geturls) and all the information for a single URL as a Log object</dd>
</dl>
<div class="foldingcode"><a href="javascript:showme('3730_3');"> Code: <b>readparsefile.rb</b></a><br />
<div style="display: none; background:white;" id=3730_3>
<pre class="ruby"><span style="color:#9966CC; font-weight:bold;">class</span> Readparsefile
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>name<span style="color:#006600; font-weight:bold;">&#41;</span>
    @name = name
    @data = <span style="color:#CC0066; font-weight:bold;">Array</span>.<span style="color:#9900CC;">new</span>
    lines = IO.<span style="color:#CC0066; font-weight:bold;">readlines</span><span style="color:#006600; font-weight:bold;">&#40;</span>@name<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">collect</span> <span style="color:#006600; font-weight:bold;">&#123;</span> |l| l.<span style="color:#CC0066; font-weight:bold;">chomp</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
    <span style="color:#9966CC; font-weight:bold;">for</span> line <span style="color:#9966CC; font-weight:bold;">in</span> lines
        line.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>/\?x\=/,''<span style="color:#006600; font-weight:bold;">&#41;</span>
        line.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>/\&amp;y\=/,','<span style="color:#006600; font-weight:bold;">&#41;</span>
        line.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>/\//,'_'<span style="color:#006600; font-weight:bold;">&#41;</span>
        x,y,url = line.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span>/,/<span style="color:#006600; font-weight:bold;">&#41;</span>
        <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#006600; font-weight:bold;">&#40;</span>x <span style="color:#9966CC; font-weight:bold;">and</span> y <span style="color:#9966CC; font-weight:bold;">and</span> url<span style="color:#006600; font-weight:bold;">&#41;</span>
            @data.<span style="color:#9900CC;">push</span><span style="color:#006600; font-weight:bold;">&#40;</span>Click.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>url, x, y<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
        <span style="color:#9966CC; font-weight:bold;">else</span>
            $stderr.<span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">"Warning: Bogus line "</span>&lt;&lt; line
        <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    @urls = <span style="color:#CC0066; font-weight:bold;">Array</span>.<span style="color:#9900CC;">new</span>
    @data.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |line|
        @urls.<span style="color:#9900CC;">push</span><span style="color:#006600; font-weight:bold;">&#40;</span>line.<span style="color:#9900CC;">url</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">"no clicks found"</span> <span style="color:#9966CC; font-weight:bold;">unless</span> lines.<span style="color:#9900CC;">length</span> &gt; <span style="color:#006666;">0</span>
    @urls.<span style="color:#9900CC;">uniq</span>!
  <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> geturls
      <span style="color:#0000FF; font-weight:bold;">return</span> @urls
  <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> coordsurl<span style="color:#006600; font-weight:bold;">&#40;</span>url<span style="color:#006600; font-weight:bold;">&#41;</span>
    @url=url
    xMax=<span style="color:#006666;">0</span>
    yMax=<span style="color:#006666;">0</span>
    coords = <span style="color:#CC0066; font-weight:bold;">Array</span>.<span style="color:#9900CC;">new</span>
    @data.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |line|
        coords.<span style="color:#9900CC;">push</span><span style="color:#006600; font-weight:bold;">&#40;</span>line<span style="color:#006600; font-weight:bold;">&#41;</span>
        xMax=line.<span style="color:#9900CC;">x</span> <span style="color:#9966CC; font-weight:bold;">if</span> line.<span style="color:#9900CC;">x</span>&gt;xMax
        yMax=line.<span style="color:#9900CC;">y</span> <span style="color:#9966CC; font-weight:bold;">if</span> line.<span style="color:#9900CC;">y</span>&gt;yMax
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#0000FF; font-weight:bold;">return</span> Log.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>xMax,yMax,coords,@url<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre>
</div>
</div>
<dl>
<dt>Click</dt>
<dd>
Stores the data in each log line, including X, Y and URL. Provides a method (xy) that returns an string like &#8220;x100y200&#8243; to compare the exact coordinates, useful to extract the maximum number of times a single click is repeated
</dd>
</dl>
<div class="foldingcode"><a href="javascript:showme('3730_4');"> Code: <b>click.rb</b></a><br />
<div style="display: none; background:white;" id=3730_4>
<pre class="ruby"><span style="color:#9966CC; font-weight:bold;">class</span> Click
    <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>url,x,y<span style="color:#006600; font-weight:bold;">&#41;</span>
        @url=url
        @x=x
        @y=y
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> url
        <span style="color:#0000FF; font-weight:bold;">return</span> @url
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> x
        <span style="color:#0000FF; font-weight:bold;">return</span> @x.<span style="color:#9900CC;">to_i</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> y
        <span style="color:#0000FF; font-weight:bold;">return</span> @y.<span style="color:#9900CC;">to_i</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> xy
        <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#996600;">"x"</span>+@x+<span style="color:#996600;">"y"</span>+@y
    <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre>
</div>
</div>
<dl>
<dt>Log</dt>
<dd>
Stores all the values pertinent to a single URL and gives accesors to them. There&#8217;s also a &#8220;next&#8221; method that returns next click within the same URL
</dd>
</dl>
<div class="foldingcode"><a href="javascript:showme('3730_5');"> Code: <b>log.rb</b></a><br />
<div style="display: none; background:white;" id=3730_5>
<pre class="ruby"><span style="color:#9966CC; font-weight:bold;">class</span> Log
    <span style="color:#9966CC; font-weight:bold;">def</span> initialize <span style="color:#006600; font-weight:bold;">&#40;</span>x,y,list,url<span style="color:#006600; font-weight:bold;">&#41;</span>
        @line = <span style="color:#006666;">0</span>
        @x=x
        @y=y
        @url=url
        @list=list
        @points = Hash.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#41;</span>
        @list.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |point|
            @points<span style="color:#006600; font-weight:bold;">&#91;</span>point.<span style="color:#9900CC;">xy</span><span style="color:#006600; font-weight:bold;">&#93;</span> +=<span style="color:#006666;">1</span>
        <span style="color:#9966CC; font-weight:bold;">end</span>
        @reps = @points.<span style="color:#9900CC;">values</span>.<span style="color:#9900CC;">max</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    attr_reader :x, :y, :list, :reps, :url
    <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#9966CC; font-weight:bold;">next</span>
        coord = @list<span style="color:#006600; font-weight:bold;">&#91;</span>@line<span style="color:#006600; font-weight:bold;">&#93;</span>
        @line += <span style="color:#006666;">1</span>
        <span style="color:#0000FF; font-weight:bold;">return</span> coord
    <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre>
</div>
</div>
<dl>
<dt>Image</dt>
<dd>Receives a log object and the conf object. There are three methods to normalize the spot we&#8217;re going to use as a click indicator (normalizespot), compose every click as a dot (iterate) and colorize the final image (colorize)</dd>
</dl>
<div class="foldingcode"><a href="javascript:showme('3730_6');"> Code: <b>image.rb</b></a><br />
<div style="display: none; background:white;" id=3730_6>
<pre class="ruby"><span style="color:#9966CC; font-weight:bold;">class</span> Image
    <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>data,conf<span style="color:#006600; font-weight:bold;">&#41;</span>
        @data = data
        @name = data.<span style="color:#9900CC;">url</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>/\W/,''<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>/\_/,''<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span>
        @conf=conf.<span style="color:#9900CC;">data</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> normalizespot
        <span style="color:#008000; font-style:italic;">#divide spot.png intensity by max. position reps (@data.reps)</span>
        intensity = <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">100</span>-<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">100</span>/@data.<span style="color:#9900CC;">reps</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">ceil</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span>
        normalize = <span style="color:#996600;">"convert "</span>&lt;&lt;@conf<span style="color:#006600; font-weight:bold;">&#91;</span>'dotimage'<span style="color:#006600; font-weight:bold;">&#93;</span>&lt;&lt;<span style="color:#996600;">" -fill white -colorize "</span>&lt;&lt;intensity&lt;&lt;<span style="color:#996600;">"% "</span>&lt;&lt;@name&lt;&lt;<span style="color:#996600;">".bol.png"</span>
        <span style="color:#CC0066; font-weight:bold;">system</span><span style="color:#006600; font-weight:bold;">&#40;</span>normalize<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> iterate
        halfwidth=@conf<span style="color:#006600; font-weight:bold;">&#91;</span>'dotwidth'<span style="color:#006600; font-weight:bold;">&#93;</span>/<span style="color:#006666;">2</span>
        compose = <span style="color:#996600;">"convert -page "</span>&lt;&lt;<span style="color:#006600; font-weight:bold;">&#40;</span>@data.<span style="color:#9900CC;">x</span>+halfwidth<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span>&lt;&lt;<span style="color:#996600;">"x"</span>&lt;&lt;<span style="color:#006600; font-weight:bold;">&#40;</span>@data.<span style="color:#9900CC;">y</span>+halfwidth<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span>&lt;&lt;<span style="color:#996600;">" pattern:gray100 "</span>
        <span style="color:#008000; font-style:italic;">#iterate spots</span>
        @data.<span style="color:#9900CC;">list</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |dot|
            compose &lt;&lt; <span style="color:#996600;">"-page +"</span>&lt;&lt;<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span>dot.<span style="color:#9900CC;">x</span><span style="color:#006600; font-weight:bold;">&#41;</span>-halfwidth<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span>&lt;&lt;<span style="color:#996600;">"+"</span>&lt;&lt;<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span>dot.<span style="color:#9900CC;">y</span><span style="color:#006600; font-weight:bold;">&#41;</span>-halfwidth<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span>&lt;&lt;<span style="color:#996600;">" "</span>&lt;&lt;@name&lt;&lt;<span style="color:#996600;">".bol.png "</span>
        <span style="color:#9966CC; font-weight:bold;">end</span>
        compose &lt;&lt; <span style="color:#996600;">"-background white -compose multiply -flatten "</span>&lt;&lt;@name&lt;&lt;<span style="color:#996600;">".empty.png"</span>
        <span style="color:#CC0066; font-weight:bold;">system</span><span style="color:#006600; font-weight:bold;">&#40;</span>compose<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> colorize
        <span style="color:#008000; font-style:italic;">#invert image...</span>
        invert = <span style="color:#996600;">"convert "</span>&lt;&lt;@name&lt;&lt;<span style="color:#996600;">".empty.png -negate "</span>&lt;&lt;@name&lt;&lt;<span style="color:#996600;">".full.png"</span>
        <span style="color:#CC0066; font-weight:bold;">system</span><span style="color:#006600; font-weight:bold;">&#40;</span>invert<span style="color:#006600; font-weight:bold;">&#41;</span>
        <span style="color:#008000; font-style:italic;">#colorize it...</span>
        colorize = <span style="color:#996600;">"convert "</span>&lt;&lt;@name&lt;&lt;'.<span style="color:#9900CC;">full</span>.<span style="color:#9900CC;">png</span> -type TruecolorMatte '&lt;&lt;@conf<span style="color:#006600; font-weight:bold;">&#91;</span>'colorimage'<span style="color:#006600; font-weight:bold;">&#93;</span>&lt;&lt;' -fx <span style="color:#996600;">"v.p{0,u*v.h}"</span> '&lt;&lt;@name&lt;&lt;<span style="color:#996600;">".colorized.png"</span>
        <span style="color:#CC0066; font-weight:bold;">system</span><span style="color:#006600; font-weight:bold;">&#40;</span>colorize<span style="color:#006600; font-weight:bold;">&#41;</span>
        <span style="color:#008000; font-style:italic;">#and apply transparency...</span>
        transparency = <span style="color:#996600;">"convert "</span>&lt;&lt;@name&lt;&lt;'.<span style="color:#9900CC;">colorized</span>.<span style="color:#9900CC;">png</span> -channel A -fx <span style="color:#996600;">"A*'&lt;&lt;@conf['opacity']&lt;&lt;'"</span>  '&lt;&lt;@name&lt;&lt;'.<span style="color:#9900CC;">final</span>.'&lt;&lt;@conf<span style="color:#006600; font-weight:bold;">&#91;</span>'<span style="color:#CC0066; font-weight:bold;">format</span>'<span style="color:#006600; font-weight:bold;">&#93;</span>
        <span style="color:#CC0066; font-weight:bold;">system</span><span style="color:#006600; font-weight:bold;">&#40;</span>transparency<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre>
</div>
</div>
<p>Then, the main program is only eight lines long. It leverages the objects&#8217; methods to be as compact as possible. In fact, the only thing it does is to iterate over each url to create a different image.<br />
<code>
<pre>
conf = Conf.new
file = Readparsefile.new(conf.data['logfile'])
file.geturls.each do |url|
    image = Image.new(file.coordsurl(url),conf)
    image.normalizespot
    image.iterate
    image.colorize
end</pre>
<p></code></p>
<h2>Is it better?</h2>
<p>You can find another program (this time written in perl) in an older post that does a similar job of making heatmaps. But there has been some modifications that makes this an usable system instead of a proof of concept:</p>
<dl>
<dt>Flexible configuration</dt>
<dd>Over the harcoded last version, in this one is quite simple to modify the images used in the heatmap generation, or the log name. <b>You only have to modify the Conf definition</b>. It would be so easy to use an external conf file, but doing it this way is quicker for me</dd>
<dt>Multiple URL support</dt>
<dd>While last version only let you extract one image, this one <b>makes a heatmap for every URL in your log</b>. </dd>
<dt>Much faster execution time</dt>
<dd>Instead of composing the full image everytime, now we create a single ImageMagick sentence to do al the composition for us. That gives us a couple of orders speed advantage. <b>Last version lasted about fifteen minutes for a couple hundred clicks, and now it&#8217;s about five seconds</b>. Please note that, for many clicks, the program uses quite a bit of memory. Probably for a production environment it would be neccesary to divide the <i>compose</i> sentence into manageable chuncks, and iterate at the end with them to create the final heatmap.</dd>
<dt>Manual capture is not needed anymore</dt>
<dd>Since the last step is to decrement the opacity of the map, we can use a little bit of javascript to overlay the PNG image over the original page. So, the stakeholders can review it without someone manually capturing the screen. This way we don&#8217;t need to set an XServer in the production environment</dd>
<dt>Easier to maintain and extend</dt>
<dd>The object oriented paradigm doesn&#8217;t give us faster code, but much more manageable one. You can extend it as you want</dd>
</dl>
<h2>What you get</h2>
<p>Now, you&#8217;ll have several images. Most of them are OK to delete, but there&#8217;s one ending in final.png that&#8217;s your heatmap. We&#8217;re going to overlay it on top of your web page. That image should be a semi-transparent PNG like this one:</p>
<p><img src="/uploads/final2_p.png"></p>
<h2>The overlay</h2>
<p>This is the final part of the proccess. We already have the overlay image and all we need is a <strong>javascript snippet </strong>that can be called anytime and that creates a layer on top of your website with the click information. Just like the first step, we&#8217;re going to position it over the very first item in the page.<br />
The best way to do that is via a <em><strong>bookmarklet</strong></em>, that is, an small javascript snippet saved as a bookmark. This way, you can have it in your browser and ask for the overlay image when you feel like. The javascript recalculates the offsets of the first element inside the &lt;body&gt; tag and writes the heatmap image on top of it.</p>
<div class="foldingcode"><a href="javascript:showme('3730_7');"> Code: <b>overlay.js</b></a><br />
<div style="display: none; background:white;" id=3730_7>
<pre class="javascript"><span style="color: #009900; font-style: italic;">/**
 * @author DavidPardo
 */</span>
<span style="color: #009900; font-style: italic;">//find the position of the first item on screen and store offsets</span>
<span style="color: #009900; font-style: italic;">//find the first item on screen (after body)</span>
<span style="color: #003366; font-weight: bold;">var</span> firstElement=document.<span style="color: #006600;">getElementsByTagName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">childNodes</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #66cc66;">&#93;</span>;
<span style="color: #009900; font-style: italic;">//find the offset coordinates</span>
xOffset=findPosX<span style="color: #66cc66;">&#40;</span>firstElement<span style="color: #66cc66;">&#41;</span>;
yOffset=findPosY<span style="color: #66cc66;">&#40;</span>firstElement<span style="color: #66cc66;">&#41;</span>;
<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>IE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span> <span style="color: #009900; font-style: italic;">// In IE there's a default margin in the page body. If margin's not defined, use defaults</span>
	<span style="color: #003366; font-weight: bold;">var</span> marginLeftExplorer  = parseInt<span style="color: #66cc66;">&#40;</span>document.<span style="color: #006600;">getElementsByTagName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">marginLeft</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #003366; font-weight: bold;">var</span> marginTopExplorer   = parseInt<span style="color: #66cc66;">&#40;</span>document.<span style="color: #006600;">getElementsByTagName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #66cc66;">&#93;</span>.<span style="color: #006600;">style</span>.<span style="color: #006600;">marginTop</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #009900; font-style: italic;">/*assume default 10px/15px margin in explorer*/</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>isNaN<span style="color: #66cc66;">&#40;</span>marginLeftExplorer<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>marginLeftExplorer=<span style="color: #CC0000;">10</span>;<span style="color: #66cc66;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span>isNaN<span style="color: #66cc66;">&#40;</span>marginTopExplorer<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>marginTopExplorer=<span style="color: #CC0000;">15</span>;<span style="color: #66cc66;">&#125;</span>
	xOffset=xOffset+marginLeftExplorer;
	yOffset=yOffset+marginTopExplorer;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #009900; font-style: italic;">// add the image element to the dom, absolutely positioned</span>
<span style="color: 