Using CSS to style forms

One of the things I’ve been slowly working on lately is taking a close look at forms: best practices, accessibility, styling, etc.

I don’t mean styling form controls–no, I’ve played around with it before and have read enough articles to feel that it’s not only impossible, but undesirable.  (Some good reading on that in the citations/references at the end of the post.)

So, no, I don’t believe form controls should be styled barring very small tweaks that you don’t mind seeing only in a few browsers.

Semantic Forms

What I want to do is get a solid foundation for a simple (and hopefully semantic) form with as robust a stylesheet as I (and geniuses I find through Google) can come up with.  If fancier effects are desired, they can be built up.  But the final result should be suitable for most forms while remaining simple and semantic.

I’ve been using a method where I wrap inputs in labels and set the labels to block–then use classes to create columns, etc.  But it tended to get bloated.  So I thought it might be time to take another look.

The biggest inspiration for the form styling was That site gave me lots of ideas about how to use and line up labels and what to think about for accessibility and the appearance of forms without a stylesheet.  The author mentioned a few alternatives tried that caused failures in browser testing — so I was able to begin where s/he left off.


One of the most challenging parts of form design with semantic form elements is styling form legends.  There were a lot of resources that were helpful there (check out the links at the end of the post), especially

My goals

  • Use form, fieldset, legend, label, and input/select/textarea and maybe br to build a form — avoiding spans, divisions, lists, and other extraneous markup.
  • Use CSS to style the form–making the CSS cross browser without bloating the stylesheet or using hacks.
  • Make the form flexible without bloating the HTML — it should not be obscure.
  • The markup for checkboxes and radio fields should make sense.
  • Make the form accessible.  Ensure it is readable without the stylesheet.  Use accesskeys and associate labels.
  • Make the form usable.  Make labels and layout clear.  Provide input hints.  Provide focus styles.
  • Provide clear errors both at the top and next to the affected field.  Ensure the error display is consistent both with the first-level JavaScript and the second-level server side validation.  (Obviously the server side will vary, but it should be easy to integrate server side errors).

There is still some tweaking and integration of JavaScript to go before I call it “finished” — I’ve made some notes in comments about my to-do list, which is:

  • Use JavaScript to create “input hints” inside text inputs–on focus they disappear, on blur they reappear if nothing has been entered.
  • Use JavaScript for first-level validation and error display.
  • Adding a few classes to the fieldsets would accomplish several things.  Part of my reduced-code-and-css approach was to also avoid the use of classes.  Once I’ve got a handle on the semi-final product, I may make some different versions that utilize classes to a greater or lesser extent.
  • Tweak the form presentation for effective reading without the stylesheet (there are some problems with this atm).
  • Test, test, test!  🙂

So here’s the styled form

HTML & CSS of a home search form.

Some final notes

It doesn’t validate!

  • Semantics – Looking pretty good!
  • CSS– To keep the testing code concise, a CSS hack was used–this would be moved to an IE conditional stylesheet in a production version, obviating the need for the validation-breaking hack.
  • XHTML– I like XHTML, I really do.  Normally I deploy in XHTML transitional.  I validate using XHTML strict normally, if I can, however.  Since this is in testing the strict doctype is used.  But the errors here (if you take a look), well, honestly…I think they’re stupid.  So I will probably ignore them.  I don’t see any reason why an accesskey shouldn’t be used on a select element  if it works in the user agent (though I’ll do some research on it to see if there actually is a good reason).  As for the other errors…sometimes I think the XHTML strict working group was smoking crack.  You must wrap ALL form elements in a fieldset?  Why?  It’s already in a form.  It’s a form field.  *shrug*

Input hints (usability, accessibility)

For input hints (in addition to the preliminary thoughts on plain-text instructions that you can see) I decided the best place to put hints would be in the title attribute on the input.  I don’t know if this is a “new” idea, though I haven’t seen it before.  My thoughts were that, using the title tag, most browsers (even without JavaScript) will display the hint on hover! So the plain text hints/instructions are very preliminary.

Display without styles (accessibility)

So far, the form is pretty readable without styles.  Using the line break tag preserves the general vertical layout.  Using labels next to inputs preserves the general horizontal layout.  The major wrenches in the display are the plain text input hints (and, upon errors, the errors might case some bad readability).  You can also see the nesting of fieldsets much more clearly without the stylesheets.  That doesn’t bother me, overall–fieldsets can be nested and the meaning of a fieldset  — “a set of associated fields” is respected by the markup.

Semantic markup (best practices, accessibility)

Eventually in a form, you pretty much have to use non-form elements.  For additional instructions, to fix a layout quirk, etc.  I wanted to keep it as simple as possible.  But instructions, plain text code hints, errors, and legends required p, span, and div (I used as seemed appropriate).  Only legends that need extra styling need to use spans, though, so you will see it’s only used in a couple of places.  I’m also still working on plain text instructions and even the errors will probably go through some additional tweaking.