There are a stack of different ways to lay out a form, but honestly sometimes I’m undecided on which way is better. Some say there’s nothing wrong with using a table to position your form elements, but I reckon that makes it semantically meaningless.
Forms have admittedly always been a field (bad pun, sorry) of HTML that I've not paid as much attention to as I should have, but I recently decided to create a functional template with the intention of re-cycling it when needed.
I had several goals for this exercise. The form needed to:
- be accessible
- have good usability
- utilise all the common form elements
- be scalable
- not use any JavaScript for effects
- validate XHTML Strict and CSS 2.1
- work in as many browsers as possible without relying on conditional hacks
- look swanky!
The finished product can be viewed here, and the complete source and demo is downloadable at the end of this article.
The XHTML bits
As accessibility is a concern, we will surely be putting in fieldsets, legends and labels. These elements also provide us with plenty of styling options, so no complaints so far.
So here's the form:
<form id="myform" method="post" action="">
<fieldset>
<legend>Personal</legend>
<label for="name">Name <span>(Your full name please)</span></label> <input type="text" id="name" />
<label for="web_site">Web Site <span>(No need to include http://)</span></label> <input type="text" value="www." id="web_site" />
<label for="email_address">Email Address <span>(Must be valid)</span></label> <input type="text" id="email_address" />
</fieldset>
<fieldset>
<legend>Professional</legend>
<label for="company">Company <span>(Name of your organisation)</span></label> <input type="text" id="company" />
<label for="position">Position <span>(What is your title?)</span></label> <input type="text" id="position" />
<label for="duration">Duration <span>(How long have you been there?)</span></label> <input type="text" id="duration" />
<label for="location">Location <span>(Seriously, where are you?)</span></label>
<select name="Location" id="location">
<option value="Australia"></option>
<option value="Australia">Australia</option>
<option value="Outside Australia">Outside Australia</option>
</select>
</fieldset>
<fieldset>
<legend>Battlestar Pop Quiz</legend>
<label>Cylon <span>Who is a among the final five?</span></label>
<input type="radio" id="adama" name="pie" class="narrow" /> <em>Adama</em>
<input type="radio" id="anders" name="pie" class="narrow" /> <em>Anders</em>
<input type="radio" id="hilo" name="pie" class="narrow" /> <em>Hilo</em>
</fieldset>
<fieldset>
<legend>Final Stage</legend>
<label for="comments">Comments <span>(Care to leave a comment?)</span></label> <input type="text" id="comments" />
<label>Agreement <span>Tick if you agree to all this</span></label>
<input name="agreement" type="checkbox" value="agreement" class="narrow" />
</fieldset>
<div><input type="submit" name="button" id="submit" value="Submit" class="submit" /></div>
</form>
Nothing out of the ordinary here, except I've placed spans within the labels with their display set to block in the CSS, which makes them fall below the label for the appearance we want.
This is better than dropping the text with a <br /> not only because we get to tweak the position with CSS, but also because it makes more sense to have this:
Name (Your full name please)
...instead of this...
Name
(Your full name please)
This is perfectly valid BTW. Ironically, the latter example is the appearance we are going for, but we'll get there with CSS.
With the label now containing the span (consider them grouped), we can set a fixed width displayed block, floating left and text aligned right so they all appear uniformly under one another. CSS is your friend:
label {
width:180px; /* Must match the exact width specified in the span */
display:block;
float:left;
text-align:right;
}
span {
display:block;
width:180px; /* Must match the exact width specified in the label */
text-align:right;
}
The input fields also have a fixed width and will appear uniformly under each other.
So to summarise at this stage, here's what we're looking at:

The 'block' trick
If you know anything about floats you're probably already wondering how these are going to line up underneath each other without some sort of containing element. In the past I would have done this by placing each in it's own div, which is messy and unnecessary, or each in a p, which is semantically incorrect as these are not paragraphs we're dealing with.
The trick is to have a single containing element around the entire lot, and guess what? We've already got one. Place an ID in the form tag, id="my_form" I've used, and use CSS to set a fixed width only wide enough so that the containing elements wrap.
This will force each onto a new line giving the appearance that they are block level elements. Sneaky huh?
IE issues resolved
As is often the story, we have to make allowances for IE. In this case we've set a background colour on the legend, which when viewed in IE bleeds into the fieldset. This was fixed with a simple absolute positioning 'hack'.
IE also had a nasty habit of showing borders around the radio buttons and check boxes on hover. Again it was easily fixed but still something that didn't happen in any other browser (surprise surprise).
Compatibility
Testing went better than first expected. It works fine in Firefox 1.5, 2.0, 3.0.11, 3.5, IE6, 7 and 8, Safari, Opera and Chrome.
The download contains the complete demo with plenty of comments in the CSS to explain what's happening.
Yours, free to enjoy for any purpose you see fit.
accessible_form.zip (7.5k)


Pete Harvy
I think to be totally accessible you should have used a higher contrast. But it looks fabulous and that's just a styling issue anyway. Stupendous effort Web Guy.
Wednesday 1st July 2009 | 08:40 PM Reply Comment URL Back to top