3d navigation buttons with CSS

Creating 3d navigation buttons with CSS is not a difficult task, provided that we understand a basic principle: using outset or inset as values for the border-style property leads to inconsistent results across browsers, especially in Internet Explorer. So we have to find another way. Given that a 3d effect is an effect usually achieved on desktop environments by using certain color combinations, we're going to follow the same approach here. Thus, given the following markup:

<ul id="navigation">

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

</ul>

we can add the following styles:

#navigation {
 margin: 0;
 padding: 0;
 list-style: none;
 background: #396;
 color: #fff;
 width: 100%;
 float: left;
}

#navigation li {
 float: left;
 height: 100%;
 padding: 0 0.5em;
}

#navigation li a:link,
#navigation li a:visited {
 background: #4a7;
 border: 0.2em solid;
 border-color: #cec #464 #575 #dfd;
 color: #fff;
 padding: 0.1em 0.5em;
 text-decoration: none;
 font-weight: bold;
 float: left;
 height: 1.8em;
 line-height: 1.8;
}

#navigation li a:hover {
 background: #396;
 color: #fff;
 border-color: #575 #dfd #cec #464;
}

The key aspect here are the different values given to the border-color property: by combining different border colors we can actually achieve the desired result by giving to our buttons the appearance of 3d images. You can see the final result here.

Inserting HTML from a text file with jQuery

Loading HTML from a text file is a useful way to get a better performance with the jQuery's load() method. Given a simple text file that contains the following line:

<h1>Test</h1>

we can easily load its content into a target element with a simple jQuery statement:

$(document).ready(function() {
    
        $('#test').load('test.txt');
    
    
});

You can see that test here. By doing so, we avoid HTML parsing while retrieving a given resource.

Table headers and text alignment in CSS

Bruno Fassino wrote this note:

Table headers (th) have a default center text alignment in most browsers.

Appendix D of the CSS2.1 spec suggests a

th { text-align: center }

rule in the default UA style sheet. But not all browsers get the above alignment in such a way, as demonstrated by what follows.

The following test case has text-align: left added to the row element (tr) including the th.

If an UA had the rule (1) in its default sheet, than the above test case should not display differently from the first one, even if text-align is a property which "inherits", because when a property is "directly" applied to an element, then inheritance does not trigger. See CSS 2.1 section 6.1.1: inheritance is taken into account only if the cascade does not result in a value (in other words: inheritance has always less "precedence" than a specified value in the cascade).

So, according to the above, with a rule (1) in the UA sheet any text-align applied on an ancestor of a th should have no effect on the th. In IE8 indeed the rendering of the above two test cases is the same. However, most other browsers (Firefox, Opera, Safari, IE<8), probably for compatibility with existing pages, behave in a way that text-align applied to an ancestor of a th has an effect on the th itself. This means that they behave differently than having a rule (1) in their UA sheet. This behavior is probably not expressible in terms of standard existing CSS properties and values.

A bug filed for Gecko, about it allowing text-align on a parent to "override" the centering of a th, has been marked as invalid. Appendix D is indeed not normative, so browsers are not required to behave exactly in that way.

Navigation tooltips with jQuery

Navigation tooltips are a useful way to add additional information to our menus. We can create navigation tooltips by using jQuery in a simple and cross-browser manner. Let's start with a simple menu:

<ul id="navigation">
<li><a href="#">Home</a></li>
<li><a href="#">Projects</a></li>
<li><a href="#">Tutorials</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Tests</a></li>
</ul>

Then we can add some CSS styles:

#navigation {
 margin: 0;
 padding: 0;
 background: #666;
 color: #fff;
 font: bold 76% Verdana, sans-serif;
 list-style: none;
 float: left;
 width: 100%;
}

#navigation li {
 float: left;
 margin-right: 0.5em;
 height: 100%;
}

#navigation li a:link, #navigation li a:visited {
 float: left;
 display: block;
 height: 100%;
 text-decoration: none;
 padding: 0.3em;
 text-transform: uppercase;
 color: #fff;
 
}

#navigation li a:hover {
 background: #999;
}

We can also stylize our tooltip, like so:

span.tooltip {
    background: #ffc;
    border: 2px solid #999;
    color: #333;
    padding: 4px;
}

The jQuery code is very simple and is as follows:


$(document).ready(function() {
    
    
        $('#navigation li a').each(function() {
 
 var $tooltip = $('<span class="tooltip"></span>');
        var $a = $(this);
 var aText = $a.text();
 var aPos = $a.position();
 $tooltip.insertAfter($a).hide();
 
 
 switch(aText) {
 
     case 'Home':
         $tooltip.text('Home page.');
  break;
     case 'Projects':
         $tooltip.text('My projects.');
  break;
     case 'Tutorials':
         $tooltip.text('My tutorials.');
  break;
     case 'Blog':
         $tooltip.text('A blog on web standards.');
  break;
     case 'Tests':
         $tooltip.text('Tests on web standards.');
  break;
     default:
             break;

 }
 
 
 $a.mouseover(function() {
 
     $tooltip.css({
         display: 'block',
  position: 'absolute',
  top: aPos.top + 33,
                left: aPos.left,
  width: '180px',
  height: '12px'
     });
 
 });
 $a.mouseout(function() {
 
     $tooltip.hide();
 
 });
 
 
 
    
    });
    
    
    });


We basically get the coordinates of each link of our navigation menu and then we absolutely position our tooltip according to these coordinates. The tooltip we'll be showed on hover and hidden when the user moves his mouse away from a link. Note that we've inserted contextual messages depending on the text content of each link. You can see the final result here.

Parsing a JSON Flickr feed with jQuery

Parsing a JSON Flickr feed with jQuery is not so simple as it could seem, because this requires a firm knowledge of two factors: the feed URL and the correct syntax to use with the jQuery's getJSON() method. First the URL, that must be in this form:

http://api.flickr.com/services/feeds/photos_public.gne?id=31968388@N02&lang=it-it&format=json&jsoncallback=?

where id is your Flickr ID and lang is your preferred language. However, the key parameter is jsoncallback. Without this, your script will fail and it'll return null. Second, the syntax of the jQuery's method:

$.getJSON(url, function(data){});

where data is a reference to your JSON object. Now, let's test something:

$(document).ready(function() {

    $.getJSON('http://api.flickr.com/services/feeds/photos_public.gne?id=31968388@N02&lang=it-it&format=json&jsoncallback=?', 
    function(data) {
          
      var ul = $('<ul></ul>');
      var html = '';
      
      $.each(data.items, function(i,item) {            
            
             html += '<li><h3>' + item.title + '</h3><p><a href="'+item.link+ '"><img src="'+item.media.m+ '"/></a></p></li>';

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


});

You can see the result here. As you can see, preliminary requirements are more difficult to understand than the actual implementation.

Facebook social buttons with jQuery

Facebook social buttons are an easy way to insert Facebook's features into your website. If you connect to this page, you get for example the "Like" button that we're going to use in this tutorial. The point is: either you choose to use an iframe or FBML (Facebook Markup Language) you'll surely stumble on many validation errors, especially if you're using XHTML 1.0 Strict. So it's better to follow another approach, by using JavaScript and jQuery. So, given this markup:

<p id="fb-like"><iframe src="http://www.facebook.com/plugins/like.php?href=http%253A%252F%252Fonwebdev.blogspot.com&layout=standard&show_faces=true&width=450&action=like&font&colorscheme=light&height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:80px;" allowTransparency="true"></iframe></p>

you get this result, which is not a valid page. The first thing we need to do is to modify our markup by taking into account also the case when JavaScript is not supported, like this:

<p id="fb-like">
   
</p>


<noscript>
       <p><a href="http://www.facebook.com/plugins/like.php?href=http%253A%252F%252Fonwebdev.blogspot.com">Like</a></p>
</noscript>

By using the noscript element we make sure that our resource is still available when JavaScript is not supported or turned-off. Now it's time to add jQuery:

$(document).ready(function() {


  var $iframe = $('<iframe></iframe').attr(
                 {
                   'src': 'http://www.facebook.com/plugins/like.php?href=http%253A%252F%252Fonwebdev.blogspot.com&layout=standard&show_faces=true&width=450&action=like&font&colorscheme=light&height=80',                 
                 
                 'scrolling': 'no',
                 'frameborder': '0',
                 'allowTransparency': 'true'
                 
                 }
                 ).css({'border': 'none', 'overflow': 'hidden', 'width': '450px', 'height': '80px'});
$iframe.appendTo('#fb-like');

Simply put, we've assembled our iframe by adding its own attributes and CSS styles. You can see the final result here.

Nightmares

Since 2001 I can't sleep very well. I have horrible nightmares every night. Maybe this is somewhat related to insomnia, although this happens to me even when I sleep regularly. I usually wake up at 3 or 4 AM, I go online and try to get back to sleep. Most of my nightmares are about my future, my life and the existence of my relatives and friends. Sometimes I watch them die, other times they blame me for something I didn't do or say or even they try to hurt me, though this last aspect is mainly related to people whom my brain generates by summing up bits and pieces of memories from my childhood. Sometimes it's like living in a movie, generally a fantasy movie where everything seems fine at the beginning and then the whole story or plot turns into a nightmare. I wake up soaked with sweat. Of course I tried almost everything to prevent this from happening, for example by avoiding stimulant drinks or smoking and the like, but it didn't work. Nightmares come back. Every night. Even in the afternoon, when I try to catch up with sleep, I have nightmares. That's why I'm so prolific on this blog. It's a way to encapsulate anxiety. It's a way to forget that it will be night again. Every day. Every night.

Creating a Wordpress theme with CSS

Creating a Wordpress theme with CSS is rather interesting. First of all, we start with the basic Wordpress theme in its naked form. Then we need to apply some styles in order to create our Wordpress theme with CSS. Let's start with some basic styles:

/* General Styles */

body {
 margin: 0;
 padding: 0;
 color: #333;
 background: #fff;
 font: 76%/1.5 Verdana, sans-serif;
}

a:link, a:visited {
 color: #d39;
 background: transparent;
 text-decoration: none;
 border-bottom: 1px solid;
}
a:hover {
 color: #f5b;
}

/* Normalizes font size on headings */

h1, h2, h3, h4, h5, h6 {
 font-size: 1em;
}

/* Get rid of not required elements */

hr {
 display: none;
}

/* Adjust links inside headings */

h1 a:link,
h1 a:visited, 
h2 a:link,
h2 a:visited {
 border-bottom: none;
}

Now our template has been normalized, that is, we've only set some basic styles in order to create a common ground from which we can start building our layout. Now we can move to more complex things. Let's start with our main container:

/* LAYOUT */

/* Global container */

#page {
 margin: 0 auto;
 width: 80%;
}

As you can see here, our layout has been centered. Additionally, we've also added a width in percentage so that our layout will be resizable. Now it's time for another massive normalization:

/* HTML elements inside the global container */

#page h1,
#page h2,
#page h3,
#page h4,
#page h5,
#page h6 {
 font-family: Georgia, serif;
 color: #b17;
}

#page h1 a:link,
#page h1 a:visited,
#page h1 a:hover,
#page h2 a:link,
#page h2 a:visited,
#page h2 a:hover {
 color: #b17;
}

#page p {
 margin-top: 0;
}

And here is the result. Now our headings and links are stylized. Time to move on. Let's stylize our header:

/* Header */

#header {
 width: 100%;
 height: 8.2em;
 min-height: 100px; /* consistency between platforms using different fonts */
 background: #fff url("../img/header.png") repeat-x 0 0;
}

#headerimg {
 width: 100%;
 height: 100%;
 background: transparent url("../img/h1.png") no-repeat 100% 5%;
}

#headerimg h1 {
 font-size: 3em;
 margin: 0 0 0 150px;
 line-height: 1;
 padding-top: 10px;
}

#headerimg div.description {
 margin-left: 150px;
 padding-top: 3px;
 font: italic 1.2em/1 Georgia, serif;
}

You can see the result here. Notice the min-height workaround: some platforms may use a different font type and size, so this trick ensures a cross-platform compatibility. Now it's time to position our elements:

/* Positioning: Main content */

#content {
 width: 70%;
 float: left;
 margin: 0;
}


/* Positioning: Sidebar */

#sidebar {
 width: 25%;
 float: right;
 margin: 0;
}

/* Positioning: Footer */

#footer {
 clear: both;
 width: 100%;
 margin: 0;
}

As you can see here, we've put our main content to the left and the sidebar to the right by using floating. Our footer will appear under both columns because of the clearance applied to it. Let's move on to our main content now:

/* Main content */

.post {
 width: 100%;
}

.post h2 {
 margin: 0;
 padding: 0.3em 0 1px 1em;
 font-size: 1.6em;
 border-bottom: 1px dashed;
 background: transparent url("../img/h2.png") no-repeat 0 0.5em;
}

.post small {
 margin: 0.3em 0;
    display: block;
 background: #d39 url("../img/small.png") repeat-x 0 0;
 color: #fff;
 font-weight: bold;
 text-align: right;
 padding: 2px;
}

/* Create gutters */

.entry, .postmetadata {
 margin: 0 auto;
 width: 96%;
}


/* Post metadata */

.postmetadata {
 border-top: 1px dashed #b17;
 padding-bottom: 1em;
 background: transparent url("../img/metadata.gif") no-repeat 0 0.2em;
 padding-left: 1.5em;
}

We've stylized our post contents, as you can see here. Nothing really difficult, just some fancy background images on headings and descriptions. Now it's time to stylize our sidebar:

/* Sidebar */

#sidebar ul {
 margin: 0;
 padding: 0;
 list-style: none;
 width: 100%;
}

#sidebar #searchform, #sidebar #searchform p {
 margin: 0;
 padding-top: 0.5em;
}

#sidebar #searchform label.hidden {
 position: absolute;
 top: -1000em;
}

#sidebar #searchform input {
 vertical-align: middle;
 font: 1em Verdana, sans-serif;
}

#sidebar #searchform input#s {
 width: 120px;
 background: #fff;
 border: 1px solid #f5b;
}

#sidebar #searchform input#searchsubmit {
 background: #d39;
 color: #fff;
 font-weight: bold;
}

#sidebar h2 {
 margin: 0;
 font-size: 1.2em;
 background: transparent url("../img/category.png") no-repeat 0 50%;
 line-height: 1;
 padding: 0.3em 0 0.4em 14px;
}


#sidebar ul li ul li {
 background: transparent url("../img/li.gif") no-repeat 0 50%;
 margin-left: 14px;
 padding-left: 1em;
}

#sidebar ul li ul {
 padding-bottom: 0.5em;
}

And here is the result. We've just stylize our search form and our categories menus. Let's move to our footer:

/* Footer */

#footer p {
 margin: 0;
 width: 100%;
 padding: 2em 0;
 background: #b17 url("../img/footer.png") repeat-x 0 0;
 color: #fff;
 text-align: center;
}

#footer p a:link,
#footer p a:visited,
#footer p a:hover {
 color: #fff;
}

You can see here the result. Finally, a touch of style by adding a background image to the whole page and the sidebar:

/* Sidebar background image */

#sidebar {
 padding-bottom: 231px;
 background: transparent url("../img/sidebar.png") no-repeat 50% 100%;
}

/* Body background image */

body {
 background-image: url("../img/body.png");
 background-repeat: no-repeat;
 background-position: 0.2em 7.3em;
}

Here's the final result. However, Internet Explorer 7 (and lower) need the following styles that you can add via conditional comments:

/* Fixes IE6 wrong percentages calculation */

* html #content {width: 69%;}

p {
 margin-bottom: 0;
 padding-bottom: 1em;
}

body {
 background-position: 0.1em 5.5em;
}

Now our theme is complete. You can download it here.

Adding W3C validation icons with JavaScript

Adding a W3C validation icon to our pages can be quite a tedious task. So why don't we add such validation icons by using JavaScript? For example, given this demo page, we have a basic Wordpress template with the following two links:

<li><a href="http://validator.w3.org/check/referer" title="This page validates as XHTML 1.0 Strict">Valid <acronym title="eXtensible HyperText Markup Language">XHTML</acronym></a></li>
   <li><a href="http://jigsaw.w3.org/css-validator/check/referer" title="This page uses valid CSS">Valid <acronym title="Cascading Style Sheets">CSS</acronym></a></li>

We want to change the content of each link with a validation icon. Here's how this could be done by using JavaScript:

function addValidationIcons () {
 var a = document.getElementsByTagName("a");
 for (var i=0; i<a.length; i++) {
  var aHref = a[i].getAttribute("href");
  if (aHref.indexOf("http://validator.w3.org/") != -1) {
   a[i].innerHTML = '<img src="../../img/valid-xhtml.png" alt="eXtensible HyperText Markup Language" />';
  } 
  
  else if (aHref.indexOf("http://jigsaw.w3.org/") != -1) {
   a[i].innerHTML = '<img src="../../img/valid-css.png" alt="Cascading Style Sheet" />';
  }
 }
}

Basically, we loop through each link on the page and if its href attribute contains either the string http://validator.w3.org/ or the string http://jigsaw.w3.org/, we change its content via the innerHTML property by setting it to an image that contains our icon. You can see the final result here.

Ajax with CSS and jQuery: using XML files

To start with Ajax and jQuery, we need a basic layout template like this. What we want to do is pretty simple: when the user clicks on the "View all my O'Reilly books" link, we fetch the book list will all the cover images and information using Ajax and jQuery.

First, we build up an XML file to store all the data we need:

<?xml version="1.0" encoding="utf-8"?>

<catalog>


 <book id="1">
 
  <title>Ajax. The definitive guide</title>
  <authors>
   <author>Anthony T. Holdener III</author>
  </authors>
  <isbn>0-596-52838-8</isbn>
  <url>http://www.oreilly.com/catalog/9780596528386</url>
 
 </book>
 
 
 <book id="2">
 
 
  <title>Ajax hacks</title>
  <authors>
   <author>Bruce W. Perry</author>
  </authors>
  <isbn>88-481-1975-1</isbn>
  <url>http://www.oreilly.com/catalog/ajaxhks</url>
 
 
 </book>
 
 
 <book id="3">
 
 
  <title>CSS cookbook</title>
  <authors>
   <author>Christopher Schmitt</author>
  </authors>
  <isbn>0-596-52741-1</isbn>
  <url>http://www.oreilly.com/catalog/cssckbk2</url>
 
 
 </book>
 
 
 <book id="4">
 
 
  <title>CSS. The definitive guide</title>
  <authors>
   <author>Eric A. Meyer</author>
  </authors>
  <isbn>88-481-1721-X</isbn>
  <url>http://www.oreilly.com/catalog/css2</url>
 
 
 </book>
 
 
 <book id="5">
 
  <title>Essential PHP security</title>
  <authors>
   <author>Chris Shiflett</author>
  </authors>
  <isbn>978-0-596-00656-3</isbn>
  <url>http://phpsecurity.org</url>
 
 
 </book>
 
 
 <book id="6">
 
  <title>Google hacks</title>
  <authors>
   <author>Tara Calishain</author>
   <author>Rael Dornfest</author>
  </authors>
  <isbn>88-8378-086-8</isbn>
  <url>http://www.oreilly.com/catalog/googlehks</url>
 
 
 
 </book>
 
 <book id="7">
 
 
  <title>Information Architecture for the World Wide Web</title>
  <authors>
   <author>Louis Rosenfeld</author>
   <author>Peter Morville</author>
  </authors>
  <isbn>88-8378-062-0</isbn>
  <url>http://www.semanticstudios.com</url>
 
 
 
 </book>
 
 
 <book id="8">
 
  <title>JavaScript: the good parts</title>
  <authors>
   <author>Douglas Crockford</author>
  </authors>
  <isbn>978-0-596-51774-8</isbn>
  <url>http://www.oreilly.com/catalog/9780596517748</url>
 
 
 </book>
 
 
 
 <book id="9">
 
  <title>JavaScript and DHTML cookbook</title>
  <authors>
   <author>Danny Goodman</author>
  </authors>
  <isbn>0-596-51408-5</isbn>
  <url>http://www.oreilly.com/catalog/9780596514082</url>
 
 
 
 </book>
 
 
 <book id="10">
 
  <title>lex and yacc</title>
  <authors>
   <author>John R. Levine</author>
   <author>Tony Mason</author>
   <author>Doug Brown</author>
  </authors>
  <isbn>1-56592-000-7</isbn>
  <url></url>
 
 
 </book>
 
 <book id="11">
 
  <title>PHP cookbook</title>
  <authors>
   <author>David Sklar</author>
   <author>Adam Trachtenberg</author>
  </authors>
  <isbn>978-0-596-10101-5</isbn>
  <url>http://www.oreilly.com/catalog/phpckbk2</url>
 
 
 </book>


 <book id="12">
 
  <title>Web database applications with PHP and MySQL</title>
  <authors>
   <author>Hugh E. Williams</author>
   <author>David Lane</author>
  </authors>
  <isbn>0-596-00543-1</isbn>
  <url>http://www.oreilly.com/catalog/webdbapps2</url>
 
 
 
 </book>
 
 
 <book id="13">
 
  <title>Programming Firefox</title>
  <authors>
   <author>Kenneth C. Feldt</author>
  </authors>
  <isbn>0-596-10243-7</isbn>
  <url>http://www.oreilly.com/catalog/9780596102432</url>
 
 
 </book>


 <book id="14">
 
  <title>Programming PHP</title>
  <authors>
   <author>Rasmus Lerdorf</author>
   <author>Kevin Tatroe</author>
   <author>Peter MacIntyre</author>
  </authors>
  <isbn>978-0-596-00681-5</isbn>
  <url>http://www.oreilly.com/catalog/progphp2</url>
 
 
 
 </book>
 
 
 <book id="15">
 
  <title>SQL in a nutshell</title>
  <authors>
   <author>Kevin E. Kline</author>
   <author>Daniel Kline</author>
   <author>Brand Hunt</author>
  </authors>
  <isbn>978-0-596-51884-4</isbn>
  <url>http://www.oreilly.com/catalog/9780596518844</url>
 
 
 </book>



 <book id="16">
 
  <title>SVG essentials</title>
  <authors>
   <author>J. David Eisenberg</author>
  </authors>
  <isbn>978-0-596-00223-7</isbn>
  <url>http://www.oreilly.com/catalog/svgess</url>
 
 
 </book>
 
 
 <book id="17">
 
  <title>XML pocket reference</title>
  <authors>
   <author>Simon St. Laurent</author>
   <author>Michael Fitzgerald</author>
  </authors>
  <isbn>978-0-596-10050-6</isbn>
  <url></url>
 
 </book>
 
 
 <book id="18">
 
  <title>XSLT</title>
  <authors>
   <author>Doug Tidwell</author>
  </authors>
  <isbn>978-0-596-52721-1</isbn>
  <url>http://www.oreilly.com/catalog/9780596527211</url>
 
 
 </book>



</catalog>

Notice how the ID of each book element corresponds to the name of each cover image. That's very important when retrieving our data. Then we create our Ajax request using jQuery:

$(document).ready(function() {
 $('p.view a:first-child').click(function() {
  $.get('http://dev.css-zibaldone.com/demos/ajax-css-jquery/js/catalog.xml', function(data) {
   $('#book-list').empty();
   $(data).find('book').each(function() {
    var $book = $(this);
     var $title = $book.find('title').text();
     var $author = $book.find('author:first-child').text();
     var $author2 = $book.find('author:first-child + author').text();
     var $isbn = $book.find('isbn').text();
     var $url = $book.find('url').text();
     var html = '<li>';
     html += '<div class="book-info">';
     html += '<h4><a href="' + $url + '">'+ $title + '</a></h4>';
     html += '<p><strong>Author(s): </strong>' + $author + ' ' +  $author2 + '</p>';
     html += '<p><strong>ISBN: </strong>' + $isbn + '</p>';
     html += '</div>';
     html += '<img src="../../img/cover/' + $book.attr('id') + '.gif" alt="Cover" />';
     html += '</li>';
     $('#book-list').append($(html));
   
   });
  });
 return false;
 });
});

Our CSS styles for the book list are pretty simple:

/* Book gallery */

p.view {
 width: 100%;
 background: transparent url("img/view.png") no-repeat 0 0;
 text-indent: 1.6em;
}

ul#book-list {
 margin: 1em 0;
 padding: 0.3em 0 0 0;
 border-top: 1px dashed #aaa;
 list-style: none;
 width: 100%;
}
ul#book-list li {
 overflow: hidden;
 height: 100%;
 margin-bottom: 0.5em;
 padding-bottom: 0.3em;
 border-bottom: 1px dashed #aaa;
}

div.book-info {
 float: right;
 width: 60%;
 margin: 0;
}

div.book-info h4,
div.book-info p {
 font-size: 1em;
 margin: 0;
}

div.book-info h4 {
 border-bottom: 1px dashed;
}
div.book-info h4 a:link,
div.book-info h4 a:visited,
div.book-info h4 a:hover {
 text-decoration: none;
}

div.book-info p {
 padding: 0.3em 0;
}
div.book-info p strong {
 background: #900;
 color: #fff;
 padding: 0 0.2em;
 margin-right: 0.3em;
}

ul#book-list li img {
 display: block;
 float: left;
 width: 39%;
 margin: 0;
}

You can see the final result here. Notice how we've used the jQuery $.get() method to fetch our XML file. Then we've retrieved all data by using the find() method. Very simple!

jQuery and XML namespaces

The question that led me to this post was: how can I manage complex XML namespaces using jQuery? Fortunately, I found this article by IBM where everything is explained in greater details. To be honest, I don't see the point in writing more here, because this article is really exhaustive. Instead, when I'll have more spare time, I'm going to test something. The article is also available in PDF format and you can download all the examples too. Hope that helps.

An XML blog with CSS and XSLT

In order to create a blog in XML, we need a basic XML template. Here's a possible template inspired by Wordpress:

<?xml version="1.0" encoding="utf-8" ?>

<document>

 <page>


  <headerimg>
  
   <h1>XML blog</h1>
   <description>a Wordpress blog</description>
 
 
  </headerimg>
  
  <content>
  
   <post>
   
    <h2>Story Heading</h2>
    <date>April 3, 2009</date>
    
    <entry>
    
     <p>
     </p>
     
     <postmetadata>Posted in <link url="#">Category</link> | <link url="#">Comment »</link></postmetadata>
    
    </entry>
   
   </post>
  
  </content>
  
  <sidebar>
  
   <h2>Archives</h2>
   
   <ulist>
    <item><link url="#">April 2009</link></item>
    <item><link url="#">March 2009</link></item>
   </ulist>
   
   <h2>Categories</h2>
   
   <ulist>
    <item><link url="#">category 1</link> (3)</item>
    <item><link url="#">category 2</link> (7)</item>  
    <item><link url="#">category 3</link> (5)</item>
   </ulist>
   
   <h2>Meta</h2>
   
   <ulist>
   
    <item><link url="#">XML</link></item>
    <item><link url="#">Wordpress</link></item>
   
   </ulist>
   
  
  </sidebar>
  
  <footer>
  
   Gabriele Romanato
  
  </footer>


 </page>


</document>

As you can see here, our document is without any style information attached to it. The first thing we're going to do is to use XSLT to transform the XML structure into an HTML one. To accomplish this task, first we need to link an XSLT stylesheet to our document:

<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet href="../xsl/style-1.xsl" type="text/xsl"?>

Then we need to define our stylesheet:

<?xml version="1.0" encoding="utf-8" ?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


 <xsl:output method="html"
 doctype-public="-//W3C//DTD HTML 4.01//EN" 
 doctype-system="http://www.w3.org/TR/html4/strict.dtd"/>
 
 
 <xsl:template match="/">
 
  <html>
  
   <head>
    <title>XML Blog</title>
   </head>
   
   <body>
   
    <xsl:apply-templates />
   </body>
  </html>
 
 
 </xsl:template>
 
 <xsl:template match="page">
 
  <div id="page">
  
   <xsl:apply-templates/>
  </div>
 
 
 </xsl:template>
 
 <xsl:template match="headerimg">
 
  <div id="headerimg">
  
   <xsl:apply-templates/>
  
  </div>
 
 
 </xsl:template>
 
 <xsl:template match="h1">
 
  <h1>
   <xsl:value-of select="."/>
  </h1>
 
 
 </xsl:template>
 
 <xsl:template match="description">
 
  <div class="description">
   <xsl:value-of select="."/>
  </div>
 
 
 </xsl:template>
 
 <xsl:template match="content">
 
  <div id="content">
   <xsl:apply-templates />
  </div>
 </xsl:template>
 
 <xsl:template match="post">
 
  <div class="post">
   <xsl:apply-templates/>
  </div>
 </xsl:template>
 
 <xsl:template match="h2">
  <h2>
   <xsl:value-of select="."/>
  </h2>
 </xsl:template>
 
 <xsl:template match="date">
  <small>
   <xsl:value-of select="."/>
  </small>
 </xsl:template>
 
 <xsl:template match="entry">
  <div class="entry">
   <xsl:apply-templates/>
  </div>
 </xsl:template>
 
 <xsl:template match="p">
 
  <p>
   <xsl:value-of select="."/>
  </p>
 
 
 </xsl:template>
 
 <xsl:template match="postmetadata">
 
  <p class="postmetadata">
  
   
   <xsl:apply-templates />
  </p>
 
 
 </xsl:template>
 
 <xsl:template match="link">
  <a href="{@url}">
   <xsl:value-of select="."/>
  </a>
 </xsl:template>
 
 <xsl:template match="sidebar">
 
  <div id="sidebar">
   <form action="#" method="get" id="searchform">
    <div>
     <input type="text" name="s" id="s" />
     <input type="submit" name="searchsubmit" id="searchsubmit" value="Search" />
    </div>
   </form>
   
   <xsl:apply-templates/>
  </div>
 
 </xsl:template>
 
 <xsl:template match="ulist">
 
  <ul>
   <xsl:for-each select="item">
    <li>
     <xsl:apply-templates/>
    </li>
   </xsl:for-each>
  </ul>
 
 </xsl:template>
 
 <xsl:template match="footer">
 
  <div id="footer">
  
   <xsl:apply-templates />
  </div>
 
 </xsl:template>
 
</xsl:stylesheet>

As you can see here, our blog begins to take shape. By turning the XML structure into an HTML one, we can now add some CSS styles to our document. Our CSS file would look like this:

/* General styles */

body {
 margin: 0;
 padding: 0;
 background: #fff;
 color: #333;
 font: 76% Verdana, sans-serif;
}

a:link, a:visited {
 color: #0a0;
}
a:hover {
 color: #393;
}

p, li {
 line-height: 1.5;
}

h1, h2 {
 font-family: "Trebuchet MS", Trebuchet, sans-serif;
 color: #0a0;
}

/* Structure */

#page {
 width: 85%;
 margin: 0 auto;
 padding: 2em 0;
}

#headerimg {
 width: 100%;
 height: 8.3em;
 min-height: 100px;
 background: transparent url("../img/header.png") repeat-x 0 0;
}
#headerimg h1 {
 margin: 0;
 padding: 8px 5px 5px 0;
 text-align: center;
 font-size: 3.5em;
}
#headerimg .description {
 padding: 0 5px 5px 0;
 text-align: center;
 font-style: italic;
 color: #393;
}

#content {
 width: 70%;
 float: right;
}

#sidebar {
 width: 29%;
 float: left;
 padding-bottom: 120px;
 background: transparent url("../img/sidebar.png") no-repeat 0 100%;
}

.post {
 width: 90%;
 margin: 0 auto;
}
.post h2 {
 margin: 0 0 0.2em 0;
 font-size: 1.6em;
 padding-bottom: 2px;
 padding-top: 6px;
 border-bottom: 1px dashed;
 background: transparent url("../img/h2.png") no-repeat 100% 50%;
}
.post small {
 display: block;
 padding: 0.2em;
 background: #efc;
}

.entry {
 width: 100%;
}

.entry .postmetadata {
 border-top: 1px dashed #393;
 border-bottom: 1px dashed #393;
 padding: 0.2em 0;
}

#searchform {
 margin: 0;
 padding-top: 9px;
 width: 100%;
}
 
#searchform #s {
 width: 100px;
 border: 1px solid #393;
 background: #fff;
 margin-right: 0.3em;
}

#searchform #searchsubmit {
 background: #393;
 font-weight: bold;
 color: #fff;
}

#sidebar h2 {
 margin: 7px 0;
 padding: 3px;
 background: #393;
 color: #fff;
}

#sidebar ul {
 margin: 5px 0;
 padding: 0 0 0 3px;
 list-style: none;
}

#sidebar li {
 padding-bottom: 3px;
 padding-left: 1.3em; 
 margin-bottom: 0.3em;
 border-bottom: 1px dashed #393;
 background: transparent url("../img/li.png") no-repeat 0 0.3em;
}
#sidebar li:hover {
 background-image: url("../img/lihover.png");
}

#footer {
 clear: both;
 width: 100%;
 background: #efc;
 padding: 2em 0;
 text-align: center;
 color: #393;
}

In order to attach our CSS file to the XML document, we need to modify our XSLT stylesheet like so:

<xsl:template match="/">
 
  <html>
  
   <head>
    <title>XML Blog</title>
    <link rel="stylesheet" href="../css/style.css" type="text/css" media="screen" />
   </head>
   
   <body>
   
    <xsl:apply-templates />
   </body>
  </html>
 
 
 </xsl:template>

In the code above, we've inserted a link element in the main xsl:template element. Now our XML document will be stylized according to the CSS rules specified earlier in the post. You can see the final result here.

Be quick or be dead: is Firefox falling?

Tipping Firefox across the chasm is an excellent post written more than five years ago. In this post, the author analyzes the rising of Firefox in the browser market share, listing some of the causes that made this possible. However, there's one point that actually is worth of mentioning: performance. In fact, Firefox is not considered under this aspect but only as an alternative to the obsolete Internet Explorer 6. Time changes everything. After five years, new browsers have been released, and a key aspect that now seems to be on the top of any browser wish list is actually performance. Take Chrome for example: it's fast, maybe it's one of the fastest browser on the market. Safari is fast too, just as Opera. Internet Explorer is just filling (or try to fill) the gap with the next release (9). And Firefox? Actually, it's much slower than Chrome, Opera and Safari. But why performance? Because in the meantime users got faster connections, so they want to see fast responses when they surf the web. A website must load in a snapshot. Period. I know that this is utopia from a mere point of view of a web developer, but the success of a browser is often determined by its users who, of course, are non-developers if they're considered as simple percentages. In other words, simple users can effectively push a browser on top or, conversely, let it falling down to minority. This is something that Firefox developers must seriously take into account. In simple words: be quick or be dead.

XML attributes and Ajax performance

Although XML is not the fastest data exchange format in use with Ajax, there are a couple of gotchas that we have to bear in mind when parsing XML documents. For example, given the following XML document:

<?xml version="1.0" encoding="utf-8"?>

<contacts>
  <contact>
    <name>Gabriele</name>
    <email>gabriele.romanato@gmail.com</email>
  </contact>
  <!--more-->
</contacts>

In order to properly parse a document like this, we should write something like:

var contacts = root.getElementsByTagName('contact');

for (var i=0; i<contacts.length; i++) {
  var name = contacts[i].getElementsByTagName('name')[0].firstChild.nodeValue;
  var email = contacts[i].getElementsByTagName('email')[0].firstChild.nodeValue;
}

This may turn out to be very expensive, because every time you need to access a child element and its contents you have to perform the same tasks. What if there are several different XML element names? Simply put, performance will suffer. Instead, we can use XML attributes to minimize the impact of the DOM access:

<?xml version="1.0" encoding="utf-8"?>
<contacts>
  <contact name="Gabriele" email="gabriele.romanato@gmail.com" />
  <!--more-->
</contacts>

So we could write something like this:

var contacts = root.getElementsByTagName('contact');
for(var i=0; i<contacts.length; i++) {
  var name = contacts[i].getAttribute('name');
  var email = contacts[i].getAttribute('email');
}

The second version of our JavaScript code is much shorter and shows a significant reduction of calls to DOM methods. By doing so, the overall performance of our code will be much better.

Styling breadcrumbs with CSS

Styling breadcrumbs (that is, breadcrumbs navigation) with CSS is not so difficult as it could seem at first glance, provided that we bear in mind semantics while building up our base markup. The best choice, in fact, is to use nested unordered lists in order to keep the directory hierarchy intact. Here's how our markup would look like:

<ul id="breadcrumbs"><li class="first-level"><a href="#">Home</a><ul><li class="second-level"><a href="#">Articles</a><ul><li class="last"><strong>Current location</strong></li></ul></li></ul></li></ul>

Why am I writing all the markup on a single line? It's just to prevent Internet Explorer 6 from applying some of its weird calculations of white-space among the various list elements. Notice how I also added some classes in order to apply different styles on each breadcrumb level. In this case, I'm willing to apply only a single background image, but in an ideal scenario you could apply different background images on each level. Here's the CSS:

/* Basic breadcrumbs formatting */

#breadcrumbs {
 margin: 0;
 padding: 0;
 list-style: none;
    height: 1.3em;
 border-bottom: 1px solid #666;
 line-height: 1.3em;
}

#breadcrumbs li ul, #breadcrumbs li {
 display: inline;
 margin: 0;
 padding: 0;
}


/* Add a background image */

#breadcrumbs li.first-level a,
#breadcrumbs li.second-level a {
 margin: 0 0.5em 0 0;
 background: transparent url("arrow.png") no-repeat 100% 0.3em;
 padding-right: 13px;
}



#breadcrumbs li.last {
 border-width: 1px 1px 0 1px;
 border-style: solid;
 border-color: #666;
 background: #fff;
 padding: 0 0.3em;
 position: relative;
 top: 2px;
}

We've turned every block level and list-item element (ul, li) into an inline element so that our items will appear on a single row. Then we've added a background image to each link. However, Internet Explorer 6 and 7 need the following code:

<!--[if lt IE 8]>
<style type="text/css" media="screen">

#breadcrumbs li.last {
 position: relative;
 top: 1px;
}
</style>
<![endif]-->

You can see the final result here.

jQuery form validator example

A form validator with jQuery is an useful coding exercise. Let's start with a basic form like this:

<form action="#" method="post" enctype="multipart/form-data">

<ul>
 <li id="for-name"><label for="name">First Name:</label>
 <input type="text" name="name" id="name" />
 </li>
 <li id="for-last"><label for="last">Last Name:</label>
 <input type="text" name="last" id="last" />
 </li>
 <li id="for-email"><label for="email">Email:</label>
 <input type="text" name="email" id="email" /></li>
 <li id="for-subject"><label for="subject">Subject:</label>
 <input type="text" name="subject" id="subject" />
 </li>
 <li id="for-url"><label for="url">URL:</label>
 <input type="text" name="url" id="url" />
 </li>
 <li id="for-message"><label for="message">Message:</label>
 <textarea id="message" name="message" cols="25" rows="15"></textarea>
 </li>
</ul>

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

What we need is:

  1. a base form validation class that we'll call jVal
  2. a script that implements this base class.

Let's start with the base class:

function jVal() {
    this.message = function (element, klass, message, position) {
 position = position || "after";
        element = $(element);
 if(arguments[3] == null) {
     arguments[3] = "after";
 }
 if(arguments[3] == "after") {
     $('<div></div>').addClass(klass).html(message).insertAfter(element);
 } else if(arguments[3] == "before") {
     $('<div></div>').addClass(klass).html(message).insertBefore(element);
 }
 
 
    }
    
    this.reg = function (re, element) {
        re = new RegExp(re);
 element = $(element).val();
 return re.test(element);
    }
    
    this.regi = function (re, element) {
 re = new RegExp(re, "i");
 element = $(element).val();
 return re.test(element);
    }
    
    this.is_empty = function(element) {
        element = $(element).val();
 var re = /.+/;
 if(element.length == 0 || element == '' ||
    !re.test(element)) {
    return true;
 } else {
   return false;
 }
    }
    
    this.specialchars = function(element) {
        element = $(element).val();
 if(element.indexOf(">") != -1 || element.indexOf(">") != -1 ||
    element.indexOf("\\") != -1) {
      return true;
 } else {
      return false;
 }
    }
    
    this.parse_url = function (element) {
        element = $(element).val();
 var re = /^https?:\/\/([a-z0-9]+\.)+[a-z0-9]{2,7}.*$/;
 return re.test(element);
    }

This class has only a few basic methods as its members, because it's only for a demonstrative purpose. The actual validation process is dispatched to the script that will implement it, which is as follows:

var validateForm = function () {
  var F = new jVal();

  var valid;
  if(!F.reg("^[a-zA-Z]{2,20}$", '#name')) {
     F.message('#name', 'error', 'This field must contain only letters and cannot be less than 2 characters.');
     valid = false;
  }
  if(!F.reg("^[a-zA-Z]{2,20}$", '#last')) {
     F.message('#last', 'error', 'This field must contain only letters and cannot be less than 2 characters.', 'before');
     valid = false;
  }
  
  if(!F.regi("^[a-z-0-9_+.-]+\\@([a-z0-9-]+\\.)+[a-z0-9]{2,7}$", '#email')) {
      F.message('#email', 'error', 'This is not a valid email address.');
      valid = false;
  }
  
  if(F.reg("<|>|&|\\$|%|\\/|\\*|@|#|\\|", '#subject')|| F.is_empty('#subject')) {
      F.message('#subject', 'error', 'This field cannot contain special characters or be empty.', 'before');
      valid = false;
  }

  if(!F.parse_url('#url')) {
      F.message('#url', 'error', 'This is not a valid URL.');
      valid = false;
  }
      
   
  if(F.specialchars('#message') || F.is_empty('#message')) {
      F.message('#message', 'error', 'This field cannot contain special characters or be empty.', 'before');
      valid = false;
  
  }
  
  
  return valid;
  
  
  
}

$(document).ready(function() {
    $('form[method=post]').submit(validateForm);
});

As you can see, the above function checks only if all the field values are in the correct format. If not, it show an error message on each field and prevent the form from being submitted. You can see the final result here.

W3C CSS Test suite: suggestions for improvements

There are a couple of problems related to the handling of tests in the W3C CSS Test Suite that I'd like to outline here, providing also some hints and suggestions about how to solve them.

  1. Lack of a CMS

    Basically, every contributor must upload his/her files through SVN. After uploading them, an email is sent to the maintainer of the suite with all the details of the upload or the changes to an existing file. Further, the maintainer must review the file, modify it, and finally flag it as approved. This is a really long and tedious task. If the CSS Test Suite used a CMS, things would be a lot faster, because:

    1. the CMS would provide the basic template to build a test case, allowing the contributor to edit it as it sees fit; then the template would be saved as a static file with a given URL, so that it can be further accessed, modified, moved or even deleted
    2. the CMS would automatically detect ill-formed markup and the like
    3. the CMS would allow the contributor to choose between all the additional files approved by the CSS Test Suite guidelines
    4. the CMS would mark the test case as pending, email the maintainer with a link to review the test file
    5. the CMS would allow the maintainer to keep all files and directories more organized
  2. Lack of references to each section of the specifications

    As it's today, the W3C CSS Test Suite guidelines don't provide direct links to each section of the CSS specifications, simply because they give only generic information about how to build a test case. It would be better, instead, to provide a classification of the possible test cases by splitting them into categories (e.g. fonts, syntax, etc.) and insert a direct link to each chapter of the specifications for a given category.

Interview with Molly Holzschlag

I asked some questions to Molly Holzschlag. Here is the interview.

  1. What's your work at Opera Software?

    My work at Opera Software is with the Developer Relations team - we work to evangelize web standards and emerging technologies.

  2. Opera is surely one of the most standard-compliant browsers on the web. Do you think it's really hard to be standard-compliant for a browser?

    Yes, to be standards compliant means to try and compete in a world where most sites and applications were built with the best options of the day - which means they weren't always standards-oriented.

  3. The W3C promotes interoperability between user-agents. Do you think that interoperability is a necessary requirement?

    I believe interoperability it the first and foremost requirement. It is the essence of the Web.

  4. You're also member of the WaSP. What are today the main goals of this association?

    I left WaSP a few years ago to work directly with browser companies. First Microsoft as a consultant, and now cozy at home with Opera as an employee. I could no longer be a leader at WaSP while taking money from browser vendors. A clear conflict of interest. So I left the group, although I am considered "Emerita" and I'm very proud of that. Today, the main goals of the association is education and global awareness via InterACT and global bridges for translations.

  5. W3C specifications are sometimes hard to understand for web developers (as it's often been said). Do you think that it would be necessary to write some guidelines that explains what every single specification is meant to or, alternatively, a guide for every specification?

    Yes, I am absolutely certain that an outreach to from the W3C to "in-the-wild" designers and developers is necessary for the survival of our entire industry. The separation is detrimental. We very much need to "Mind The Gap"

  6. Finally, you're one of the most influent women on the web. What do you think the role of women is in today web?

    Women, men, everyone of any identity has something to contribute to the Web. Why? Because the Web is essentially human. Whatever we are will be made manifest in the Web. Our beauty, our hatred, our goodness, our cruelty, our confusion, our clarity, our wars and our ultimate peace.

Fluid CSS tabs

CSS tabs are better when they're fluid, because they can scale along with text and that's an important thing. Let's start with a basic structure like this:

<ul id="navigation">
 
  <li id="current"><strong>Home</strong></li>
  <li><a href="#">Articles</a></li>
  <li><a href="#">Test</a></li>
  <li><a href="#">Blog</a></li>
  <li><a href="#">About</a></li>
 
</ul>

Here you can see our basic structure. Now it's time to start adding some styles:

/* Tabs */

#navigation {
 margin: 0;
 padding: 0;
 height: 1.6em;
 list-style: none;
 border-bottom: 1px solid #0c0;
}

#navigation li {
 float: left;
 height: 100%;
 margin-right: 0.4em;
 background: #0c0 url("../img/topleft.png") no-repeat 0 0;
}

#navigation a:link,
#navigation a:visited,
#navigation strong {
 float: left;
 font-weight: bold;
 height: 100%;
 line-height: 1.6;
 padding: 0 0.5em;
 background: transparent url("../img/topright.png") no-repeat 100% 0;
 color: #fff;
}

#navigation strong {
 text-transform: uppercase;
}

This page shows the results we've got so far. As you can see, tabs have no explicit width declaration so that they can scale along with text. Now it's time to finish our work:

/* Hover effect */

#navigation li:hover {
 background: #24df00 url("../img/toplefthover.png") no-repeat 0 0;
}
#navigation a:hover {
 background-image: url("../img/toprighthover.png");
 background-position: 100% 0;
 background-repeat: no-repeat;
}
#navigation li#current:hover {
 background: #0c0 url("../img/topleft.png") no-repeat 0 0;
}

In this page, we've simply added an effect on hover by using the :hover pseudo-class on li elements. However, since Internet Explorer 6 supports this pseudo-class only on links, we have to use a couple of JavaScript lines to make it work:

function addHoverLi () {
 var navigation = document.getElementById("navigation");
 var li = navigation.getElementsByTagName("li");
 for (var i=0; i<li.length; i++) {
  if(!li[i].getAttribute("id")) {
  
  
   li[i].onmouseover = function () {
    this.style.background = "#24df00 url('../img/toplefthover.png') no-repeat 0 0";
   };
   li[i].onmouseout = function () {
    this.style.background = "#0c0 url('../img/topleft.png') no-repeat 0 0";
   }; 
  }
 }
}

window.onload = addHoverLi;

You can see the results here. As you can see, the achieved result is flexible, fluid and cross-browser.

jQuery form validation

We start with a basic form like this:

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

<fieldset>

<legend>Contact information</legend>

<ul>

<li>
 <label for="name">Name:</label>
 <input type="text" name="name" id="name" />
</li>

<li>
 <label for="surname">Surname:</label>
 <input type="text" name="surname" id="surname" />
</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 id="message" name="message" cols="30" rows="15"></textarea>
</li>


</ul>


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

</fieldset>


</form>

Then we add some basic styles, just to stylize the form a little bit:

body {
 background: #fff;
 color: #333;
 font: 76% Verdana, sans-serif;
}

form {
 margin: 1em 0 0 2em;
 width: 50%;
}

fieldset {
 margin: 0;
 border: 1px solid #ccc;
 padding-bottom: 1em;
}

legend {
 font-weight: bold;
 text-transform: uppercase;
}

fieldset ul {
 margin: 0 auto;
 padding: 0.5em 0;
 width: 90%;
 list-style: none;
}

fieldset ul li {
 overflow: hidden;
 height: 100%;
 padding: 4px 0;
}

label {
 float: left;
 width: 5em;
 padding-right: 0.3em;
 font-weight: bold;
}

input {
 font: 1em Verdana, sans-serif;
}

fieldset ul li input {
 float: left;
 width: 120px;
 border: 1px solid #ccc;
}

textarea {
 width: 300px;
 height: 200px;
 border: 1px solid #ccc;
 font: 1em Verdana, sans-serif;
}

form p {
 margin: 0;
 padding: 0.4em 0 0 7em;
}

form p input {
 background: #666;
 color: #fff;
 font-weight: bold;
}

You can see this basic page here. After setting our base template, we can start to add a little more interaction by providing a simple JavaScript function that will handle the form processing (of course we're doing it with JavaScript only for demonstrative purpose). Before this, we need to add some styles to our stylesheet:

/* JavaScript styles */

ol#data {
 margin: 1em 0;
 padding: 0.3em;
 background: #e7e7e7;
 border: 1px solid #666;
 list-style: none;
}

ol#data li {
 margin: 0.3em 0;
 padding: 3px;
 background: #fff;
}

ol#data li strong {
 display: block;
}
ol#data li p {
 margin-top: 0;
 padding: 0;
}


Then we can write our little script:

function process() {
 var name = $('#name').val();
 var surname = $('#surname').val();
 var email = $('#email').val();
 var subject = $('#subject').val();
 var message = $('#message').val();
 
 var $ol = $('<ol id="data"></ol>').appendTo('form[method=post]');
 $ol.html('<li><strong>Name:</strong><p> ' + name + '</p></li>' +
       '<li><strong>Surname:</strong><p> ' + surname + '</p></li>' + 
       '<li><strong>Email:</strong><p> ' + email + '</p></li>'
        + '<li><strong>Subject:</strong><p> ' + subject + '</p></li>' + 
        '<li><strong>Message:</strong><p>' +
        message + '</p></li>');
}


$(document).ready(function () {
 $('form[method=post]').attr('action', 'javascript:process()');
});

You can see the page in action here. Notice that we're not validating the form yet. First, we need to add a couple of styles to our CSS:

div.error {
 clear: left;
 margin-left: 5.3em;
 color: red;
 background: transparent url("../../img/error.png") no-repeat 100% 0;
 padding-right: 1.3em;
 height: 100%;
 padding-bottom: 0.3em;
 line-height: 1.3;
}

.input-error {
 background: #ff9;
 border: 1px solid red;
}


div.warning {
 clear: left;
 margin-left: 5.3em;
 color: #338;
 background: transparent url("../../img/warning.png") no-repeat 100% 0;
 padding-right: 1.3em;
 height: 100%;
 padding-bottom: 0.3em;
 line-height: 1.3;
}

Then we can write our validation routines with jQuery:

var validateForm = function(){
 var $name = $('#name').val(); 
 var $nameRe = /^[a-zA-Z]{2,20}$/;
 if(!$nameRe.test($name)) {
   
  handleError('#name', 'The name field must contain only letters and cannot be less than 2 characters.');
 
   
 }
 
 var $surname = $('#surname').val();
 var $surnameRe = /^[a-zA-Z]{3,20}$/;
 if(!$surnameRe.test($surname)) {
  
  handleError('#surname', 'The surname field must contain only letters and cannot be less than 3 characters.');
   
   
 } 
  
 
 var $email = $('#email').val();
 var $emailRe = /^[a-z-0-9_+.-]+\@([a-z0-9-]+\.)+[a-z0-9]{2,7}$/i;
 if(!$emailRe.test($email)) {
   
  handleError('#email', 'This is not a valid email address.');
   
 }

 var $subject = $('#subject').val();
 var $subjectRe = /^\s+|<|>|"|\$|&|\/|'|\*|#|@|\\|\.\.|\./;
 if($subject.length == 0 || $subjectRe.test($subject)) {
   
  handleError('#subject', 'The subject field cannot be empty or contain special characters.');
 }
  
 var $message = $('#message').val();
 var $messageRe = /^\s+$/;
 if($message.length == 0 || $messageRe.test($message)) {
   
  handleError('#message', 'The message field cannot be empty.');
 }
  
 if($nameRe.test($name) && 
  $surnameRe.test($surname) && 
  $emailRe.test($email) &&
  $subject.length > 0 &&
  !$subjectRe.test($subject) &&
  $message.length > 0 &&
  !$messageRe.test($message)) {
   return true;
  } else {
   return false;
 }
  
}

function handleError(element, message) {
 element = $(element);
 element.addClass('input-error');
 var $li = element.parent('li');
 var error = $('<div class="error"></div>').text(message);
 error.appendTo($li);
 $(element).keyup(function() {
  $(error).fadeOut(1000, function() {
    $(element).removeClass('input-error');
  });
 });
 
}

function handleWarning(element, message) {
 element = $(element);
 var $li = element.parent('li');
 var warning = $('<div class="warning"></div>').text(message);
 warning.appendTo($li);
}
   


$(document).ready(function() {
 $('form[method=post] :input').each(function() {
  var $input = $(this);
  $input.focus(function() {
  if($('div.error').size()) {return;}
  if($input.attr('id') == "name") {
   handleWarning($input, 'The name field must contain only letters and cannot be less than 2 characters.');
  } else if($input.attr('id') == "surname") {
   handleWarning($input, 'The surname field must contain only letters and cannot be less than 3 characters.');
  } else if($input.attr('id') == "email") {
   handleWarning($input, 'Enter a valid email address, such as name@example.com.');
  } else if($input.attr('id') == "subject") {
   handleWarning($input, 'The subject field cannot be empty or contain special characters.');
  } else if($input.attr('id') == "message") {
   handleWarning($input, 'The message field cannot be empty.');
  }
 });
 $input.blur(function() {
  $('div.warning').fadeOut(1000);
 });
});
 $('form[method=post]').submit(validateForm);
 
});

The above routines perform the following tasks:

  • create error and warning messages
  • create a routine to handle errors
  • create a routine to handle warnings
  • validate user input

You can see the live demo here. Optionally, we could add even more validation routines, but I think that for the sake of simplicity the aforementioned ones will suffice.

Bleach: a new Python library

James Socol has released Bleach, a new Python library. As he says:

We’ve released another Python library: Bleach, for sanitizing HTML and automatically linking URLs in text, that we’re using on addons.mozilla.org and support.mozilla.com. It’s based on html5lib, which we chose because of its foundation in web standards and its active development community. Bleach is available on Github and PyPI.

Bleach uses a tree-walking approach to automatically link URLs that I think is pretty interesting. I wrote a short post outlining the method.

You can find more info at http://blog.mozilla.com/webdev/2010/02/25/new-python-library-bleach/.

jQuery and CSS: column order

Column order with CSS has been an hot topic for quite a while. Basically, with CSS we can modify the source code order either with relative positioning or with negative margins. Anyway, this involves some tedious calculations in order to get the desired result. So why should we not make life easier by using just some lines of jQuery code?

Let's start with a simple three-columns layout with header and footer:

body, h1, h2, p {
 margin: 0;
 padding: 0;
}

body {
 background: #fff;
 color: #333;
 font: 76% Arial, Helvetica, sans-serif;
}

h1 {
 font-size: 2em;
}

h2 {
 font-size: 1.6em;
}

p {
 padding: 0.4em 0;
 line-height: 1.5;
}

#site {
 margin: 0 auto;
 width: 76%;
 padding: 2em 0;
 overflow: auto;
 height: 100%;
}

#header {
 border-bottom: 2px solid #ccc;
 padding-bottom: 0.2em;
 width: 100%;
}

#content, #sidebar, #extra {
 float: left;
 margin: 0;
 padding-top: 0.3em;
}

#content {
 width: 49%;
 background: #ffc;
}

#sidebar, #extra {
 width: 25%;
}

#sidebar {
 background: #cff;
}

#extra {
 background: #def;
}

#footer {
 clear: both;
 padding: 0.2em 0;
 border-top: 2px solid #ccc;
 width: 100%;
}

View the live demo

So far so good. Now we want to modify the column order with jQuery. Here's how this could be done:

$(document).ready(function() {

    var $content = $('#content').clone();
    $('#content').remove();
    $content.insertAfter('#sidebar');


});

View the live demo

First, we've cloned the first column in source, then we've removed it and finally we've inserted it just after the second column in source, so that now the first column is placed just in the middle of our layout as the central column. Do more with less!

CSS complex forms

Complex forms with CSS can be quite difficult to stylize because of the many existing discrepancies across browsers. Let's say that we want to stylize a form for ordering books. We could start with a markup like this:

<div id="order">
<h2>Order your books</h2>
<form action="#" method="post">


<table summary="Order: copies, code, title, price">

<tr>
    <th scope="col">Copies</th>
    <th scope="col">Code</th>
    <th scope="col">Title</th>
    <th scope="col">Price</th>
</tr>

<tr>
    <td><input type="text" name="copy1" id="copy1" /></td>
    <td><input type="text" name="code1" id="code1" /></td>
    <td><input type="text" name="title1" id="title1" /></td>
    <td><input type="text" name="price1" id="price1" /></td>
</tr>


<tr>
    <td><input type="text" name="copy2" id="copy2" /></td>
    <td><input type="text" name="code2" id="code2" /></td>
    <td><input type="text" name="title2" id="title2" /></td>
    <td><input type="text" name="price2" id="price2" /></td>
</tr>



<tr>
    <td><input type="text" name="copy3" id="copy3" /></td>
    <td><input type="text" name="code3" id="code3" /></td>
    <td><input type="text" name="title3" id="title3" /></td>
    <td><input type="text" name="price3" id="price3" /></td>
</tr>

<tr>
    <td><input type="text" name="copy4" id="copy4" /></td>
    <td><input type="text" name="code4" id="code4" /></td>
    <td><input type="text" name="title4" id="title4" /></td>
    <td><input type="text" name="price4" id="price4" /></td>
</tr>




</table>


<fieldset>
<legend>Payment method</legend>

<ul>
    <li>
        <label for="cod">COD</label>
        <input type="checkbox" name="cod" id="cod" value="cod" />
    </li>
    <li>
        <label for="visa">VISA</label>
        <input type="checkbox" name="visa" id="visa" value="visa" />
    </li>
    <li>
        <label for="american-express">American Express</label>
        <input type="checkbox" name="american-express" id="american-express" value="american-express" />
    </li>
    <li>
        <label for="master-card">Master Card</label>
        <input type="checkbox" name="master-card" id="master-card" value="master-card" />
    </li>
    
</ul>

<div class="footer">

    <div class="left">
    
        <label for="cc-number">N.</label>
        <input type="text" name="cc-number" id="cc-number" />
    
    </div>
    
    <div class="right">
    
         <label for="cc-expires">Expires</label>
         <input type="text" name="cc-expires" id="cc-expires" />
    
    
    </div>


</div>

</fieldset>

<ul class="customer-info">

    <li>
         <label for="name">Name</label>
        <input type="text" name="name" id="name" />
        <label for="address">Address</label>
        <input type="text" name="address" id="address" />
    </li>
    
    
    
    <li>
         <label for="city">City</label>
        <input type="text" name="city" id="city" />
        <label for="state">State</label>
        <input type="text" name="state" id="state" />
    </li>
    
    
    <li>
         <label for="phone">Phone</label>
        <input type="text" name="phone" id="phone" />
        <label for="email">Email</label>
        <input type="text" name="email" id="email" />
    </li>
    
    


</ul>


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




</form>
</div>

Why a table? It's quite simple to understand: in this form, data are organized in name/field pairs (name, title, price, etc.), so the most semantical way to mark up this is using a table. Of course not all data is contained within a table, so this is another issue to take into account. Here's our CSS styles:

/* General styles */

body, h2, form, fieldset, table, th, td, ul, p, legend {
 margin: 0;
 padding: 0;
 border: none;
 list-style: none;
 color: #333;
}


body {
 background: #fff;
 color: #333;
 font: 76% Arial, Helvetica, sans-serif;
}

h2 {
 font-size: 1.6em;
 font-weight: normal;
 color: #666;
}

/* Give input elements a consistent dimension */

input {
 font: 1em Arial, Helvetica, sans-serif;
}


/* Styling the main container */


#order {
 width: 700px;
 margin: 2em auto;
 padding: 8px 6px;
}

/* Styling the form element just for IE6/7 */

form {
 height: 100%;  /* http://www.satzansatz.de/cssd/onhavinglayout.html */
}

/* Styling the main title */

h2 {
 text-align: center;
 text-transform: uppercase;
}

/* Styling the table for order details */

form table {
 width: 100%;
 padding: 6px 0;
 border-spacing: 0;
 border-collapse: collapse;
 margin-bottom: 0.5em;
}

form table th {
 text-align: left;
 font-weight: normal;
}

form table td {
 padding-bottom: 3px;
}

form table td input {
 border: 1px solid #ccc;
 display: block;
 margin-right: 4px;
}

form table td #copy1,
form table td #copy2,
form table td #copy3,
form table td #copy4,
form table td #price1,
form table td #price2,
form table td #price3,
form table td #price4 {
 width: 50px;
}


form table td #code1,
form table td #code2,
form table td #code3,
form table td #code4 {
 width: 70px;
}

form table td #title1,
form table td #title2,
form table td #title3,
form table td #title4 {
 width: 505px;
}


/* Payment method: fieldset and its children */

fieldset legend {
 font-weight: bold;
 padding-bottom: 5px;
}

fieldset ul {
 width: 100%;
 height: 100%;
 overflow: hidden;
}

fieldset ul li {
 float: left;
 width: 172px;
 margin: 0;
}

fieldset ul li label {
 font-weight: bold;
 vertical-align: middle;
}

fieldset ul li input {
 vertical-align: middle;
}


fieldset div.footer {
 width: 100%;
 padding: 10px 0 20px 0;
 height: 100%;
 overflow: hidden;
}

fieldset div.footer div.left {
 float: left;
 width: 200px;
 margin: 0;
}

fieldset div.footer div.right {
 float: right;
 width: 200px;
 margin: 0;
 position: relative;
 left: 17px;
}

fieldset div.footer input {
 vertical-align: middle;
 border: none;
 border-bottom: 1px solid #ccc;
}
fieldset div.footer label {
 vertical-align: middle;
 font-weight: bold;
}


/* Customer info */


form ul.customer-info {
 width: 100%;
 padding: 15px 0;
 overflow: hidden;
 height: 100%;
}

form ul.customer-info li {
 float: left;
 width: 340px;
 margin: 0 4px 0 0;
}

form ul.customer-info input {
 vertical-align: middle;
 border: none;
 border-bottom: 1px solid #ccc;
 width: 110px;
 margin-right: 5px;
}

form ul.customer-info label {
 font-weight: bold;
 vertical-align: middle;
 padding-right: 4px;
}


/* Submit button */

form #submit {
 border-color: #ccc;
 background: #666;
 font-weight: bold;
 color: #fff;
}

The rendering of the fieldset element is inconsistent in Internet Explorer 7 and lower, so we have to fix it using conditional comments:

<!--[if lt IE 8]>
<style type="text/css" media="screen">
fieldset legend {
 position: relative;
 left: -6px;
}
</style>
<![endif]-->

View the live demo

The secret here for achieving a good consistency across browsers is to explicitly specify a font size and family on form elements. By doing so, we can actually have proportional form elements that scale gracefully along text.

Clearing CSS floats with CSS table values (display: table)

This post describes a new way of clearing floats by using CSS table values. The technique provided below is inspired by the famous article of John Gallant and Holly Bergevin on the Easy Clearing method.

Clearing floats with 'display: table'

Let's say that we have the following markup:

<div id="container">
 <img src="float.png" alt="Float" class="float" />
 Filler text.
</div>
<div id="clear">Cleared text.</div>

with the following styles:

#container {
 width: 50%;
 padding: 1%;
 background: aqua;
}

.float {
 float: left;
 margin: 0.2em 0.3em 0 0;
}

#clear {
 width: 50%;
 background: lime;
 padding: 1%;
}

As you will see, the floated element overflows its container because there is no clear property applied to the #clear element. We can easily overcome this problem by adding a special class to the container with a single CSS declaration:

.clearfix {
 display: table;
}

View the live demo

This solution works well in all supporting browsers (Internet Explorer 8, Firefox, Opera) with the exception of Webkit-based browsers (see later in this post). According to what is stated in the CSS specification, a table computes its height in a peculiar way. Specs say:

The height of a table is given by the 'height' property for the 'table' or 'inline-table' element. A value of 'auto' means that the height is the sum of the row heights plus any cell spacing or borders. Any other value is treated as a minimum height. CSS 2.1 does not define how extra space is distributed when the 'height' property causes the table to be taller than it otherwise would be.

– from 17.5.3 Table height algorithms

In short, a table will always stretch in height to make room for the contents that actually determine the computation of its minimum height.

Fixing Webkit's problems

In Safari and Chrome, the element after the float is wider than usual, This is probably due to the fact that this element is actually a block-level element, so its width is computed differently. Keep in mind that once declared an element as a table, its width is partly determined by the table-layout property that is set to auto by default. Anyway, Safari and Chrome need only the following declaration that will be applied to the affected element:

#clear {
  display: table;
}

We've simply turned this element into a table, so that its width is computed correctly. We can give separate styles to Safari and Chrome by using JavaScript, as shown below.

var ua = navigator.userAgent.indexOf("AppleWebKit");
if(ua) {
 var head = document.getElementsByTagName("head")[0];
 var link = document.createElement("link");
 link.setAttribute("href", "webkit.css");
 link.setAttribute("rel", "stylesheet");
 link.setAttribute("type", "text/css");
 link.setAttribute("media", "screen");
 head.appendChild(link);
}

This JavaScript snippet search for an occurrence of the string AppleWebKit inside the userAgent property of the navigator object. If there is a match, then it creates a link element that points to a style sheet and attaches it to the head element.