Pretty form controls with CSS

Posted on 28 February 2007 (10:48 AM)

As Roger Johansson proves in his article(s) on styling form controls, you are very limited when it comes to spicing up form controls.

There are some sites around that provide an alternative, but these techniques rely heavily on Javascript to swap the normal form control with an image.

With the CSS3 pseudo-class :checked as my weapon of choice, I'll provide a way to make checkboxes pretty using CSS only (and tell you in which browsers it goes wrong).

The semantic layer

I want to start with a semantic layer. A good hack should be built upon the same foundation you would use in the regular scenario. This means regular input elements, combined with regular label elements.

  1. <fieldset>
  2. <legend>Check some boxes</legend>
  3. <input type="checkbox" name="test[]" value="foo" id="foo_field"><label for="foo_field">Foo</label>
  4. <input type="checkbox" name="test[]" value="bar" id="bar_field"><label for="bar_field">Bar</label>
  5. <input type="checkbox" name="test[]" value="baz" id="baz_field"><label for="baz_field">Baz</label>
  6. <input type="submit" value="Submit" name="subm">
  7. </fieldset>
  8. Download this code: /code/pretty_form_controls_with_css1.txt

The label's for attribute corresponds to the input's id, as to provide a way to focus on the field by clicking the label, something that this technique relies heavily upon, as I will explain later.

So far we have a regular form, nothing special. I'm going to use CSS to make these regular checkboxes look like these:

An unchecked box A checked box

(The icons are part of an icon set provided by Paul Armstrong)

The presentational layer

Because labels can be used to focus on an input element, I can use them to mimic the actual controls. Check out the CSS:

  1. fieldset {
  2. overflow: hidden;
  3. position: relative;
  4. }
  5. input[type=checkbox] {
  6. position: absolute;
  7. left: -999em;
  8. }
  9. input[type=checkbox] + label {
  10. display: block;
  11. height: 16px;
  12. padding-left: 25px;
  13. background: url(bullet.gif) top left no-repeat;
  14. }
  15. input[type=checkbox]:checked + label {
  16. background-image: url(bullet_checked.gif);
  17. }
  18. Download this code: /code/pretty_form_controls_with_css2.txt

First, I throw out the actual checkbox. Thanks to left: -999em;, they are shoved out of the fieldset, effectively making them invisible. Then I use the labels to act as a container for the checkbox-image.

Thanks to the :checked pseudo-class and the sibling selector, I can differentiate between a checkbox's checked and normal state!

Check this example to see it in action. The same thing works great for radio-buttons by the way. Of course, it wouldn't be a proper CSS experiment if there weren't some nasty issues involved...

Browser issues

Working browsers

The technique works in the latest versions of Firefox, Opera and Camino, as well as Netscape and Mozilla. No problems whatsoever.

Internet Explorer 6

My CSS is a little too advanced for IE6. It understands almost none of my CSS rules (due to the heavy use of attribute selectors).

The good thing is; the form remains unstyled and therefore usable. You could easily load up a different stylesheet using a Conditional Comment, or even place the IE style-rules before the advanced style-rules in the same stylesheet. Easy to work around.

Internet Explorer 7

The crappy thing about IE7 is that it does understand all my CSS rules, except for the vital :checked pseudo-class. So everything looks good, and even works good (when you click some checkboxes and hit submit, you'll see the values get to the other side of the form anyway), but the "behaviour" of the checkbox is gone.

No worries though; just load up an additional stylesheet in a conditional comment and you can display the checkboxes the regular way.

Safari

Safari is nasty on this one. Just like IE7, it doesn't support the :checked pseudo-class, but what's even worse; labels in Safari do not provide the handy click-and-focus method they do in other browsers! So unlike IE7, Safari won't even send the proper values back after submitting.

Chris Cassell has written a nice Javascript, of which I think it's good practice to include it in every site that contains form controls anyway. It solves the click-and-focus problem, but I won't get the pretty checking and unchecking behaviour unless I also script some alternative to the :checked pseudo-class. A pity.

Edit: I just found this article that provides a way to hack Safari. I'm not a big fan of CSS hacks, but you could use this to fork different style-rules to Safari and fix the technique if you want. Remember though; the minute Apple removes this bug from Safari, your forms will break.

So, will you use it?

I know I won't. At least not on regular sites, e.g. sites that should not break in Apple's browser.

IE's faulty behaviour can be worked around (did I mention conditional comments?), but Safari's faulty behaviour will require scripting. If I wanted to solve this through scripting, I wouldn't have gone through the hassle of typing all those CSS3 style-rules.

Too bad, though, because I think this technique is much cleaner than any Javascript alternative.

Back to top

Filed under HTML and CSS

Comments:

  1. 15 July 2008 (03:33 PM) by css dersleri

    CSS layer examples / properties and layer attributes

    http://CSS-less...-properties.htm

  2. 15 August 2008 (06:52 PM) by Jason Grant

    This doesn't work in IE7.

  3. 12 December 2008 (09:37 PM) by Ted

    Why not file a bug at webkit.org about it? The webkit team has been pretty good at tackling the ones I've filed. And now that Google is using Webkit, you've got a better shot at it getting fixed sooner rather than later.

  4. 09 November 2009 (07:51 PM) by Kreshiv

    This is a cool way for check boxes. but this is not working with IE7. Is it possible to make some changes and do it for IE7.

  5. 08 June 2010 (08:42 AM) by john

    this is a waste of web space.

    thanks though!!

  6. 01 July 2010 (09:16 PM) by James Tryon

    Thanks for taking your time to write all this up.

    I use Jquery UI to do this and it works in all browsers from what i can tell. No Problems.

    http://jqueryui.com/demos/button/#radio

  7. 18 February 2011 (03:10 AM) by weather in yiwu

    Thanks for your content and I will go back again soon because this place is so interesting .

Sorry, due to spam, comments are temporarily out of order.

Back to top

Preferences

These settings will be saved for your convenience.