Simple Form Example

Contact
Gender

Accessibility Guidelines

When designing forms its important to consider how a screen reader will read the form. This is done using something called forms mode within the screen reading software. What this does simply is let the user tab between form elements reading out only the label and the input (alt and title get read out if no label exists). Therefore when placing 'required field' markings it is important that they are placed in the label. Any text beside the input that is not in the label will not be read out to the user if they are using a screen reader.

The next important thing to consider is that the legend will be read out before each input, consequently avoid using long legends and instead use 1 or 2 words maximum, this should be a shortened version of a longer heading above the form if required.

Points to remember

Explanation

Legends are near impossible to style and in mozilla browsers can not be taken out of flow, so well use and style a span instead to take the content of the legend out of flow and so collapse it to 0px height.

Wrapping each label/input pair in a block level element prevents the inputs and labels appearing on a single line when styles do not get loaded. a br element could be used however this would be using it for style purposes and would limit the flexibility of styling.

I have left the styling on the form to the absolute minimum to demonstrate styling of radio buttons or other inline grouped inputs. see Who Says CSS Forms Cant Look Good? for an example of what can be done.

What about definition lists?

Some people argue about definition lists should be used for forms however there are a couple of problems with this. Most importantly that when it comes to screen readers in forms mode they will only read out the legend, and labels so other marked up text will not be read out. This is a problem when it comes to the example above, gender would be marked up as a dt with male and female in the dd. So the screen reader would never present the user with the gender heading for the inputs.

HTML

<form action="?">
	<fieldset>
		<legend>Contact</legend>
		<div><label for="name">Name</label> <input id="name" name="name"></div>
		<fieldset class="radio">
			<legend><span>Gender</span></legend>
			<ul>
				<li><input type="radio" id="male" name="male"> <label for="male">Male</label></li>
				<li><input type="radio" id="female" name="female"> <label for="female">Female</label></li>
			</ul>
		</fieldset>
	</fieldset>
</form>

CSS

form * {margin:0;padding:0;} /* Standard margin and padding reset, normally done on the body */

legend {
	color:#000; /* IE styles legends with blue text by default */
	*margin-left:-7px; /* A hack that only ie reads to position the legend in the same place cross browser */
}
fieldset {
	border:1px solid #dedede; /* Default fieldset borders vary cross browser, so make them the same */
}
fieldset div {
	overflow:hidden; /* Contain the floating elements */
	display:inline-block; /* Give layout in ie to contain float */
}
fieldset div {display:block;} /* Reset element back to block leaving layout in ie */
label {
	float:left; /* Take out of flow so the input starts at the same height */
	width:5em; /* Set a width so the inputs line up */
}

.radio {
	position:relative; /* Position so children are relative to this container */
	border:0; /* Remove the border */
}
.radio span {
	position:absolute; /* Take the content of the legend out of flow */
	top:0;left:0; /* and position it to the top left of the fieldset */
	width:5em; /* Same width as labels */
}
.radio ul {
	margin-left:5em; /* Since the legend is out of flow. set margin, so inputs are inline */
	list-style:none; /* Dont want bullets */
}
.radio li {
	position:relative; /* Fix a bug in IE zoom functionality */
	display:inline; /* Display the inputs in a line */
	white-space:nowrap; /* We dont want a label to wrap between the input and label */
}
.radio label, .radio input {
	width:auto; /* Reset the width on the label from the 5em, set earlier */
	float:none; /* Reset the float from left on the label, set earlier */
	vertical-align:middle; /* Align the radio buttons with the inputs */
}