Cleanly Styling Checkboxes

One of the biggest challenges to creating nice looking web forms is that specific elements, like the `select` menu, radio buttons, and checkboxes are notoriously difficult to style. Most browsers are very rigid when it comes to applying styles to these elements, especially if you try to modify them too radically.

Lots of very smart people have ways to work around this, mostly using JavaScript and some sort of image replacement, but now that we’re moving in to a new era where CSS3 elements are more widely accepted (even in the stodgiest of browsers), these methods are becoming less necessary.

## The Checkbox

A great example of this is the checkbox.

Unstyled Checkbox

These little guys are usually left alone, but can have a pretty dramatic impact on your site design if they do get to put on some fancy dress clothes. Unfortunately, you can’t *actually* style them (or at least not much; you can play with their dimensions and position, but that’s about it). History, this is one of the elements that would get changed out with JavaScript and CSS sprites, especially since they’re state-based, changing their display based on whether or not the element is checked. Moreover, if the checkbox is supposed to be checked when the page is loaded, you would naturally want that to be shown to the user.

## Living life JavaScript and Image Sprite free

I’m here to tell you that you don’t need JavaScript to accomplish this goal, and you don’t need images (though you can use them, if you so choose).

I’ve taken that vanilla checkbox I showed you earlier and applied a little bit of style:

[codepen embedded sample]

## Advanced selectors and generated content to the rescue

Here’s the markup I’m working with:

Nothing too fancy, I’m just wrapping the checkbox in a label. Note that the label is associated with the with checkbox input, to make for a larger clickable area for the user (good practice in general).

Then I apply my styles:

.checkbox input[type=”checkbox”] {
position: relative;
}

.checkbox input[type=”checkbox”]:before {
display: block;
margin-top: -3px;
margin-left: -2px;
width: 16px;
height: 16px;
background-color: cyan;
content: ” “;
}

.checkbox input[type=”checkbox”]:checked:after {
display: block;
margin-top: -15px;
margin-left: -2px;
width: 16px;
height: 16px;
content: “X”;
text-align: center;
}

Let’s walk through this ruleset by ruleset; note that the `.checkbox` class is applied to the `label`, not the `input`.

### The `.checkbox` ruleset

.checkbox input[type=”checkbox”] {
position: relative;
}

The first ruleset is just creating a container for the positioning that I’ll use on the [`:before`](https://developer.mozilla.org/en-US/docs/CSS/::before) and [`:after`](https://developer.mozilla.org/en-US/docs/CSS/::after) pseudo-elements. These elements are associated with the checkbox input and not the label, since that’s the element that we’re styling in this particular case.

Not setting the position (`top`, `left`, `bottom`, or `right`) means they stay in their default value of `auto`, which means that the checkbox label and the input inside of it don’t move anywhere (added bonus: `position: relative` doesn’t change the document flow).

### The checkbox’s `:before` ruleset

.checkbox input[type=”checkbox”]:before {
display: block;
margin-top: -3px;
margin-left: -2px;
width: 16px;
height: 16px;
background-color: rgb(0,175,236);
content: ” “;
}

Here’s where we start to take advantage of some advanced CSS wrangling. Essentially what we are telling the document to do is to create a new element that gets placed before the checkbox. That new element should be a block-level element that is 16×16 in dimension, and with a very attractive blue background color. You could make this more fancy, adding box-shadows and border-radii to it if you want, of course.

The margins just do some alignment tweaking to get the newly-created box to be centered over the top of the input that is being styled.

The `content` property is important. In order to get a pseudo-element like `:before` to display, it needs some content. I’m using a space character (note that an empty string, `””` won’t work) because I don’t want anything to show up in this element (it’s my un-checked state).

### The checkbox’s `:after` ruleset

.checkbox input[type=”checkbox”]:checked:after {
display: block;
margin-top: -15px;
margin-left: -2px;
width: 16px;
height: 16px;
content: “X”;
}

This ruleset should look remarkably similar (and if I were putting this in to a production environment, I’d refactor it so that both this and the `:before` ruleset’s shared properties were defined together) with a few distinct differences.

The first is the `:checked` pseudo-selector. This is stating that these styles only apply to the `:after` element when the checkbox is in its checked state. Like the `:before` ruleset, this creates a new element (this time with a content of “X”, though it could have been a checkmark (`✓`), but you’ll need to use an escaped hex-code (in this case, it’d be `2713`).

## That’s a wrap

That’s all there is to it; set up your container, generate some content, and then style it all up. You can see a live example of this code here: http://codepen.io/miketierney/pen/cDsCn