Tuesday, May 19, 2015

A Customized Checkbox

It's been a while since I've made a post, but it's always good to take a little time to recharge.

I was presented with an interesting problem recently. A colleague of mine needed to display a customized checkbox on a web page. As many of you undoubtedly know, however, customizing a checkbox in a browser is nearly impossible. Most of the time we're left with the rather ugly instead of something pretty when what we want is something like the examples shown in the image to the right.

If you search online for a solution, what you'll find - or at least what I found - is that typical solutions are either not semantic or are not accessible, or both. As anyone who knows me can attest, I'm not satisfied with something that is either not semantic or not accessible, so I started out to build something better.

What I ended up doing is starting with absolutely semantic markup - an INPUT tag and a LABEL tag, i.e., <INPUT id="cbx" name="cbx" type="checkbox" value="1" /> <LABEL for="cbx">Check</LABEL> and then added the CSS to style it. It's important to note that the markup always has the INPUT tag first and the LABEL tag immediately following it - even though in the example image Example 2 shows the checkbox after the label.

The CSS then, hides the input in an accessible manner using the clip property. Since the INPUT is hidden, but can still receive focus using the keyboard (an important accessibility feature), you need to show the user an indication that the field has received focus. By default, this is typically done using a one pixel dotted black border, so feel free to use that, but be sure to add a transparent border to the LABEL when the checkbox does not have focus, otherwise your user will see a flicker as the label shifts back and forth by one pixel.

Also, since the INPUT is clipped, you'll need something to show the user thé state of the checkbox. We're going to do this using a background image on the label. In my example, I've used a simple checkbox with a gradient from top left to bottom right for unchecked and a green checkmark when it's checked (using the psuedoclass 'checked'). If the input is to be displayed to the right, I accommodate that by adding a class 'right' to the INPUT element, which changes the background position to center right.

One design note - this was done very quickly and with minimal image editing, so you'll probably want to do things like make sure your 'checked' and 'unchecked' images have transparent pixels to the left and/or right so that you can add padding to the left and right on your label to make your focus border look a little better.

Although I don't do anything with the indeterminate state, you can add that if you'd like...although I'm not sure it makes sense in most experiences. To add an indeterminate state, you'd simply add an input[type="checkbox"]:indeterminate + label rule to your stylesheet with an associated background image. If you'd like more information about the psuedoclass, checkout out the MDN entry.

Aside from the indeterminate psuedoclass, all my rules can be seen in the style below or you can take a look at the prototype page to see what it looks like in your browser. In the coming days I will likely be fine tuning the prototype to make the design a little more attractive, but here's the brief version of this little snippet.

input[type="checkbox"] {
  clip:rect(0, 0, 0, 0);
  position:absolute;
}
input[type="checkbox"] + label {
  background-image:url("unchecked_ico.png");
  background-position:left center;
  background-repeat:no-repeat;
  border:1px solid transparent;
  font-size:15px;
  padding-left:20px;
}
input[type="checkbox"]:checked + label {
  background-image:url("icon_checkbox_1.gif");
}
input[type="checkbox"]:focus + label {
  border:1px dotted #999;
}
input[type="checkbox"].right + label {
  background-position:right center;
  padding-left:0;
  padding-right:20px;
}

Happy coding.

No comments:

Post a Comment