Make checkbox or radio button in mobile browsers render consistently using :before or :after pseudo-element
Recently we ran into an issue with checkboxes being too small in Andriod mobile phone (default webkit browser) that must be corrected, and all attempts using paddings or width went futile.
Stackoverflow has some answers but none are cross-browser proof. A user, Valipour suggested appending :before pseudo-element to create a faked checkbox places about the default checkbox.
input[type=checkbox]:before {
content:""; display:inline-block; width:12px; height:12px; background:red; }
input[type=checkbox]:checked:before { background:green; }
This gave us a good start to solving the problem (thank you!) and improve it further so that it works consistently across browsers in the mobile devices.
Oh no, it only works for webkit browsers
First let’s break it apart and show you what problem was with the above method.
From above screenshot, we can clearly see only webkit browsers render the :before pseudo-element and it also cannot fully cover default checkbox. We can fix it by making width and height bigger, but this does not solve the problem in iOS Safari, which we will explain later.
Problem for IE10
User jimpanzee suggested adding visibility: hidden to checkbox and visibility: visible to :before pseudo-element. While this makes the issue in webkit browsers gone it creates a new problem. In IE 10, the entire checkbox disappears due to the hidden visibility.
Well just add an IE conditional comment that will do it. You said.
We can’t do that anymore because IE 10 no longer supports conditional comments (there are ways to get around it but this is not what we wanted to head to).
In fact IE is not an issue here (if no visibility: hidden is declared for checkbox input) because it simply ignores the :before pseudo-element, but we do want to make it bigger in IE 10 in Windows 8 Phone, to do this simple declare width and height in checkbox input type:
input[type="checkbox"] {width:18px;height:18px}
We don’t want it too big as it will looks blur in Firefox desktop, and 18px is a right size for mobile device for a site visitor who has big fingers.
Fix the rendering issue in iOS Safari
iOS Safari shows both default and :before‘s faked checkbox. As mentioned above, making width and height larger doesn’t solve it. The faked checkbox created by :before pseudo-element expanded down-right diagonally, and margin position doesn’t make any difference. We didn’t test it further for that adding margins will create problem for webkit defualt browser that has already rendered correctly.
To fix the issue in iOS Safari we declared absolute position for input[type=checkbox]:before and relative position for a div class which wraps the html checkbox and label code.
Here is our final code:
.chkbox_select {
position:relative;
}
input[type="checkbox"] {width:18px;height:18px}
input[type=checkbox]:before{
content:"";
display:inline-block;
width:18px; height:18px;
background-color:#F6FFCF;
border:1px solid #ccc;
margin-right:10px;
top:12px;
left:0;
position:absolute;}
input[type=checkbox]:checked:before {
content:"✓";
background-color:#fff;
border:1px solid #ccc;
color:#8EB120;font-size:18px;
position:absolute;
top:13px;left:0;}
Note that we added a tick mark for the :checked:before because it is important to let user knows (if) a checkbox is checked by default.
Here is our final result.
Opera Mini renders the same as webkit browsers, and there is a bit of padding or margin issue which resulting checkbox and label text not aligned nicely. It is a cosmetic issue and hard to fix for that there is no reliable opera hack available. We really hate CSS hack. So we ignored it.
Note: :after pseudo-element works too, and you can certainly use it for radio type.