« Back to Posts

Fieldsets and Legends in IE7

Jun 18, 2011

Solving a problem with legend positioning in Internet Explorer 7.

Background

(Skip the background, take me straight to the solution!)

For accessibility purposes, all radio button and checkbox groups should be put inside an HTML fieldset tag with a legend tag. This is because their is no label for the radio button group as a whole. Consider the following code:

1 <div>
2 	<p>A yes/no question?</p>
3 	<input type="radio" name="radio" id="yes" value="yes"/>
4 	<label for="yes">Yes</label>
5 	<input type="radio" name="radio" id="no" value="no"/>
6 	<label for="no">No</label>
7 </div>

The labels “Radio 1″ and “Radio 2″ select the respective radio buttons when click on. But if you navigated to this form element using a screen reader there is a good chance that you would miss the question entirely. To fix that, use a fieldset and legend:

1 <fieldset>
2 	<legend>A yes/no question?</legend>
3 	<div>
4 		<input type="radio" name="radio" id="yes" value="yes"/>
5 		<label for="yes">Yes</label>
6 		<input type="radio" name="radio" id="no" value="no" />
7 		<label for="no">No</label>
8 	</div>
9 </fieldset>

Now a screen reader will inform the user that the current input fields (yes and no) are part of “A yes/no question?” Much better.

Problem

Fieldsets bring along with them extra formatting in the browser. By default a fieldset appears as a box with the inputs inside it:

You’ll note that the legend tag is positioned by default slightly off of the top-left corner. But what happens if we want to make the question horizontal, so we can fit it into a list of fields? This can be accomplished as so:

1 fieldset.radio legend {
2 	float: left;
3 	width: 30%;
4 }
5 fieldset.radio div {
6 	float: left;
7 }

Results:

There are still some spacing issues and a border, due to browser defaults on the fieldset and legend elements. Expanding our code:

 1 fieldset.radio {
 2 	padding: 0;
 3 	border: 0;
 4 }
 5 fieldset.radio legend {
 6 	float: left;
 7 	width: 30%;
 8 	margin-left: -2px;
 9 }
10 fieldset.radio div {
11 	float: left;
12 }

See the example code. Results:

Looks pretty good, right? But that’s before we take it into Internet Explorer 7:

IE7 seems to have 2 issues:

  • It uses different default margins (7px left instead of 2px left) than other browsers
  • Left floated legends still force other elements to clear beneath them

The first problem we can solve fairly easily using a conditional comment. The second is more puzzling.

Solution

The best solution is to absolutely position the legend. This breaks it out of the normal flow of the document so it doesn’t mess with other elements. Then we have to give the div left padding of 33% so it is not under the legend. Why padding and not margin? Good question. IE7 doesn’t like margin, but padding works.

 1 fieldset {
 2 	padding: 0;
 3 	border: 0;
 4 }
 5 legend {
 6 	background-color: blue;
 7 	margin-left: -2px;
 8 	position: absolute;
 9 }
10 fieldset.radio div {
11 	background-color: red;
12 	padding-left: 30%;
13 }

We also include some IE7 specific CSS to move the legend farther to the left:

1 <!--[if IE 7]>
2 <style type="text/css">
3 	fieldset.radio legend {
4 		margin: 0 0 0 -7px;
5 	}
6 </style>
7 <![endif]-->

Result:

We can turn on background color so you can see the location of the fieldset (blue) and div with radio group (red). See example code.

Other Solutions

There are several other solutions that produce similar results, though none are ideal. I include them below for reference.

1. Place the legend at the end of the fieldset and float the div right instead of left. This works, but we have to reorder are HTML and the containing element has to have an explicit width or the inputs end up on the far right. See example code.

2. Wrap the legend tag in a div and float that div. This seems to remove the core problem (presumably because the div, not the legend, is floated), but it still involves an HTML change. See example code.

3. Leave the legend how it is and reposition the div to the right and up, so it ends up in the correct place. This requires no HTML modification, but the degree of vertical repositioning is dependent on the font size and is thus tricky. See example code.

Conclusion

This seems to be a fairly workable cross-browser solution to get a horizontal fieldset that uses a legend. As demonstrated above, it works in IE7. It seems to work in IE6, and even back to IE 5.5, though I did not test thoroughly on those browsers. It also works in IE8 and IE9.

If you wanted to keep your code more consistent, you could use the standard float left for most browsers, and move the absolute positioning into the conditional comment for IE7 and below.

In order to get the legend in a pixel-perfect location across all browsers you might need to do a little tweaking on the margins, but this is pretty close. I hope you find it useful.