Extreme CSS typography

Extreme CSS typography can be a real fun. To achieve our goals, we start with a basic markup like this:

<div id="branding">
    <h1>CSS</h1>
    
    <p id="strapline">A world of style</p>
</div>

Then we can specify enormous font sizes, like so:

#branding {
    width: 100%;
    background: #224185 url(img/brand.jpg) no-repeat top right;
}

#branding h1 {
    font: 17em Impact, sans-serif;
    color: #fff;
    margin: 0;
    padding: 20px 460px 20px 20px;
}


#strapline {
    margin: 0;
    padding: 20px;
    color: #224185;
    font: 6em Georgia, serif;
    background: #fff;
    text-align: center;
}

As you can see, we've used 17em and 6em, respectively. You can find the final result here.

Creating an Excel file with PHP: tips

Creating an Excel file with PHP is not so simple as many online tutorials claim it is, because it requires a certain basic knowledge of how an Excel file is structured. First of all, an Excel file is an XML file. This implies that all the parsing rules of XML apply to this kind of files. In fact, an Excel file must be:

  • well-formed and
  • with all the XML entities properly encoded

Some tutorials propose to serve Excel files as text/xml in order to benefit of the native support of Internet Explorer to these files. If you serve an Excel file as an XML file (of course we're talking about its content type), IE will automatically open it as the user were viewing the document in Excel. That's fine. However, you must be aware that Excel validates internally its files, so you should create a file that honor its rules. For example, data types inside Cell elements must be in the correct format (Number, String etc.). Excel is really strict with data types. Another thing to bear in mind is the number of columns and rows in a Table element: they must match the number of column and rows you're generating from your database.

Another ugly thing is encoding. As said above, all XML entities must be encoded and, what's more, correctly expanded. Generally, UTF-8 is the best choice, provided that:

  • database data is in the correct encoding
  • your PHP files are encoded in UTF-8 (without BOM)

Before creating an Excel file, you should make sure that all data in your database is properly encoded. If this is not the case, you must perform a conversion /filtering with PHP, using all entities-related functions (such as iconv() and utf8-encode()) provided by PHP. If you don't take all these details into account, you'll probably bang your head on the desk watching Excel generating an infinite sequence of error logs.

Facebook: the client-side code is a mess

Facebook logoNo kidding. If you take a look at the source code of any Facebook page (for example, your home page), you will see something quite shocking: the 80%-90% of the page is made up by JavaScript code! That's why Facebook doesn't work with assistive technologies: there's very few actual content to parse and render in such pages. Facebook seems to embrace the what-you-see-is-what-you-get philosophy or, as they put it, we're not cool enough to support your browser (said to a Lynx user). Fine. So they don't care if many users can't access their web application. But there's another thing that needs to be emphasized: by relying so heavily on JavaScript and Ajax, Facebook delivers a consistent parsing and rendering load to web browsers. Sure, JavaScript engines evolve, but what about backward compatibility? There should be a certain balance between effective content and JavaScript-generated content. Facebook is completely unbalanced. And yes, this is a mess. No kidding.

Chrome: calm like a bomb

ChromeGoogle Chrome has raised exponentially in the browser market during the last two years. Now its share is approximately 15% or 25%, depending on the site. Surely Chrome is gaining its momentum, but I think that it didn't express its full potential yet. What we got so far? A full standard compliant browser, really fast in loading pages and executing complex JavaScript scripts (a must for most RIAs). Is it enough? Certainly not! There are other possible scenarios for Chrome, which include:

  • full integration with Google web services, such as Gmail and Google Maps; in other words, more like a suite than a simple browser (see Seamonkey)
  • new features added with extensions
  • full support to HTML5
  • improved performance

Is it enough? I guess so! But the most exciting things are yet to come (Geolocations API, Microformats, just to name few). Time will tell if Chrome will get on the top of the browser market or be just another fad.

Parsing a Flickr feed with SimpleXML

Parsing a Flickr RSS feed requires some preparatory steps. First of all, I tried to download a static copy of my feeds using wget just to study the file structure. Wrong choice! In fact, the format returned was Atom, not RSS. So I used the following approach:

$file = file_get_contents('http://api.flickr.com/services/feeds/photos_public.gne?id=31968388@N02&lang=it-it&format=rss_200');
echo $file;

So I got the correct format. Parsing the feed is quite a simple task:

$rss = simplexml_load_file('http://api.flickr.com/services/feeds/photos_public.gne?id=31968388@N02&lang=it-it&format=rss_200');
    
    foreach($rss->channel->item as $entry) {
    
    
    
        $title = $entry->title;
        $raw_published = $entry->pubDate;
        $published = str_replace('-0700', '', $raw_published);
        $raw_content = $entry->description;
        $content = html_entity_decode($raw_content, UTF-8);
        
        
        echo '<li>' . "\n" . '<h2>' . $title . '</h2>' . "\n" . '<p class="pubdate">' . $published . "</p>\n" . 
        $content . "</li>\n";
    
    
    
    
    }

Two notes here:

  1. you need to start parsing from the root element, not from the SimpleXMLObject itself
  2. the description element contains markup that needs to be expanded using the html_entity_decode() function

You can see this test here.

Test on CSS3 box-shadow and border-radius

I've just finished to upload a new test which combines the CSS3 box-shadow and border-radius properties. The code is as follows:

 div.pic {
    
        width: 260px;
        height: 200px;
        background: maroon;
        position: relative;
        border-radius: 8px;
        -moz-border-radius: 8px;
        box-shadow: #666 5px 5px 5px;
        -moz-box-shadow: #666 5px 5px 5px;
        -webkit-box-shadow: #666 5px 5px 5px;
        margin: 0 auto;
}

You can see this test here.

JavaScript polymorphism

In JavaScript, but also in other languages, polymorphism is the ability of a method to perform different tasks. To implement polymorphism through JavaScript objects (also called classes, though JavaScript is a class-free language), we have to grasp how the prototype property works. The first problem with this approach is related to the fact that a method of a child class with the same name of an existing one of the parent class is overridden in the child class. Also, this affects even the original method of the parent class. To circumvent this problem, we have to write something like this:

function Message(subject) {

    this.subject = subject;
    this.send = function() {
    
      alert('Message sent!');
    
    }

}


function SMS (){};


SMS.prototype = new Message('Test');
SMS.prototype.constructor = SMS;

SMS.prototype.send = function() {


  alert('SMS sent!');

}

Here the send() method of the Message class will alert 'Message sent!', while the same method on the SMS class (which extends its base class) will alert 'SMS sent'. This happens because we've specified as constructor the SMS class instead of simply augmenting the prototype property. So far so good. Now we want something more, say, like modifying the action of the child method. Here's how it can be done:

function Email(to) {

    this.to = to;

}


Email.prototype.send = function() {

    alert('Email sent');

}


function HTMLEmail () {};

HTMLEmail.prototype = new Email('test@localhost');
HTMLEmail.constructor.prototype = HTMLEmail;

HTMLEmail.prototype.send = function() {

    alert('[Content-Type: text/html] ');
    
    this.constructor.prototype.send.call(this); // this.constructor.prototype points to Email
    


}

Here there have been some slight changes: we don't modify directly the prototype property of the derived class, but its constructor's prototype. We use the call function that invokes the send() method of the parent class. In fact, in this case the this keyword points to the parent class. In this way, you can actually have a method that performs two different tasks, thus improving the overall efficiency of your code. You can see these tests here.

CSS tables performance

Tables can be a real bottleneck in the overall page loading because browsers parse and render them in a peculiar way. When a table has an automatic width (table-layout: auto), browsers must perform a different calculation on each row and cell to determine what is the actual width of the table itself. Since the overall width of a table is given by the sum of the widths of its cells, it's safe to say that with an automatic table layout browsers don't know in advance how to calculate these widths.

Instead, with a fixed table layout (table-layout: fixed) such calculations are much faster, because the fixed table layout algorithm has the obvious advantage of being clearly defined in the CSS specifications, while the automatic layout mostly relies on browser's internal algorithms.

In short, use this:

table {
  table-layout: fixed;
}

It's not necessary to specify a width for the table cells. The important thing here is that you're actually forcing the browser to use a fixed table algorithm.

jQuery basic dynamic menu

We have a basic navigation menu that we want to make dynamic by using jQuery. The markup is as follows:

<ul id="navigation">

<li class="more"><a href="#">About</a>

<ul>

<li><a href="#">About me</a></li>
<li><a href="#">Resumé</a></li>
<li><a href="#">Portfolio</a></li>

</ul>

</li>

<li><a href="#">Home</a></li>
<li><a href="#">Articles</a></li>
<li><a href="#">Contact</a></li>


</ul>

The first item, as you can see, contains a submenu. The relevant CSS styles are the following:

/* @group Page elements */
 
 body {
 
     margin: 0;
     padding: 0;
     background: #fff;
     color: #333;
     font: 62.5% Arial, sans-serif;
 
 
 }
 
 #site {
 
     width: 100%;
     font-size: 1.4em;
 
 }
 
 #navigation {
 
     height: 7em;
     overflow: hidden;
     margin: 0;
     padding: 0 0.5em;
     background: #338 url(img/top_nav_bg.jpg) repeat-x 0 0;
     list-style: none;
 
 
 }
 
 #navigation li {
 
      float: left;
      height: 100%;
      margin-right: 0.5em;
 
 }
 
 
 #navigation li a {
 
     float: left;
     display: block;
     padding: 0 1em;
     height: 100%;
     line-height: 7;
     color: #fff;
     text-decoration: none;
     font-weight: bold;
     text-transform: uppercase;
 
 
 }
 
 #navigation li a:hover {
 
 
     background: transparent url(img/top_nav_ov.jpg) no-repeat 0 0;
 
 
 }
 
 #content {
 
     width: 90%;
     margin: 0 auto;
     padding: 1em 0;
 
 
 }
 
 #content h2 {
 
     margin-top: 0;
     font: normal 1.6em Georgia, serif;
     color: #900;
 
 }
 
 /* @end */
 
 
 /* @group JQuery styles */
 
 span.plus, span.minus {
 
     padding-left: 4px;
 
 }
 
 
 li.more ul {
 
     margin: 0;
     padding: 0;
     height: 100%;
     list-style: none;
     float: left;
 
 
 }
 
 li.more ul li {
 
     height: 100%;
     display: block;
     margin-right: 0.4em;
     float: left;
 
 }
 
 
 #navigation li.more ul li a {
 
     display: block;
     float: left;
     height: 100%;
     background: transparent;
     line-height: 7;
     padding: 0 1em;
     color: #fff;
     text-transform: none;
 
 
 }
 
 #navigation li.more ul li a:hover {
 
      text-decoration: underline;
 
 
 }

Two groups of styles: the former for page elements and the latter for our submenu. Now let's add jQuery.

$(document).ready(function() {

    $('<span class="plus"></span>').html('+').appendTo('li.more > a:first-child');
    $('<span class="minus"></span>').html('-').appendTo('li.more > a:first-child').hide();
    $('li.more ul').hide();
    
    $('li.more > a:first-child > span.plus').click(function () {
    
        var parent = $(this).parent().parent();
        
        
        parent.find('ul').show();
        $(this).hide();
        $(this).next().show();    
    
    });
    
     $('li.more > a:first-child > span.minus').click(function () {
    
        var parent = $(this).parent().parent();
        
        
        parent.find('ul').hide();
        $(this).hide();
        parent.find('span.plus').show();    
    
    });

    
    


});

First, we add a plus and a minus sign to our active menu item and we hide one of them according to the current state of the submenu (either visible or not). Then when an user clicks on the plus sign, we show the submenu and we change the plus sign into a minus sign (and vice-versa). You can see the final result here.

Understanding Ajax

People don't understand how Ajax works. Generally, they think that Ajax has finally fixed the problem of the World Wide Wait scenario. Wrong! Totally wrong! Because either you post something or you get something through Ajax, you have to wait until your request has been processed by the server if you want to get a response. For example, when you click on a "Like" link on Facebook, your GET request is passed to a PHP script that:

  1. extracts all URL parameters
  2. processes those parameters
  3. returns a response that JavaScript can handle

So if the server is busy, you have to wait. You've probably noticed that sometimes your browser hangs on Facebook. That's exactly what I mean: you have to wait until the server has freed some of its resources to complete your request processing. This is something that you cannot fix with some Ajax/JavaScript workarounds : you have to work on the server-side aspect of the problem. I hope that people will bear this in mind while developing their RIA (Rich Internet Applications) with Ajax.

jQuery sliding content

Making content slide with jQuery requires some workaround if we want this happen by using a controller with links. We start with a basic markup like this:

<div id="extra">

  <div class="extra-box"></div>
  
  <!-- more extra boxes -->
  
  <div id="controller">
  
  <!-- pagination links here -->
  
  </div>

</div>

In this demo we're using real links for the sake of accessibility (generating links can be actually troublesome for browsers that don't support JavaScript). When an user clicks on a link, only the content related to that link will be showed. Here's the jQuery code:

$(document).ready(function() {

   $('div.extra-box').eq(0).nextAll().not('#controller').hide();
   
   var index = 0;
   var $id = 'box';
   var indexes = [];
   
   $('div.extra-box').each(function() {
   
       index++;
       
       $(this).attr('id', $id + index);
       
       indexes.push($(this).attr('id'));
   
   });
   
   
   for(var i=0; i<indexes.length; i++) {
   
   
       var $href = indexes[i];
       
       $('#controller a').eq(i).attr('name', $href); 
         
   
   }
   
   
   
   
   $('#controller a').each(function() {
   
        
        var $a = $(this);
        var $name = $a.attr('name');
        
        $('div.extra-box').each(function() {
           
               var $box = $(this);
               
               if($box.attr('id') == $name) {
               
                   if($box.is(':visible')) {
                   
                       $box.hide();
                   
                   }
               
               
               }           
           
       });

        
        $a.click(function() {
        
            $('div.extra-box').each(function() {
                        
            
               var $box = $(this);
               
               if($box.attr('id') == $name) {
               
                   if($box.is(':hidden')) {
                   
                   
                       $box.slideDown();
                       
                       $('#extra div.extra-box').not($box).slideUp();
                       
                                     
                   
                   }          
               
               }
            
            
            
            });
            
                   
        
        });
        
                 
   
   });
});

First, all boxes are hidden. Then we generate an ID for each box and a name attribute for the controller links using the same value of the IDs. Then, when an user clicks on a link, only the related box will be shown, while the others will be hidden. To achieve the sliding effect, we use the slideUp() and slideDown() methods. You can see the final result here.

Limiting results with PHP SimpleXML

While parsing an RSS feed with SimpleXML, is certainly useful to limit the number of items fetched with the simplexml_load_file() method. Suppose that we want to parse a Twitter feed and we want only the first five items. We could write the following:

  $rss = simplexml_load_file('http://twitter.com/statuses/user_timeline/120345723.rss');
  
  $items = $rss->channel->item;
  $i = -1;
  
  do {
      
    $i++;
    
       $raw_title = $items[$i]->title;
        $title = str_replace('gabromanato:', '', $raw_title);
        $title = preg_replace('/http.+/', '', $title);
        
        $raw_date = $items[$i]->pubDate;
        $date = str_replace('+0000', '', $raw_date);
        
        $link = $items[$i]->link;
        
         echo '<li><a href="' . $link . '">' . $title . '</a>' . "\n" . '<div class="pubdate">' . $date . '</div>' . "\n" . "</li>\n";                               
      
      
  } while($i < 5);

We're actually using a do.. while loop here. Every time we increment our internal counter, we move to the next item in the array. Since the returned array starts from 0, we set our counter to -1 to start from the very first item. You can see a test here.

Using jQuery's fn prototype

The jQuery's fn object member is actually an alias for the prototype property of jQuery itself. By means of this object, you can extend jQuery by adding new methods to the jQuery's chain. For example:

jQuery.fn.insert = function(element, content, attribute, value) {

    element = element || '<div></div>';
    
    content = content || 'Test';
    
    attribute = attribute || 'class';
    
    value = value || 'test';
    
    return $(element).appendTo(this).html(content).attr(attribute, value);
}


$(document).ready(function() {

     
      $('body').insert();
      
      

});

The problem with jQuery's prototype is that it's not extensible from other classes except from jQuery itself. In other words, the link to the prototype property works as expected, but your new class cannot use the core jQuery's methods. You can see the test of the above example here.

jQuery's extend() method: simple test

The extend() method of jQuery can be used to extend an object with another object, thus resulting in a new object that inherits all the properties and methods from the existing objects. For example:

var A = new function() {
    
        this.foo = 'Foo';
        this.getFoo = function() {
        
            
            return this.foo;
        
        };
    
    };
    
    var B = new function() {
    
    
        this.url = location.href;
        this.getURL = function() {
        
           return this.url;
        
        };
    
    
    };
    
    
    var AB = $.extend(A, B);

We can check whether the resulting object has correctly inherited all the properties and methods by simply writing:

 $('<p></p>').html(AB.getFoo()).insertAfter('#class-ab');

You can see this test here.

Ajax form with jQuery

Building an Ajax form with jQuery requires two components:

  1. a server side script to process data
  2. the ajax() object of jQuery

Suppose that you want a search form to get some definitions of web standards. The server-side script is as follows:

<?php

header('Content-Type: text/plain');

$q = $_GET['q'];
$response = '';

if(preg_match('/^\s+$/', $q) || empty($q)) {
    $response = '<p class="error">You must provide a search term.</p>';
    echo $response;
} else {

   $term = strtoupper($q);
   $definitions = array(
                  'CSS' => 'A stylesheet language.',
    'DOM' => 'An interface to manipulate web documents.',
    'XML' => 'An extensible markup language.'
    );
   
   foreach($definitions as $definition => $value) {
   
       if($definition == $term) {
       
           $response = '<div class="success"><h2>' . $definition . '</h2><p>' . $value . '</p></div>';
    
    break;
       
       } else {
       
       
           $response = '<p class="error">No term found.</p>';
    
    break;
       
       
       }
   
   
   }
   
   
   echo $response;
   
   
    
   


}
?>

Note that we're serving our response in plain text, because it's faster. Also note that we're simply using an associative array to mimic the behavior of a database. The jQuery code is really simple:

 $(document).ready(function() {
    
    
        $('#test').submit(function() {
 
 if($('p.error').size()) {
 
     $('p.error').remove();
     
 }
 
 var query = $('#q').val();
 var data = 'q=' + query;
 $.ajax({
 
     type: 'GET',
     url: 'process.php',
     data: data,
     success: function(html) {
     
        $('<div></div>').html(html).insertAfter('#test');
     
     
     }
 
 
 });
 
 return false;
 
        });
    
    
    });

First of all, you need to clean all the previous Ajax messages inserted after a form submission. Then you build up your query string and pass it to the ajax() object, also specifying the type of your request, the URL of the server-side script and the data passed with your query (in this case, it's a GET query). If the request is successful, you insert the result into an HTML element. Be aware that you have also to prevent the default action of the form from happening: if you don't do so, your browser will open the page specified in the action attribute of your form.

If you want to test this example, try to insert some valid values such as CSS, DOM and XML and then some dummy text. You can see the final result here.

Parsing a FeedBurner feed with jQuery

Parsing a FeedBurner feed with jQuery requires two components:

  1. a proxy to fetch the feed
  2. Ajax to parse the feed

Here's the proxy, written in PHP:

<?php
header('Content-Type: text/xml');

$feed = file_get_contents('http://feeds.feedburner.com/blogspot/onwebdev/');

echo $feed;

?>

Now we can add jQuery:

$(document).ready(function() {
    
        $('<ul></ul>').insertAfter('h1');
    
    
        $.get('proxy.php', function(data) {
        
        
            var $items = $(data).find('item');
            
            $items.each(function() {
            
                var html = '';
            
                var $item = $(this);
                
                var $title = $item.find('title').text();
                var raw_author = $item.find('author').text();
                
                var $author = raw_author.replace('gabriele.romanato@gmail.com', '').
                              replace('(', '').replace(')', '');
                              
                var $link = $item.find('author').next().next().text();
                
                var raw_date = $item.find('pubDate').text();
                var $pubdate = raw_date.replace('+0000', '');
                
                
                html += '<li><a href="' + $link + '">' + $title + '</a>' + '<div class="author">' + $author + '</div>' + 
        '<div class="pubdate">' + $pubdate + '</div>' + "</li>";

                $(html).appendTo('ul');
            
            });
        
        
        
        });
    
    
    });

There's only a difficult part here: selecting the feedburner:origLink element which has a namespace. To accomplish this task, we've used the next() method which returns the adjacent sibling of a given element. You can see the final result here.

Wordpress theme metadata and CSS

Each Wordpress theme metadata (such as author, theme name, version, etc.) is actually contained at the very beginning of the main style sheet of your theme. For example:

/*   
Theme Name: Rose
Theme URI: the-theme's-homepage
Description: a-brief-description
Author: your-name
Author URI: your-URI
Template: use-this-to-define-a-parent-theme--optional
Version: a-number--optional
.
General comments/License Statement if any.
.
*/

Providing this information is essential because it allows the Wordpress core to show all the details provided with your theme. If your don't specify this metadata, Wordpress won't show any information while you try to select and activate your theme.

Parsing a FeedBurner feed with SimpleXML

Parsing a FeedBurner feed with SimpleXML requires only a single gotcha: the actual parsing starts from the root element, not from the whole object created with the simplexml_load_file() function. For example, the following code returns nothing:

$feed = simplexml_load_file('http://feeds.feedburner.com/blogspot/onwebdev/');

foreach($feed->item as $item) {

    //... nothing here

}

Instead, the following code works as expected:

 $feed = simplexml_load_file('http://feeds.feedburner.com/blogspot/onwebdev/');
    
    foreach($feed->channel->item as $item) {
    
        $title = $item->title;
        $raw_author = $item->author;
        $author = str_replace('gabriele.romanato@gmail.com', '', $raw_author);
        $author = str_replace('(', '', $author);
        $author = str_replace(')', '', $author);
        $links = $item->children('http://rssnamespace.org/feedburner/ext/1.0');
        $link = $links->origLink;
        $raw_date = $item->pubDate;
        $pubdate = str_replace('+0000', '', $raw_date);
        
        echo '<li><a href="' . $link . '">' . $title . '</a>' . "\n" . '<div class="author">' . $author . '</div>' . "\n" .
        '<div class="pubdate">' . $pubdate . '</div>' . "</li>\n";
    
    
    }

You can notice that now the parsing starts from the channel element. You can see the final result here.

Parsing a Twitter feed with jQuery

Parsing a Twitter feed with jQuery requires two steps:

  1. building a server-side proxy to retrieve the feed
  2. using Ajax to parse the feed.

The proxy's code, written in PHP, is really simple:

tweets.php

<?php
header('Content-Type: text/xml');
$tweets = file_get_contents('http://twitter.com/statuses/user_timeline/120345723.rss');
echo $tweets;
?>

After this, we can use the $.get() method of jQuery to parse this file:

$(document).ready(function() {
 
 
 $.get('tweets.php', function(data) {
 
 
     var $items = $(data).find('item');
     
     $items.each(function() {
     
     
         var $item = $(this);
         var $raw_title = $item.find('title').text();
         var $title = $raw_title.replace('gabromanato:', '').replace(/http:.+/, '');
         var $raw_date = $item.find('pubDate').text();
         var $date = $raw_date.replace('+0000', '');
         var $link = $item.find('link').text();
         
         var html = $('<li></li>').html('<a href="'+$link+'">'+$title+'</a>'+ '<div class="pubdate">'+$date+'</div>');
         
         html.appendTo('#tweets');
     
     
     
     });
 
 
 
 });
 
 
 });

I did this because Ajax cannot fetch a resource located on another domain (this is called same domain policy), so we have to use a Proxy. You can see the final result here.

Parsing Twitter feeds with SimpleXML

Parsing Twitter feeds with SimpleXML is quite a simple task. First of all, you need the URL of your Twitter RSS/Atom feed. Then you can use SimpleXML as follows:

$tweets = simplexml_load_file('http://twitter.com/statuses/user_timeline/120345723.rss');
        
    
    foreach($tweets->channel->item as $tweet) {
    
        $raw_title = $tweet->title;
        $title = str_replace('gabromanato:', '', $raw_title);
        $title = preg_replace('/http.+/', '', $title);
        
        $raw_date = $tweet->pubDate;
        $date = str_replace('+0000', '', $raw_date);
        
        $link = $tweet->link;
        
        echo '<li><a href="' . $link . '">' . $title . '</a>' . "\n" . '<div class="pubdate">' . $date . '</div>' . "\n" . "</li>\n";
    
    
    }

I've only removed some unnecessary strings using str_replace() and preg_replace(). You can see the final result here.

Browser default style sheets

I stumbled on this great website following some links on the HTML5 default style sheet used by supporting browsers. The information provided here are really useful and serve as a quick start for testing CSS styles in various versions of Internet Explorer. Versions 6, 7, 8 and 9 are all reviewed. Further, this site provides also information on Firefox, Webkit and Opera default style sheets. This is useful, because sometimes we need to rely on browser default styles to render certain elements, such as paragraphs or lists.

Browser statistics: the Chrome's momentum

Recently I consulted the Google statistics about this blog. Browser stats are reported in the following table:

Browser statistics of the last two months
Browser Visits % visits
Firefox 925 48.58%
Chrome 452 23.74%
Safari 193 10.14%
Internet Explorer 166 8.72%
Opera 57 2.99%

First Firefox, last Opera. More surprising is the still relevant percentage of Internet Explorer users, with 166 visits. I don't know which version of IE they're actually using, though. Second and third are Chrome and Safari, respectively. This shows how Chrome is gaining its momentum among web developers and web users.

CSS comments: grouping blocks

Richard Rutter proposed an interesting technique for organizing CSS through comments. This technique is based upon grouping. Simply put, we can actually organize our CSS files by using groups of rules that perform some common actions on the layout. For example:

/* @group Tables */

table {
 border-bottom: 1px solid #666;
}

caption {
 font-weight: bold;
 padding-bottom: 0.643em; /* 9px */
 font-size:1.077em; /* 14px */
}

thead th {
 border-top: 1px solid #666;
 border-bottom: 3px solid #666;
 padding-top: 0;
 padding-bottom: 0.692em; /* 9px */
}

tbody {
 border-top: 3px solid #666; /* not rendered in IE6/7 */
}

tbody tr th, tbody tr td {
 border-top: 1px solid #ddd;
}

th, td {
 text-align: left;
 padding: 0.385em 0.692em 0.308em 0.692em; /* 5px 9px 4px 9px */
}

/* @end */

Each group is marked up by two CSS comments, one at the beginning of the group and the other one at its end, starting with @group Name and ending with @end. So if you want to run a global search in your CSS file, you have simply to search for every instance of the @group sequence. This gives you a complete mapping of your CSS file. I find this technique more useful than CSS flags. In fact, with CSS flags you get only the beginning of a block. For example:

/*=Tables */

Instead, with grouping blocks you can even perform a more powerful search using regular expressions that match the whole content of a block. Very useful.

CSS Mastery: Advanced Web Standards Solutions

CSS MasteryCSS Mastery: Advanced Web Standards Solutions is a great book on CSS written by Andy Budd, Simon Collison and Cameron Moll. After reading the review at FriendsOfEd, I decided to add it to my wish list. The fact is that Andy and the others are perhaps some of the most influent voices on client-side web development that we can find on the web. They're skilled, talented and they've supported web standards since the beginning of the end of browser wars (or even before). I always like learning something new from the great Jedi masters of the web, because there are still some obscure details of CSS that make me feel confused. Books are completely different from what you can find on the web. Before publishing, they've been accurately reviewed and all the live examples provided with the paper version have been extensively tested. I trust books. They're something that doesn't depend on network efficiency or electrical power. The real power is in the mind of the reader who can bring them to life. I love books!

Generating a multiplication table with CSS

We can actually generate a multiplication table using CSS generated content. We start with a basic table with ten rows and ten cells on each row:

<table summary="Multiplication table">
<caption>Multiplication table</caption>

<tr id="one">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="two">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="three">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="four">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="five">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="six">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="seven">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="eight">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="nine">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr id="ten">
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>

We have ten different IDs on ten rows. Now we can add a progressive numeration using CSS counters:

tr#one {
counter-reset: one;
}

tr#one>td:before {
counter-increment: one;
content: counter(one);
}

tr#two {
counter-reset: two;
}

tr#two>td:before {
counter-increment: two 2;
content: counter(two);
}

tr#three {counter-reset: three;}
tr#three>td:before {
counter-increment: three 3;
content: counter(three);
}

tr#four {counter-reset: four;}
tr#four>td:before {
counter-increment: four 4;
content: counter(four);
}


tr#five {counter-reset: five;}
tr#five>td:before {
counter-increment: five 5;
content: counter(five);
}


tr#six {counter-reset: six;}
tr#six>td:before {
counter-increment: six 6;
content: counter(six);
}


tr#seven {counter-reset: seven;}
tr#seven>td:before {
counter-increment: seven 7;
content: counter(seven);
}


tr#eight {counter-reset: eight;}
tr#eight>td:before {
counter-increment: eight 8;
content: counter(eight);
}


tr#nine {counter-reset: nine;}
tr#nine>td:before {
counter-increment: nine 9;
content: counter(nine);
}


tr#ten {counter-reset: ten;}
tr#ten>td:before {
counter-increment: ten 10;
content: counter(ten);
}

As you can see, each row has its own counter (one, two, three and so on). Each counter is first reset and then incremented by a progressive factor (2, 3, 4, 5 etc.) so that each cell show the desired numerical progression. We use the :before pseudo-element to insert each number inside its own cell. You can see the final result here.

CSS tutorial for Blogger users: font size constants

As a rule of thumb, you should always use relative font sizes to make the reading comfortable to your visitors. By doing so, users can actually resize your text and are not forced to get closer to their monitor. CSS provides two useful relative lengths for this purpose: ems and percentages. However, browser are really quirky when it comes to font resizing with these lengths. During all these years, fortunately, some developers found out two useful font size constants that form the base of a successful font sizing:

  1. 62.5% – equals to 10px
  2. 76% – equals to 12px

First example with 62.5%:

body {font-size: 62.5%;} /* 1em = 10px */

h1 {font-size: 2em;}  /* 1 * 2 = 20px */

Second example with 76%:

body {font-size: 76%;} /* 1em = 12px */

p {font-size: 1.1em;} /* 1 * 0.1 = 13px */

As you can see, it's very simple to make font size calculations using these constants.

CSS tutorial for Blogger users: styling the header

Surely the header of our Blogger blog is one of the first things we need to stylize with CSS. For example, given the following markup:

<div id="wrapper">

    <div id="header">
    
        <h1><a href="http://onwebdev.blogspot.com">onwebdev</a></h1>
    
    </div>

</div>

we can add the following styles if we want our header appear with a tiled background image:

body {
    font-size: 76%; /* 1em = 12px */
    margin: 0;
    padding: 0;
    background: #fff;
    color: #333;
}

#wrapper {

    width: 100%;

}

#header {

    height: 190px;
    background: #def url(img/header.png) repeat-x 0 0;
    position: relative;

}

#header h1 {

    margin: 0;
    font: normal 8em Georgia, serif;
    color: #339;
    position: absolute;
    bottom: 0;
    left: 0.5em;
    

}

#header h1 a {

    color: #339;
    text-decoration: none;

}

The background image is repeated horizontally using the background-repeat property. Note that we've also specified a background color for our header. This is considered a best practice to follow in order to make sure that a correct contrast between background and foreground colors is provided to users who have turned off images in their browsers. To achieve the effect of a title put at the very bottom of the header, we use absolute positioning on the h1 element. This work because its parent element has the declaration position: relative. This is called contextual positioning. You can see the final result here.

Extending jQuery: the removeAttributes() method

This plugin for jQuery simply resets all attributes for a given element. It is as follows:

(function($) {

    $.fn.removeAttributes = function() {
    
       var attrs = this[0].attributes;
       
       for(var i=0; i<attrs.length; i++) {
       
           var $attr = attrs[i].nodeName;
    
    
    
    switch($attr) {
    
        case 'class':
            this[0].className = '';
     break;
        case 'border':
            this[0].setAttribute('border', 0);
     break;
    
        default:
           this[0].setAttribute($attr, '');
    break;
    
    }
       
       
       }
    
    
    };


})(jQuery);

Example:

$('table').removeAttributes();

We work with the DOM element node to make sure that we have access to the attributes collection. Some things need still to be tested, particularly those attributes with numeric values. Here we use the className property to fix an obtuse bug of IE 6 with the setAttribute() method. You can see a demo here and download the source code here.

Styling an hCard with CSS

In this post, I'm going to show you how to stylize an hCard with CSS. An hCard is a specification which defines a new type of microformat. In simple terms, it is defined as:

hCard is a simple, open, distributed format for representing people, companies, organizations, and places, using a 1:1 representation of vCard (RFC2426) properties and values in semantic HTML or XHTML. hCard is one of several open microformat standards suitable for embedding in HTML, XHTML, Atom, RSS, and arbitrary XML.

In our example, we're going to stylize the following hCard:

<div class="vcard">
  <a class="fn org url" href="http://onwebdev.blogspot.com/">onwebdev</a>
  <div class="adr">
    <span class="type">Work:</span>    
    <span class="street-address">Some address</span>
    <span class="locality">A City</span>,  
    <abbr class="region" title="Region">A Region</abbr>
    <span class="postal-code">000000</span>
    <span class="country-name">Italy</div>
  </div>
  <div class="tel">
   <span class="type">Work</span> +39-00-00-00
  </div>
  <div class="tel">
    <span class="type">Fax</span> +39-00-00-00
  </div>
  <div>Email: 
   <span class="email">gabriele.romanato@gmail.com</span>
  </div>
</div>

with the following CSS styles:

.vcard {

    height: 100%;
    border-top: 3px solid #000;
    border-bottom: 2px solid gray;
    padding: 0.4em 0;


}

a.url {

    display: block;
    height: 100%;
    color: #339;
    font: 1.3em Georgia, serif;
    background: url(img/warning.png) no-repeat 0 0;
    padding-left: 19px;
    border-bottom: 1px solid gray;

}

.adr {

    width: 90%;
    margin: 10px auto;
    padding: 5px 5px 5px 19px;
    background: #eee url(img/name.png) no-repeat 0.3em 0.5em;
    border-left: 4px solid gray;
    border-right: 4px solid gray;

}


.adr span {

    font-style: italic;
    padding: 0 0.3em;

}

.adr span.type {
    display: block;
    height: 100%;
    font: normal 1.3em Georgia, serif;
    color: #666;
    border-bottom: 1px dashed;
}

.tel {

    height: 100%;
    margin-bottom: 10px;
    padding: 5px 0 5px 19px;
    border-bottom: 1px dashed gray;
    background: url(img/subject.png) no-repeat 0 0.5em;

}

.tel .type {

    font-weight: bold;

}

div.tel + div.tel + div {

    height: 100%;
    margin: 10px 0;
    padding: 5px 0 5px 19px;
    border-bottom: 1px dashed gray;
    background: url(img/email.png) no-repeat 0 0.4em;
    font-weight: bold;

}

div.tel + div.tel + div > .email {font-weight: normal;}

As you can see, there's nothing really difficult here. Of course this is only a basic example, but you can extend it further. You can see the final result here.

CSS tutorial for Blogger users: handling floated images

Handling floated images can be actually a tedious task, especially when we don't want that the elements following those images be still affected by floating. For example, if you have a markup like this:

<p><img src="image.png" alt="Image" class="alignleft" />Paragraph content.</p>

In this case, it's very likely that the elements coming after the paragraph are still affected by floating, because the content of the paragraph is not sufficient to contain the floated image. You can easily fix this problem by adding the following class to the paragraph:

.cleared {
  overflow: hidden;
  height: 100%; /* IE6 */
}

However, you still have to add this class manually. You can automate this task by using jQuery. For example:

$(document).ready(function() {

    $('img').each(function() {

      var $img = $(this);

        if($img.hasClass('alignleft') {
             
              $img.parent().addClass('cleared');
        }

    });

});

By doing so, floated images inside paragraphs are automatically cleared and contained.

Styling links with CSS3 attribute selectors

Styling links is easy with CSS3 attribute selectors. We're going to use the following attribute selectors:

  1. element[attribute$="value"] – matches an element when the value of its attribute ends with value
  2. element[attribute*="value"] – matches an element when the value of its attribute contains value
  3. element[attribute^="values"] – matches an element when the value of its attribute starts with value.

Here's a sample CSS code:

a[href$="pdf"] {

    background: url(img/pdf.png) no-repeat 100% 2px;
    padding-right: 15px;

}

a[href*="facebook"] {

    background: url(img/facebook.png) no-repeat 100% 0;
    height: 23px;
    padding-right: 29px;
    display: inline-block;
    line-height: 23px;

}

a[href^="http://onwebdev"] {

    background: url(img/recent-entries.gif) no-repeat 100% 55%;
    padding-right: 15px;

}

a[href$="xml"] {

    background: url(img/xml.png) no-repeat 100% 3px;
    padding-right: 16px;

}

You can see the final result here.

jQuery horizontal accordion

We want to create an horizontal accordion with jQuery and some nice animation effects to show when we expand our items. We start with a basic markup like this:

<div id="accordion">

    <h2 class="main"><a href="#main-content">Title</a></h2>
    
    <div id="main-content" class="content">
        <p>...</p>
    </div>
    
    <h2 class="sub"><a href="#sub-content">Title</a></h2>
    
    <div id="sub-content" class="content">
        <p>...</p>
    </div>

</div>

Then we add some CSS styles to create the effect of a side panel menu:

#accordion {
 width: 100%;
 height: 100%;
 overflow: hidden;
}

#accordion h2 {
 margin: 0 10px 0 0;
 width: 5px;
 height: 35px;
 display: block;
 float: left;
 background: url(img/expand.gif) no-repeat 0 0;
}

#accordion h2 a {
 float: left;
 display: block;
 height: 35px;
 width: 5px;
 text-indent: -1000em;
 outline-style: none;
               
}

#accordion div.content {
 float: left;
 width: 200px;
 margin: 0;
 padding-right: 10px;
}

#accordion div.content p {
 margin-top: 0;
}

Each panel is made up by an heading and an hyperlink which are left-floated and the heading has a background image. The whole area is clickable because the child link has exactly the same dimensions of its parent. Now let's add jQuery:

$(document).ready(function() {

    $('#accordion .content').hide().css('width', '100px');
    
    $('#accordion h2').each(function() {
    
        var $h2 = $(this);
        
        $h2.find('a').click(function() {
 
 $h2.next().animate({width: '200px'}, 'slow');
 
 return false;
 
        });
    
    
    });
});

After hiding all the panels next to our tabs, we've assigned to them a width that is less than their original CSS width. Why so? Because later in the source we use the animate() method to create our effect: when an user clicks on a tab, he/she will see the text growing until the whole block gains its original dimensions. You can see the final result here.

CSS tutorial for Blogger users: handling wide images

Wide images can actually break your layouts if not handled properly. Suppose that you don't want to use the Blogger upload function. Instead, you want to insert an image this way:

<img src="http://www.somesite.com/img/wide-image.png" />

You open your post page and you notice that your layout is broken. Sure, you can specify the dimensions of each image through HTML attributes, but to do this you have to know in advance the exact dimensions of each image. CSS provides a simple workaround to this problem:

img.wide {
  display: block;
  width: 100%;
}

By doing so, the width of each image will always fit the width of its container. This technique works because we've turned our images into block-level elements and then we've applied percentages to them. You don't have to worry about the exact dimensions of each image anymore. Really useful!

CSS tutorial for Blogger users: CSS reset

The CSS reset technique deals with browser default styles. Each browser has its own default styles used to handle HTML elements when no other styles are provided. Sometimes these default styles can actually interfere with the design that you want to get. So it's better to reset them by normalizing all HTML elements. However, you have to make a choice: if you want to perform a global reset, just use one of many CSS reset templates that you can find with a Google search, otherwise you have to select which elements you want to normalize. Here's a basic example:

html, body, h1, h2, h3, h4, h5, h6, p, ol, ul, dd, blockquote, pre, address, form, fieldset, legend {
    font-size: 100%;
    margin: 0;
    padding: 0;
    border: none;
    font-style: normal;
}

As you can see, we've chosen some elements that we know as affected by the default styles of browsers. Of course you can add even more elements to the list, for example by including table elements. The choice is up to you. Bear in mind, however, that sometimes relying on default styles is useful. For example, paragraphs have all top and bottom margins set to 1em. If you reset them at the very beginning of your CSS file, you have to specify these margins later in the source if you want to achieve the effect of some white space above and below them.

CSS tutorial for Blogger users: overriding styles

Sometimes we cannot get the effect that we want with CSS due to some cascade and specificity problems. The first and most noticeable problem is that related to inline styles. Inline styles are those attached to a single HTML element through the style attribute. According to CSS specifications, these styles take precedence over other styles. For example, if you have the following markup:

<p style="color: red;">Test</p>

with this CSS rule:

p {
  color: blue;
}

The text of the paragraph is still red because of the higher specificity of inline styles. If you want to override them, you have to use the !important statement, like so:

p {
  color: blue !important;
}

You can use this statement in many cases, but not in all. Suppose that your template contains the following rule:

#wrapper .post {
  font-size: 1.2em;
}

An innocent coder would be tempted to use the !important statement, as follows:

.post {
    font-size: 1em !important;
}

It doesn't work, because the former rule is still more specific than the latter. Instead, you have to write:

#wrapper .post {
  font-size: 1em !important;
}

Also remember that the source code order is relevant: if two rules have the same specificity, the winner is the rules that comes after in the source. This also applies to the source code position of stylesheets: if all the embedded styles are put within the style element, make sure that your linked styles (via the link element) come after this element, like so:

<head>
<style type="text/css">
...
</style>
<link rel="stylesheet" href="http://mywebspace.com/style/blogger.css" type="text/css" media="screen" />
</head>

By doing so, your styles can actually override the others in case of rules with the same specificity.

CSS tutorial for Blogger users: basic concepts

Although you can easily download and install a new Blogger template, it's always a good thing to understand how CSS layouts are actually handled by Blogger. First, CSS styles are embedded inside your main HTML page template inside the style element, like so:

<head>
<style type="text/css">
...
</style>
</head>

If you want to embed new styles, just put them inside this element. Otherwise, you can even use an external stylesheet that you can upload elsewhere and link in your template using the link element, as follows:

<head>
<-- more here -->
<link rel="stylesheet" href="http://yourwebspace.com/style/blogger.css" type="text/css" media="screen" />
</head>

Now one important thing to take into account is how your HTML page template is structured. You should bear in mind that you can actually edit your design through the visual design editor provided by Blogger. When you make a change to the layout using this editor, this change is automatically added to the embedded stylesheet used by your template (in the style element, remember?) through Blogger variables which start with a $ character.

Further, you have to deal with widgets. Widgets are HTML snippets used by Blogger to contain all the sections of your blog. When you edit your HTML template, you have to select the option "Expand Widget Templates" to see their inner HTML structure. Why so? Suppose that you want to stylize the main container of your blog. You expand widgets and find out that its name is wrapper. So you can write the following CSS rule:

#wrapper {
    margin: 0 auto;
    width: 90%;
}

I don't recommend you to modify this widgets through the HTML editor, because their names are used internally by the CMS to make your blog work. If you want to add or remove widgets, use the GUI provided by Blogger.

An image gallery with a definition list and CSS

Building an image gallery with a definition list (dl) and CSS can be very interesting. We start with a basic markup like this:

<dl id="gallery">

<dt><img src="img/duck.png" alt="Duck" /></dt>
<dd>
<ul>
<li>
<h3>A duck</h3>
<p>Uploaded: Sat, June 19 2010</p>
</li>
</ul>
</dd>


<dt><img src="img/boat.png" alt="Boat" /></dt>
<dd>
<ul>
<li>
<h3>A boat</h3>
<p>Uploaded: Sat, June 19 2010</p>
</li>
</ul>
</dd>

</dl>

We want the image be on the left and the description on the right. Here is how it can be done with CSS:

#gallery {

    height: 100%;
    overflow: hidden;
    padding: 1em 0;
    border: 5px solid gray;
    border-width: 5px 0;


}

#gallery dt {

    float: left;
    width: 200px;
    margin: 0;
    clear: left;

}

#gallery dd {

    
    margin: 0 100px 0 0;
    padding: 5px 0;
    border: 1px dashed gray;
    border-width: 1px 0;
    width: 200px;
    float: right;
    display: inline;

}

#gallery dd ul {

    margin: 0 auto;
    width: 90%;
    padding: 5px;
    list-style: none;
    border: 2px solid gray;
    border-radius: 3px;
    -moz-border-radius: 3px;

}

#gallery dd h3 {

    margin: 0;
    font: normal 1.4em "Trebuchet MS", Trebuchet, sans-serif;
    color: #666;
    border-bottom: 1px dashed;

}

#gallery dd p {

    font-style: italic;
    margin-top: 0;
    padding-top: 4px;

}

We've used the float property to align our boxes. The declaration display: inline avoids the infamous doubled margin bug in Internet Explorer 6. Our floats appear on different lines simply because there is no more space available to display them on a single line (this is one of the several rules defined by the CSS specifications). You can see the final result here.

WAI-ARIA: another W3C failure?

ARIA (Accessible Rich Internet Applications) is a WAI initiative promoted by the W3C to make rich internet applications accessible to assistive technologies. I'm actually quite a fan of this initiative, but I'm also aware of the fact that maybe we're facing another W3C failure. I'll try to make myself clear. The sad truth about these initiative is that the actual actors of this drama are not on the stage together. The actors of the W3C play are both user-agent vendors and assistive technologies vendors. So far so good.

The problem here is that both actors don't communicate to each other. For example, many of you recall the problem of the CSS declaration display: none interpreted by most screen readers as speak: none. This is a bug, of course, but you can't blame or curse screen readers, because their implementors were not involved with the process behind the CSS specifications. None of them! As result, screen readers didn't implement aural style sheets which were later abandoned. So we have two actors on two different stages, as you can see from the following picture taken from the ARIA specs:

WAI-ARIA Scheme

Theoretically speaking, user-agents and assistive technologies should communicate in order to make this model work. Reality is actually different: WAI-ARIA is currently poorly supported by most browsers, not to say ignored by Internet Explorer which is still the most used browser on the web. I think that we're facing a situation similar to the lack of support for application/xhtml+xml which made XHTML 1.1 fall into oblivion (and, consequently, HTML 5 arose from the ashes of XHTML 2). To prevent this from happening, the W3C should put both actors on the same stage by getting them involved with this initiative as much as possible. Otherwise, this would be another W3C failure.

Adding icons to form elements with jQuery

Adding icons to form elements is quite a simple task with jQuery. Suppose that we have a basic contact form like this:

<form action="" method="post" id="contact-form">

<ul>
    
        <li>
            <label for="name">First Name</label>
            <input type="text" name="name" id="name" />
        </li>
        
        <li>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname" id="lastname" />
        </li>
        
        <li>
            <label for="email">Email</label>
            <input type="text" name="email" id="email" />
        </li>
        
        <li>
             <label for="subject">Subject</label>
             <input type="text" name="subject" id="subject" />
        
        </li>
        
        <li>
            <label for="message">Message</label>
            <textarea cols="30" rows="15" name="message" id="message"></textarea>
        </li>
        
        <li>
            <label for="antispam">The capital of Italy</label>
            <input type="text" name="antispam" id="antispam" />
        </li>
    
    
    </ul>


<p><input type="submit" name="submit" id="submit" value="Send" /></p>



</form>

Each form items should have a different background image put on the left of each label element. We can actually use the following CSS classes to be applied to li elements:

.name, .lastname, .subject, .message, .antispam, .email {
 padding-left: 19px;
 background-position: 0 2px;
 background-repeat: no-repeat;
}

.name, .lastname {
 background-image: url("img/name.png");
}
.subject {
 background-image: url("img/subject.png");
}
.message {
 background-image: url("img/message.png");
}
.antispam {
 background-image: url("img/warning.png");
}

.email {
 background-image: url("img/email.png");
}

We don't want to add them manually, so we use jQuery, like so:

function setFormIcons() {
    
        if($('#contact-form')) {
 
     $('#contact-form ul li').each(function() {
     
     var $li = $(this);
  var $attrFor = $li.find('label').attr('for');
  
  switch($attrFor) {
  
      case 'name':
      $li.addClass('name');
      break;
      
      case 'lastname':
      $li.addClass('lastname');
      break;
      
      case 'subject':
      $li.addClass('subject');
      break;
      
      case 'message':
      $li.addClass('message');
      break;
      
      case 'antispam':
      $li.addClass('antispam');
      break;
      
      case 'email':
      $li.addClass('email');
      break;
      
      default:
      break;
  
  
  }
  
     
     });
 
 
 } else {
     return;
 }
    
}



$(document).ready(function() {

    setFormIcons();
    
});

We define a function called setFormIcons() that retrieves the value of the for attribute of each label element and applies a CSS class to its parent depending on the value in use. Of course you can follow another approach by retrieving the value of the various name attributes and then applying the related CSS class to each li element. You can see the final result here.

Centering the text of a legend element with CSS

Centering the text of a legend element with CSS is not so simple as it could seem at first glance. The main problem that we have to face is that this kind of element is governed by the internal rules of the browser, because CSS specifications don't say how this element should be handled and rendered. The result is that every browser has its own rules, so that we have to use some workarounds to manage this situation. I hate to use presentational markup, but in this case I actually ended up with a basic markup like this:

<form action="" method="post">

<fieldset>

<legend><span>Test</span></legend>

<div class="checkbox-container">
<input type="checkbox" id="check1" name="check1" />
<input type="checkbox" id="check2" name="check2" />
</div>

</fieldset>

</form>

However, all the presentational markup can actually be generated by JavaScript and here has only a demonstrative purpose. Then come our CSS styles:

form {

    margin: 0;
    padding: 0;
    height: 100%;

}

fieldset {

    margin: 0;
    padding: 0;
    border: 1px dashed #000;
    border-width: 0 0 1px 0;

}

legend {

    margin: 0;
    padding: 0;
    text-align: center !important;
    display: block !important;
    width: 100%;
}

legend span {

    background: #fff;
    position: relative;
    top: 0.7em;
    padding: 0 0.5em;

}




.checkbox-container {

    border-top: 1px dashed;
    width: 100%;

}

Here we've turned our legend element into a block-level element and we've assigned a width to it (100% is required to make it work) plus the declaration text-align: center. Finally, we've stylized our extra span element by adding some horizontal padding and relative positioning plus a background color which is equal to the background color of the page (it's necessary to create the effect of the hanging text). Notice that we've actually used the top border of our checkbox wrapper instead of the top border of the fieldset element just because this approach would cause some problems. You can see this demo here.

Screenshots taken from Internet Explorer

IE 6

IE 6

IE 7

IE 7

IE 8

IE 8