First, a caveat: restyling form elements is dangerous business.
There’s a reason browsers don’t easily allow this: from a user experience standpoint, the best UI is a familiar one. You can easily confuse users mucking around with novel controls.
The lesson? Don’t go overboard. Remember what Spider-man taught us.
Faux Checkboxes. Adjacent Label.
First, a basic example. We hide the actual input element by setting
z-index to tuck the element out of sight behind the label.
Then, we create a
:before pseudo-element to serve as our input on the label. This gives us nigh-unlimited styling potential. We’ll keep it basic for the moment — just a basic square.
Last, we create a third style using the pseudo-class
:checked and the adjacent label’s faux input.
In short, we create our own input element and simply style it differently if the input field is checked.
In this example, note the
input element is outside the
label, which uses the
for attribute to identify it:
<input type="checkbox" class="plumbing" name="opt" id="opt" value="1"><label class="porcelain" for="opt">One</label>
We’ll cover the alternative syntax next.
Faux Radio Buttons. Parent Label.
The radio button works the same way. To differentiate it in the barebones example, we’ll simply add a
border-radius to the pseudo-element if the selected element has a
label is a parent element of the
input, the former of which we cannot style based on the input’s
:checked state — there are no parent selectors. Therefore, we added a
span tag immediately after the input element to host our styled “field”.
<label><input type="radio" class="plumbing" name="opt" id="opt" value="One"><span class="porcelain">One</span></label>
Label as checkbox.
In the above examples, we’ve been using the
:before pseudo element to create faux-input elements, but the
label itself is still a sibling selector, and can be just as effective as an input of its own.
*This, one could argue, is a good example of not following the lessons that Spider-Man taught us.