UPDATE: following on from comments by Thierry Koblenz, I have written an update to this article. The techniques described below will still work in different browsers, but the new article explains how it can be achieved with a little less mark-up.
It’s a well-established fact that achieving cross browser consistency when styling form controls is an “exercise in futility”
. And one of those elements that just won’t play ball is the <legend> tag.
A legend is like a caption for a <fieldset> and a fieldset is used for grouping related form controls. You don’t have to use either in your forms, but if your forms are lengthy, using fieldsets can make your forms more usable by dividing them into smaller, manageable pieces, and if you use fieldsets, you must have a legend.[1]A legend is required when using a strict HTML 4.0 doctype. Pages using strict XHTML doctypes will validate without a legend, but from an accessibility point of view, it is still recommended that you have one.
The problem
Legends work just fine if you’re not doing much styling of your form. Their default state is to display along the top border of the fieldset and indented from the left slightly, as can be seen below. (The screenshot is from Firefox 2.0.0.1, Opera 9.02 and IE6 – IE7 is identical to IE6.)

Problems occur when you try to use background-colors on your form or fieldset or if you try to position the legend in any way other than the default. Internet Explorer particularly has a problem with background-colors:

The solution
So what do you do if you want a more customised look to your forms? One solution is to add extra tags around both the fieldset and legend content and style those instead.
Unlike most form elements, fieldsets and legends are simply containers for content and don’t play any part in the processing of form information, so if we use other elements to mimic their display properties, no real harm is done either to the script that processes the submitted form or to the visitor to your site.
OK, so they get a bit of additional markup, but it’s not a lot (as we’ll see next) and it in no way reduces the usability and accessibility of the form. In fact, as a lot of people disregard fieldsets and legends and their associated accessibility and usability features due to their stubborn resistance to styling, the additional markup means we’re not sacrificing those aspects any more for the design.
So how’s it actually done? In place of fieldset and legend we’re going to use generic <div> and <span> respectively. We use a span inside the legend because legends can only contain inline content. We remove all the styling from the fieldset and legend and instead apply it to the div and the span.
The black sheep
The extra div wouldn’t be necessary if it weren’t for one particular browser. And no, it’s not IE this time: it’s Firefox. As evidenced on Bugzilla, how to style legends with the Gecko rendering engine is a bit of a thorny issue. I was suprised, however, when first looking into this issue that Firefox not only has trouble with the legend when trying to use position: absolute, but also when the same is applied to a span inside a legend.
The problem is highlighted in these examples. The examples of both fieldset/legend pairs look fine in IE6 & 7 and Opera 9 (Opera 8.5 has a little trouble with the positioning in the first example too), but in Firefox 2 and 1.5, the legend in Example 1 seems to take it’s top and left coordinates from the first element in the form after the legend (a label) and not from the fieldset which has position: relative on it to establish a new positioning context.
It’s only to get the same result in Firefox that we actually need to add the extra div around the fieldset and move all the styling from the fieldset to the div (Example 2). The div also needs to wrap the fieldset and not the other way around because then the HTML would be invalid.
The examples
Having established what needs to be done to bring consistency to the styling between browsers, let’s look at a few different examples of how the legend can be positioned.
Example 1 shows the legend inset within the frame of the fieldset (or the div that looks like a fieldset) that holds it.
fieldset { border: none; }
.fieldset {
width: 30em;
position: relative;
padding: 2.5em 1em 0.5em 1em;
border: 1px solid #000;
background: #F8F8F8;
font-size: 90%;
}
legend span {
position: absolute;
width: 29em;
top: 0.5em; left: 1em;
color: #000;
font-weight: bold;
}
I’ve given the div that holds the fieldset a class of fieldset and applied the background-color and border to that instead of the fieldset which has its default border turned off. It’s also given position: relative to establish a new positioning context which means the legend span will be placed in relation to it.
The span inside the legend is given a width because Opera 8.5 won’t display the text in a single line otherwise. It’s also useful if you want to give it a background and border as in the second example. It’s then positioned absolutely and given the appropriate top and left values to place it where it’s wanted.
Example 2 shows the legend sitting in the middle of the top border, similar to its default display. The difference is, of course, that we don’t get the problem with the background of the fieldset showing above its top border in IE.
.two legend span {
top: -0.75em; left: 1em;
padding: 0 0.2em;
background: #FFF;
border: 1px solid #000;
}
.fieldset.two { padding-top: 1.5em }
It’s given a background and border and a bit of extra padding and a negative top value to pull it up over the top border. The containing div is given a smaller padding-top in this case because it doesn’t need to make as much room for the legend in this example.
Example 3 takes it one step further and moves the legend completely above the fieldset.
.three legend span { top: -2em; left: 0; }
.fieldset.three { padding-top: 0 }
This example doesn’t need any border, background etc., and the container doesn’t need any top padding at all this time.
Example 4 pushes the legend over into the empty space at the top right corner of the fieldset.
.four legend span {
top: 0.5em; left: 26em;
width: 5em;
text-align: right;
}
I’ve given it a smaller width because I wanted it to run over several lines and given it a large left value to place it where I want.
Example 5 is probably something you would hardly ever do, particularly as this won’t work in anything but IE at the moment. That’s because it uses the word-wrap: break-word property which is only supported by IE (although it is in the working draft for CSS3).
.five legend span {
top: 0; left: -1.5em;
width: 0.5em;
text-align: right;
word-wrap: break-word;
line-height: 1;
text-transform: uppercase;
}
.fieldset.five { margin-left: 1.5em; padding-top: 0 }
I won’t go into too much detail about this last example. Just check it out in IE.
























Great article, John. I really like some of the methods you show on your examples page. Very clever and they open up a nice set of possibilities. Typically I just remove the fieldset border, make the background color close to the the parent background it not transparent so it doesn’t look like crap, and then negative margin the legend to line it up. Your suggestions will be implemented there is no doubt. I do wish browsers supported CSS properties on legends better, but with your ideas it becomes a moot point. Some people will no doubt object to the use of a span, but I think of it as adding a puff of air. A span means nothing so adding nothing to an element is not something I concern myself with.
Hi Mike,
Obviously the aim is to use as little markup as is essential (although I do remember reading an article not so long back that actually recommended adding in a few extra ‘hookable’ elements as a form of future-proofing your layouts for possible redesigns – didn’t remember to bookmark it though), but in some cases, it’s just not possible to achieve certain visual styling with the minimum set.
With the current state of things, extra elements abound for things like image replacement and rounded corners techniques, so I think you have to weigh up the pros and cons of extra markup versus stylistic effect and in this case, I think the extra couple of elements is perfectly acceptable.
Like I said, I’m all for it. I don’t mind throwing around a few spans to get the job done.
You should try using position:fixed for the legend.
form legend {position: fixed;}Since IE6 doesn’t recognize position:fixed, all it does is add positioning to that element. This allows you to add no more code and it works great! I believe this won’t work for IE7 since :fixed actually works, so you’ll have to find another solution.
Hi Micah,
Maybe I’m missing something but using position: fixed doesn’t seem to work very well at all cross browser. In Firefox, the legend is stuck firmly along the top border of the fieldset, no matter what top and left coordinates you apply; in Opera, it takes those coordinates from the window, rather than the fieldset; and in IE6 you get the same problem as highlighted in the second series of screenshots I’ve shown in the article.
Do you have an example that illustrates how using position: fixed will work in this situation?
Nice article!! It will help me to convert my client forms to accessible forms. Before this solution, I had a lot of problems to style the legends.
Hmm.. I’m not using spans or divs to style my fieldset/legend pairs. Checked in FF2, IE6/7 and both look the same. Here’s some code:
form fieldset.sr{
border-width:1px;
border-style: solid;
border-color: #cccccc;
background-color: #f3f3f8;
margin: 20px 0px 6px 0px;
position:relative;
display:block;
padding: 0px 14px 14px 10px;
}
form fieldset.sr legend{
font-weight:bold;
background-color:#FFFFFF;
border-width:1px;
border-style:solid;
border-color:#888888;
padding:2px;
margin:0px 0px 0px 0px;
position:relative;
top: -10px;
width: 130px;
}
Here’s the html:
<fieldset class=”sr”>
<legend class=”sr”>
<img style=”vertical-align: middle”
src=”../images/NewGUI/Icon_Select.gif”> Select an Activity
</legend>
<div id=”icons”>Dynamic icon code goes here</div>
</fieldset>
If I could add an image, I would. My legends have an icon in them and then the text to the right. They have a different color background than the fieldset and both have borders. Seems fine in the browsers I’ve checked. Nobody using this app uses Opera. Most IE6/7 and possibly some Firefox and maybe Safari but unlikely.
Hi Bob,
I think there maybe something necessary missing from your code because when I test your example, I still see the fieldset background-color showing above the top border.
I’ll think you’ll also find that you can’t position the legend to appear completely above the fieldset in Firefox, i.e. with a larger negative top position (you can with other browsers).
And positioning the legend so it sits completely inside the fieldset’s borders produces the same bg-color problems in the versions of IE.
Ah yes! There is something missing!
I keep forgetting I’m developing in Visual Studio 2005 and it’s running on IIS.
I viewed the source for Firefox 2.0.0.3 and it’s no different than what I posted and the fieldset/legend look exactly the same as in IE6/7. Just like the PNG I sent which was an IE6 screenshot.
I’ll double-check my code and see if I missed something. I may have missed something in the css files because I’m using multiple ones and there’s a LOT of css.
Sir
This is a fine piece of work. On many occasions have I wanted to design the legend in to a form.
My hat is duly tipped.
It’s nice that you can give width to a legend field with a div inside it. It gives the wanted effect that the legend tag lacks.
Hi John,
Nice examples.
I just checked this one:
http://www.tyssendesign.com.au/examples/firefox-legend-bug.html
I think it is possible to make it work without the DIV wrapper, by using the “margin-top” and “margin-left” properties *instead* of “top” and “left”.
As a side note, for people who want to keep their markup clean, I wrote a short script that plugs “span” elements into legend:
http://www.tjkdesign.com/articles/how_to_position_the_legend_element.asp
Hi Thierry, do you have an example of what you mean because I’ve tested it out with:
.one legend span {
position: absolute;
width: 25em;
top: 0; left: 0;
margin-top: -2em;
display: block
}
and I get a completely different position in Firefox compared to all the others.
Hi John,
I borrowed the markup of your page to do a quick test:
Demo without the wrapper DIV
Hi Thierry, you’re quite right. It looks like I’ll have to revise the article.
Regarding this statement in the entry:
Are you sure that is an accurate statement? The only thing I could think of that would make that invalid is if fieldsets could not contain block-level elements, but according to SitePoint and W3C, they can:
http://reference.sitepoint.com/html/fieldset
Type
block-level element
Contains
block-level elements, inline elements
Also, I just tested it out and validated it on http://validator.w3.org, and it validated as XHTML 1.1 Transitional just fine. So what makes you think that wrapping a div in a fieldset is invalid HTML?
@Rlively: it’s invalid because the legend needs to be the first child of the fieldset, so this:
<fieldset><div><legend>is incorrect.
You could do:
<fieldset><legend><div>but for the purposes of positioning the legend, it needs to be contained within a div.
Validator results
Hey John — Just wanted to thank you for this excellent article. Saved me a lot of pain!
Ben
If i apply to a fieldset with legend rounded corners don’t work. Rounded corners work only if i remove background and border colors.
rounded corner:
border-radius: 8px;
-o-border-radius: 8px;
-icab-border-radius: 8px;
-khtml-border-radius: 8px;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
Could you help me to fix this? Thanks
You’ll probably have to apply the border radius to the div wrapping the fieldset instead.
I can’t because in the fieldset i use a legend.
Well one of the main points of the article is to attach the styling to the div wrapping the fieldset instead of the fieldset itself.
Few things are are frustrating to work with in CSS as fieldset and legend. Of course, this is all IE’s fault – every other browser handles them pretty consistently, while IE is way out in left field.
I think you’ll find with legends, that Firefox also has problems.
I haven’t read all the replies, but another way to avoid extra markup is to add it with JavaScript.
As long as things look ok without the extra markup (in case of JS failing), most users will get the good stuff.
i thing the styles 4 and 5 is overflow, but this example word for me, thanks for sharing.
Is there any way to have the legend text to be aligned to bottom. By default it is left-top corner. Now I want it to be
left-bottom . Any help please….
Not that I’ve tried it but I imagine it’d just be a case of adding padding to the bottom of your fieldset rather than the top and using a value for
bottomrather thantop.