Fieldset, legend, border-radius and box-shadow

The fieldset and legend elements are notorious for being tricky to style, especially if you want the same result across browsers. Other than the line wrapping issue I wrote about in How to line wrap text in legend elements, even in IE, you may run into problems and differences related to padding, backgrounds and positioning of the legend element.

Recently I noticed more fieldset + legend weirdness, this time involving the border-radius and box-shadow CSS properties. If you use either property on a fieldset element that has a child legend element (which all fieldset elements should), you will get unexpected results in some browsers. Luckily I also found a fix after a bit of experimentation.

For reference I created a demo page with a fieldset element styled with the problematic properties so you can see for yourself. The relevant CSS is this:

fieldset {
    border:1px solid #999;
    border-radius:8px;
    box-shadow:0 0 10px #999;
}
legend {
    background:#fff;
}

Chrome, Opera and Safari all render the border and box shadow the way I expected, like this:

Screenshot of fieldset with border-radius and box-shadow in Chrome 24 on Mac OS X 10.8

Browser problems

But then I checked in Firefox and saw this:

Screenshot of fieldset with border-radius and box-shadow in Firefox 18 on Mac OS X 10.8

While it renders the actual border the same way as Opera and the WebKit browsers, the top part of the box shadow is pushed away from the border as if to make room for the legend element. I checked in Firefox 3.6 and 18 to see if there was any difference, but they both behave the same way.

Next up was Internet Explorer. As long as you stick to box-shadow, it behaves as expected. Well, almost as expected – in my example the box shadow has no horizontal or vertical offset, just a 10px blur, and in IE the top part of the box shadow doesn’t extend quite as far from the border box as from the other edges. But it’s not that bad and it seems that IE (9+, since that’s when it added support for box-shadow) does this on other elements as well, not just on fieldset elements. View the demo page in IE9+ and take a look at the p element I added for reference.

Ok, so that’s box-shadow, and now for some IE weirdness when you apply border-radius to fieldset elements. It turns out that both IE9 and IE10 ignore border-radius on the actual border, but they do round the box shadow, like this:

Screenshot of fieldset with border-radius and box-shadow in IE 10 on Windows 8

Getting out of the flow

So now there are two problems to solve:

  • Prevent the legend element from pushing away the box shadow in Firefox
  • Make IE apply border-radius to the border of fieldset elements

I tried to apply the line wrapping fix (legend {display:table;}) I wrote about in the article I mentioned earlier, but it had no effect on border-radius or box-shadow in either browser.

Thinking that the solution would be to somehow get the legend element out of the normal flow I experimented with position:absolute, which sort of worked. It stopped Firefox from pushing away the box shadow and IE magically started rounding the corners of the border on the fieldset element. However, if the text in the legend element is long enough for it to line wrap, it is likely to cover part of the contents of the fieldset element. So yes, position:absolute can work, but is unreliable unless you know that the legend will never need to wrap.

The float fix

Another way to remove an element from the normal flow is to float it. And what do you know, floating the legend element has the same effect as position:absolute in both Firefox and IE. Even better, it does not cause the legend element to cover other content in the fieldset in case it needs to line wrap. And as an extra bonus, float seems to solve the line wrapping problem in IE (including IE8), removing the need for display:table. But there are still a couple of side effects to handle:

  • All browsers now render the legend inside the fieldset’s top border instead of on top of it as they normally do. To fix that I added a negative margin-top to pull it back up. The exact value will depend on whatever padding-top you give the fieldset, line-height, etc.
  • To make sure that the other content of the fieldset element doesn’t pop up next to the legend element (since it’s now floated), I added a rule to make sure the first element after the it clears the float: legend + * {clear:both;}.

See the demo page for an unfixed fieldset, one with the position:absolute attempt and the final fix that uses float (view source for the CSS). Here are the most relevant parts of the CSS:

fieldset {
    padding-top:10px;
    border:1px solid #666;
    border-radius:8px;
    box-shadow:0 0 10px #666;
}
legend {
    float:left;
    margin-top:-20px;
}
legend + * {
    clear:both;
}

Long story short: Float legend elements to make their contents line wrap and to enable consistent rendering of fieldset elements that are styled with border-radius and box-shadow.

Posted on February 23, 2013 in CSS

Comments are disabled for this post (read why), but if you have spotted an error or have additional info that you think should be in this post, feel free to contact me.