In keeping with my New Year’s resolution to not get involved in “black-hole” projects so that I have more flexibility to pursue fun stuff on a whim, I whipped up a fun experiment in CSS3.

The Main Idea

If you design a lot of forms, you know that radio and checkbox lists are hard to style. And no matter how perfectly you lay them out, they are still just plain boring. I thought it would be fun to make checkbox and radio lists a bit more fun by going an entirely different route, and by getting a bit more 3D.

Enter “Chunky Checker.” This set of styles takes an ordinary list of checkboxes or radio buttons and converts them into a super-chunky 3D list. As the radios/checkboxes are activated, the particular segment of the list transforms, creating a “depressed” look, sort of as if a button was physically pressed.

The Markup

This approach is completely, 100% CSS and HTML–no JavaScript whatsoever. Moreover, it uses a pretty standard markup. The following is all that’s needed to recreate the demos:

    <legend>Favorite Color:</legend>
    <input type="checkbox" name="color" value="Red" id="red" class="red"/>
    <label for="red">Red</label>
    <input type="checkbox" name="color" value="Orange" id="orange" class="orange" />
    <label for="orange">Orange</label>
    <input type="checkbox" name="color" value="Yellow" id="yellow" class="yellow" />
    <label for="yellow" class="yellow">Yellow</label>
    <input type="checkbox" name="color" value="Green" id="green" class="green" />
    <label for="green" class="green">Green</label>
    <input type="checkbox" name="color" value="Blue" id="blue" class="blue" />
    <label for="blue">Blue</label>
    <input type="checkbox" name="color" value="Indigo" id="indigo" class="indigo" />
    <label for="indigo">Indigo</label>

Nothing out of the ordinary here.

How it Works

in general, the styling is created by completely hiding the checkbox/radio buttons, and applying all of the styles to each input’s label. As checkboxes and radio buttons will be activated by their label being clicked, it’s easy to manage the “state” of the input element.

Speaking of input state, the stylesheet uses the :checked psuedo-selector to determine whether or not to apply particular styles based on the state of the input. There are also rules to apply particular styles based on the state of adjacent inputs.

Finally, there are box-shadows added to create a 3D-ish look, and some animations are thrown in the mix to make the whole thing a bit more dynamic.


This has been tested very little :) I don’t recommend you use it in production anywhere, as the following issues have been admittedly neglected. If you have suggestions for improving in these areas, please get the source from GitHub and hack away to your heart’s content.

Cross-browser Compatibility: I’ve only tested it on Chrome, Firefox, Safari, and Opera, and even then, only on Mac. It seems to work decently well on all of them, although by far it works best in Firefox (go figure). There’s no telling how it behaves in IE9+, and it will surely be terrible in anything before IE9. On the other hand, this is an experiment in CSS3, so that’s kind of expected…

Accessibility: Accessibility for this is probably awful, although I don’t have the interest to test it. There is currently no “focus” class for the inputs’ labels, so this probably isn’t great for use with a keyboard.

Chrome Hack: There is a crazy, silly bug in Chrome that caused me some headaches. If you depress a label, you’ll notice that an inset shadow appears on the depressed label element. When depressing the label to the right of an already-depressed label, the shadow *should* disappear. This works correctly in Firefox and Opera, but only works in Chrome if you move your mouse over the previously-depressed label, open Developer Tools, close Developer Tools, or do some other action that messes with Chrome’s chrome.

Fortunately, I ran across a good description of this bug, which helpfully also had a hack solution. Check it out if you’re curious.

The Demos

I whipped up a couple of demos to show that this works pretty snazzily with radios and checkboxes.