In other entries I’ve discussed the correct markup and best practices to make a well-structured, semantic, accessible form. The appearance of the form has been a secondary consideration while I emphasized how important it was to not add extra markup. Forms are not paragraphs, and they do not need <br>
tags or tables to display correctly. That is, not surprisingly, the role of CSS.
Step One: Clarify Accesskey Shortcuts
Part of the process of designing a good form is using markup to make it accessible by users of differing abilities. Each label
in our form
should have a unique accesskey
value. While correctly configured browsers will make these accesskey
options obvious to users that need them, we want to make sure that everyone who desires to use them is very clear on which shortcuts are present. If you’ve consistently used the first letter from the text of the label
for an accesskey
, (which is recommended) the CSS to achieve this is very simple:
label:first-letter {
font-weight: bolder;
color: red;
}
(Of course, you can customize the appearance of the first letters in any way you wish).
Sometimes using the first letter of every <label>
is impossible, simply because it has been used elsewhere in the form, or because that key press combination is reserved by the system. In that case, you must use other characters in the <label>
text.
A good example of this would be two separate fields in a form, one asking for a phone number and the other for a postal code. We cannot use “p” as an accesskey
value for both fields. This means adding a little markup to our HTML. To this:
<label for="postalcode" accesskey="c">
Postal Code
</label>
<input type="text" name="postalcode" id="postalcode" pattern="[A-Za-z][0-9][A-Za-z] [0-9][A-Za-z][0-9]">
<label for="phonenumber" accesskey="n">
Phone Number
</label>
<input type="tel" name="phonenumber" id="phonenumber" pattern="\d{3}[\-]\d{3}[\-]\d{4}">
We add the following inside the <label>
for each element:
<label for="postalcode" accesskey="c">Postal
<span class="shortcutkey">C</span>ode</label>
<label for="phonenumber" accesskey="n">
Phone <span class="shortcutkey">N</span>umber
</label>
And change the CSS to:
label span.shortcutkey {
font-weight:
bolder-color: red;
}

Step Two: Make The Form Presentable
There are many possibilities for cleaning up the appearance of our form via CSS. Let’s start with the simplest:
Option 1: Label and input on separate lines
This set of declarations forces each label on its own line, keeping the submit
button by itself through the use of an attribute selector:
label, input[type="submit"] {
display: block;
}
label {
display: block;
}
Option 2: Label and input on same line, evenly spaced
Many designs call for <label>
elements to be beside their associated form fields, to save on space. In that case, there are two possibilities. The first is an extension of the technique we just used:
label {
display: block;
width: 10em;
clear: left;
}
label, input {
float: left;
}
The CSS reads as follows: when the browser encounters a new <label>
tag, display it as a block
element (so we can give it a width
), and make sure that everything is cleared to its left
(i.e. nothing comes before it on the line, or influences where the line falls). That will force each element onto a new line when it appears, floating to the left
of the following element.
The only problem you may encounter with this technique would be putting two input
tags next to each other, such as a divided postal code, or an area code and phone number. In that case, you could overrule the embedded or linked style with an inline style on the affected element.
Option 3: Label and input on same line, label evenly spaced
Another possibility for lining up our labels comes from using variants of display: table
, the basics of which we covered in a previous section. Essentially, we want our labels to act as if they are in a single column of a table
, which should make the width
provided to them exactly the same. To the HTML we have used above, we apply the following CSS:
label, input {
display: table-cell;
}
The problem is that the browser does not know when to place label-input
pairs on a new line. We’ll do so by adding a <div>
around each pair, and adding appropriate CSS:
<div>
<label for="postalcode" accesskey="c">
Postal Code
</label>
<input type="text" name="postalcode" id="postalcode" pattern="[A-Za-z][0-9][A-Za-z] [0-9][A-Za-z][0-9]">
</div>
<div>
<label for="phonenumber" accesskey="n">
Phone Number
</label>
<input type="tel" name="phonenumber" id="phonenumber" pattern="\d{3}[\-]\d{3}[\-]\d{4}">
</div>
As they are block
elements, each <div>
will automatically divide the label-input pairs onto separate lines. The <div>
elements are only used in the context of a <form>
with valid markup, so we can use a descendant selector in our declaration:
form div {
display: table-row;
}
Now, in addition to placing the label-input
pairs on separate lines, each <div>
also acts like a table row
, meaning that each column of implied “cells” takes up the same width
.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.