A Wired.com user account lets you create, edit and comment on Webmonkey articles. You will also be able to contribute to the Wired How-To Wiki and comment on news stories at Wired.com.
It's fast and free.
processing...Retrieve Sign In
Please enter your e-mail address or username below. Your username and password will be sent to the e-mail address you provided us.
processing...Welcome to Webmonkey
- edit articles
- add to the code library
- design and write a tutorial
- comment on any Webmonkey article
Sign In Information Sent
Stylize Forms With CSS
/skill level/
/viewed/
Web forms are one of the uglier elements on web pages. These pull-downs, text boxes, radio buttons and checkboxes are often blocky, awkward and out of place in the overall design of the page. There's a good reason; styling forms is challenging.
The problem is complicated by the myriad of ways to mark up a form using HTML. Since the markup often changes from site to site, it's difficult to create a clean, reusable code base you can move from one website to the next. We figured out a way, of course. If we didn't you wouldn't be reading this right now.
So read on. We're going to break down the elements of web forms and talk about how to handle them in your stylesheets.
Got a tip we forgot to cover? Log in and add it to this page. The article is on a wiki, after all."
Contents |
What you'll need
- A working understanding of HTML, especially
<form>elements - Decent CSS knowledge
- An eye for web page design
Understand the HTML
For every <form> element, there are a number of tags available. Not all of them are necessary, but here's an overview of some of the tools at your disposal:
- form -- hopefully obvious, this is the container tag
- fieldset -- often overlooked the
<fieldset>tag is a handy way of grouping related form elements - legend -- used in conjunction with
<fieldset>, legend allows you to add a caption to each fieldset. Think of it as a title for your fieldsets - label -- the label has two purposes, first it tells the user what sort of data the input requires and it also creates a code-level link between the data being collected and the control element
- input -- the meat of your form, this is the tag that actually collects the user data and passes it on
As an example of how you might use these elements to mark up your form, let's take a look at one of the most common forms on the web -- the comment form. Here's what your HTML might look like:
<form action="#" class="myform">
<fieldset>
<legend>Leave a Comment</legend>
<ul>
<li>
<label for="name">Name:</label>
<input id="name" />
</li>
<li>
<label for="email">Email:</label>
<input id="email" />
</li>
<li>
<label for="comment">Comments:</label>
<textarea id="comments" rows="7" cols="25"></textarea>
</li>
<li>
<label for="remember">Remember Me:</label>
<input type="radio" name="remember" value="true" />Yes
<input type="radio" name="remember" value="false" checked/>No
</li>
</ul>
</fieldset>
<p><input type="submit" value="Leave comment" /></p>
</form>
Let's break this down and see what's going on. First off we have the form container tag. Obviously you'd want to switch out the "#" for the path to your form processing script. Next we use a fieldset tag to group together all of our form elements except for the button at the bottom which we've wrapped in paragraph tags.
Next up we add a legend tag so people will know this is the comment form. Then we use an unordered list to group our form elements. Why? Well, for one thing it makes it easy to style. Each %lt;li> tag acts as a container for a row in our form with the label and input conveniently grouped together. The other reason is semantic. A form is gathering a list of data. Now you could make the argument that a definition list might be the more semantically valid choice, but it makes styling a bit more complicated. For simplicity's sake, we'll stick with the unordered list.
Adding Some Style
Now that we have the HTML elements in place let's add some CSS styles to make our form look better.
form.myform {
margin-left: 155px;
width: 300px;
}
form.myform fieldset {
margin-bottom: 10px;
margin-left: -155px;
}
form.myform legend {
padding: 0 2px;
font-weight: bold;
font-size: 1.6em;
}
form.myform fieldset ul {
margin: 0 0 0 155px;
padding: 0;
}
form.myform fieldset li {
list-style: none;
padding: 10px;
margin: 0;
clear: both;
}
form.myform label {
font-weight: bold;
float: left;
text-align:right;
margin-left: -155px;
width: 150px;
}
form.myform p {
margin-left: 155px;
}
What we've done here is just add some basic margin and padding so that all our elements nicely spaced and then remove the default list element styles.
The only thing slightly tricky in this CSS is adding a left margin to the whole form and then pulling the fieldset and label tags back with a negative left margin. This has the effect of creating a two column look to our form. The left side holds all the labels, the right side all of the inputs.
Here's roughly what your form should now look like :
It's a bit spartan, but a good starting point. Before we move on we should point out that, while it doesn't affect our form, the Internet Explorer 6 "3-pixel bug" often pops up when styling multiline forms. It can make things like inline checkboxes very difficult to deal with. Fortunately there's a solution that isn't too hard to implement. Check out Position is Everything for the details.
Making It Prettier
Now we have a nice structure to our form and there are countless possibilities for styling the other various elements. Here's one take that we whipped up. This code will create a nice pale blue form with shaded text inputs and highlighting for the active text box. Paste the following code into the style definition below what we used above:
form.myform input, form.myform textarea {
border: solid 1px #85b1de;
background: #fff url('formbg.gif') repeat-x;
background-position: top;
}
form.myform input:focus, form.myform textarea:focus {
background-image: none;
background-color: #ffffff;
border: solid 1px #fded7f;
}
These styles add a nice blue border around all our input areas and includes an image with a slight gradient to shade the text areas. To round out the bluish look, add a background to the fieldset tag like so:
form.myform fieldset {
margin-bottom: 10px;
margin-left: -155px;
background: #d0d9fd;
}
Your form should now look like the screenshot below, which shows the new blue look with the yellow highlight to let users know which field is currently selected. If you can't see the yellow highlight CSS won't work in IE 6. To accomplish something similar in a way that IE 6 can handle, you'll need to resort to JavaScript.
One thing to note about styling the background using the fieldset element: IE 6 may apply the background beyond the fieldset border causing a bit of spillover. The problem is that IE 6 applies the background color to the legend tag as well. The solution is to position the legend tag outside the usual document flow by using position:absolute;. Check out Matt Heerema's blog for more details on how to handle the IE 6 workaround.
The End Result
Here's an example of the code in action. Of course, filling out and submitting this form does nothing. It's an example. If you really want to leave a comment, head over to this article's discussion page.
Alternate methods
If the whole thing seems just too much for you, have a look at the JavaScript library Niceforms which handles some of the heavy lifting for you. In our experience, Niceforms doesn't degrade too well in some instances.
Other resources for styling forms include A List Apart's Pretty Accessible Forms and Eric Meyer's Formal Weirdness, which covers some of the cross-browser issues you might encounter.
Conclusion
As we've seen, styling forms is not the easiest thing in the world. However, once you understand the basic tags and the options available, it isn't terribly difficult to create well-styled forms that can go a long way to making your site much more usable and attractive.
- This page was last modified 23:17, 27 October 2008.
/related_articles/
Special Offer For Webmonkey Users
WIRED magazine:
The first word on how technology is changing our world.


