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:
Browser problems
But then I checked in Firefox and saw this:
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:
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 offieldset
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 whateverpadding-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 thelegend
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
.
- Previous post: Making elements keyboard focusable and clickable
- Next post: How to shrinkwrap and center elements horizontally