I found another way, without using adjacent labels or surrounding divs.
My usecase was that I had a markdown parser that generates those nifty TODO lists and I wanted to style them. Changing the generated HTML wasn't a option, so I came up with this solution:
given a checkbox like this:
<input type="checkbox" id="cb">
You can style it with visibility: hidden
on checkbox and visibility: visible
on ::after, like this:
#cb {
visibility: hidden;
}
input#cb::after {
visibility: visible;
content: "F";
color: red;
background: green;
padding: 8px;
}
input#cb:checked::after {
content: " T ";
color: green;
background: red;
}
<!doctype html>
<html>
<body>
<input type="checkbox" id="cb">
</body>
</html>
EDIT:
@connexo in a comment pointed out that input elements cannot have content. It could be easly done using label element, for example like so (please someone correct me if this is wrong, I don't have non-webkit browser handy to test it).
#cb-span * {
visibility: hidden;
}
input#cb + label::after {
visibility: visible;
content: "F";
color: red;
background: green;
padding: 8px;
}
input#cb:checked + label::after {
content: " T ";
color: green;
background: red;
}
<!doctype html>
<html>
<body>
<span id="cb-span">
<input type="checkbox" id="cb">
<label for="cb"></label>
</span>
</body>
</html>
The checkbox works just like normal one and you can style it anyway you like.
Maybe it'll help someody (and I can bookmark it, because I haven't found anything like this on the web)