I have recently created a way to style HTML checkboxes and radio buttons, but it requires adding additional elements to it, like a <p>
or a <span>
. This isn't terrible inconvenient, but when you're styling (CSS) a complete web software, having to go back and rewrite every checkbox can be annoying.
I recently just had a "revelation" about how to style them without using any additional elements, and it works amazingly in Chrome, but in Firefox, well, lets just say it doesn't work.
My HTML:
<input type="checkbox" />
My CSS:
input[type="checkbox"]
{
visibility:hidden;
}
input[type="checkbox"]:after
{
visibility:visible;
content:"W";
display:block;
background:#0ab9bf;
width:20px;
line-height:20px;
text-align:center;
height:20px;
overflow:hidden;
text-indent:-100px;
}
input[type="checkbox"]:checked:after
{
text-indent:0;
}
I was hoping that someone here can help? Keep in mind that I am looking for a strictly CSS solution to this. I will seek a javascript solution only as a last resort. Until then, my hopes are high.
I guess my question is, what is preventing Firefox from showing the "checkbox?" And how can I fix this. Is there a different way to go about doing this?
I'm guessing it's as David Thomas suggests that the pseudo-element is not visible because of it's 'parent' element. The reason for it working in other browsers could be explained by a different implementation, where the pseudo-elements aren't considered children of the element maybe?
Anyhow, I've had a bit of experience styling checkboxes and radio buttons like this. A pretty cool trick I've learnt is to hide the <input>
off screen and style the associated <label>
with some fancy selector tricks. This method leverages the fact that clicking on the <label>
will also click the associated <input>
.
<input type="checkbox" id="check" />
<label for="check"></label>
input[type="checkbox"] {
position:absolute;
left:-9999px;
top:-9999px;
}
input[type="checkbox"] + label {
visibility:visible;
content:"W";
display:block;
background:#0ab9bf;
width:20px;
line-height:20px;
text-align:center;
height:20px;
overflow:hidden;
}
input[type="checkbox"]:checked + label {
background:#F00;
}
This method uses the a + b
selector which means select b
which immediately follows a
. So the <label>
must come after the <input>
. A 'safer' way to do this would be to wrap them in a container and style using the general sibling selector a ~ b
. The styles will then tolerate the <label>
in a different position provided they are still siblings.
<div>
<input type="checkbox" id="check" />
<div>It will still work!</div>
<label for="check"></label>
</div>
Standalone this method is not compatible with IE8 and below because it doesn't support :checked
. The usual way to get around this is to add a class .checked
, but unfortunately IE8 also has a rendering bug when changing classes and you need a little more hacky JavaScript.
var labels = document.querySelectorAll('label');
for (var i = 0; i < labels.length; i++) {
labels[i].onclick = handleClick;
}
function handleClick () {
var checkbox = document.getElementById(this.getAttribute('for'));
// do something with checkbox.checked
alert(checkbox.checked);
}
Luckily you shouldn't need to support anything lower than 8 due to its now tiny market share (< 0.77%).