I'd follow the advice of SW4's answer – to hide the checkbox and to cover it with custom span, suggesting this HTML
<label> <input type="checkbox"> <span>send newsletter</span> </label> The wrap in label neatly allows clicking the text without the need of "for-id" attribute linking. However,
#do not hide it using visibility: hidden or display: none
It works by clicking or tapping, but that is a lame way to use checkboxes. Some people still use much more effective tab to move focus, space to activate, and hiding with that method disables it. If the form is long, one will save someone's wrists to use tabindex or accesskey attributes. And if you observe the system checkbox behavior, there is a decent shadow on hover. The well styled checkbox should follow this behavior.
cobberboy's answer recommends Font Awesome which is usually better than bitmap since fonts are scalable vectors. Working with the HTML above, I'd suggest these CSS rules:
Hide checkboxes
input[type="checkbox"] { position: absolute; opacity: 0; z-index: -1; }I use just negative
z-indexsince my example uses big enough checkbox skin to cover it fully. I don't recommendleft: -999pxsince it is not reusable in every layout. Bushan wagh's answer provides a bulletproof way to hide it and convince the browser to use tabindex, so it is a good alternative. Anyway, both is just a hack. The proper way today isappearance: none, see Joost's answer:input[type="checkbox"] { appearance: none; -webkit-appearance: none; -moz-appearance: none; }Style checkbox label
input[type="checkbox"] + span { font: 16pt sans-serif; color: #000; }Add checkbox skin
input[type="checkbox"] + span:before { font: 16pt FontAwesome; content: '\00f096'; display: inline-block; width: 16pt; padding: 2px 0 0 3px; margin-right: 0.5em; }
\00f096 is Font Awesome's square-o, padding is adjusted to provide even dotted outline on focus (see below).
Add checkbox checked skin
input[type="checkbox"]:checked + span:before { content: '\00f046'; }
\00f046 is Font Awesome's check-square-o, which is not the same width as square-o, which is the reason for the width style above.
Add focus outline
input[type="checkbox"]:focus + span:before { outline: 1px dotted #aaa; }
Safari doesn't provide this feature (see @Jason Sankey's comment), you should use window.navigator to detect the browser and skip it if it is Safari.
Set gray color for disabled checkbox
input[type="checkbox"]:disabled + span { color: #999; }Set hover shadow on non-disabled checkbox
input[type="checkbox"]:not(:disabled) + span:hover:before { text-shadow: 0 1px 2px #77F; }
Try to hover the mouse over the checkboxes and use tab and shift+tab to move and space to toggle.