How to style a checkbox using CSS
I am trying to style a checkbox using the following:
<input type="checkbox" style="border:2px dotted #00f;display:block;background:#ff0000;" />
But the style is not applied. The checkbox still displays its default style. How do I give it the specified style?
UPDATE:
The below answer references the state of things before widespread availability of CSS 3. In modern browsers (including Internet Explorer 9 and later) it is more straightforward to create checkbox replacements with your preferred styling, without using JavaScript.
Here are some useful links:
- Creating Custom Form Checkboxes with Just CSS
- Easy CSS Checkbox Generator
- Stuff You Can Do With The Checkbox Hack
- Implementing Custom Checkboxes and Radio Buttons with CSS3
- How to Style a Checkbox With CSS
It is worth noting that the fundamental issue has not changed. You still can't apply styles (borders, etc.) directly to the checkbox element and have those styles affect the display of the HTML checkbox. What has changed, however, is that it's now possible to hide the actual checkbox and replace it with a styled element of your own, using nothing but CSS. In particular, because CSS now has a widely supported :checked
selector, you can make your replacement correctly reflect the checked status of the box.
OLDER ANSWER
Here's a useful article about styling checkboxes. Basically, that writer found that it varies tremendously from browser to browser, and that many browsers always display the default checkbox no matter how you style it. So there really isn't an easy way.
It's not hard to imagine a workaround where you would use JavaScript to overlay an image on the checkbox and have clicks on that image cause the real checkbox to be checked. Users without JavaScript would see the default checkbox.
Edited to add: here's a nice script that does this for you; it hides the real checkbox element, replaces it with a styled span, and redirects the click events.
You can achieve quite a cool custom checkbox effect by using the new abilities that come with the :after
and :before
pseudo classes. The advantage to this, is: You don't need to add anything more to the DOM, just the standard checkbox.
Note this will only work for compatible browsers. I believe this is related to the fact that some browsers do not allow you to set :after
and :before
on input elements. Which unfortunately means for the moment only WebKit browsers are supported. Firefox + Internet Explorer will still allow the checkboxes to function, just unstyled, and this will hopefully change in the future (the code does not use vendor prefixes).
This is a WebKit browser solution only (Chrome, Safari, Mobile browsers)
See Example Fiddle
$(function() {
$('input').change(function() {
$('div').html(Math.random());
});
});
/* Main Classes */
.myinput[type="checkbox"]:before {
position: relative;
display: block;
width: 11px;
height: 11px;
border: 1px solid #808080;
content: "";
background: #FFF;
}
.myinput[type="checkbox"]:after {
position: relative;
display: block;
left: 2px;
top: -11px;
width: 7px;
height: 7px;
border-width: 1px;
border-style: solid;
border-color: #B3B3B3 #dcddde #dcddde #B3B3B3;
content: "";
background-image: linear-gradient(135deg, #B1B6BE 0%, #FFF 100%);
background-repeat: no-repeat;
background-position: center;
}
.myinput[type="checkbox"]:checked:after {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAQAAABuW59YAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAB2SURBVHjaAGkAlv8A3QDyAP0A/QD+Dam3W+kCAAD8APYAAgTVZaZCGwwA5wr0AvcA+Dh+7UX/x24AqK3Wg/8nt6w4/5q71wAAVP9g/7rTXf9n/+9N+AAAtpJa/zf/S//DhP8H/wAA4gzWj2P4lsf0JP0A/wADAHB0Ngka6UmKAAAAAElFTkSuQmCC'), linear-gradient(135deg, #B1B6BE 0%, #FFF 100%);
}
.myinput[type="checkbox"]:disabled:after {
-webkit-filter: opacity(0.4);
}
.myinput[type="checkbox"]:not(:disabled):checked:hover:after {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAQAAABuW59YAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAB2SURBVHjaAGkAlv8A3QDyAP0A/QD+Dam3W+kCAAD8APYAAgTVZaZCGwwA5wr0AvcA+Dh+7UX/x24AqK3Wg/8nt6w4/5q71wAAVP9g/7rTXf9n/+9N+AAAtpJa/zf/S//DhP8H/wAA4gzWj2P4lsf0JP0A/wADAHB0Ngka6UmKAAAAAElFTkSuQmCC'), linear-gradient(135deg, #8BB0C2 0%, #FFF 100%);
}
.myinput[type="checkbox"]:not(:disabled):hover:after {
background-image: linear-gradient(135deg, #8BB0C2 0%, #FFF 100%);
border-color: #85A9BB #92C2DA #92C2DA #85A9BB;
}
.myinput[type="checkbox"]:not(:disabled):hover:before {
border-color: #3D7591;
}
/* Large checkboxes */
.myinput.large {
height: 22px;
width: 22px;
}
.myinput.large[type="checkbox"]:before {
width: 20px;
height: 20px;
}
.myinput.large[type="checkbox"]:after {
top: -20px;
width: 16px;
height: 16px;
}
/* Custom checkbox */
.myinput.large.custom[type="checkbox"]:checked:after {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGHRFWHRBdXRob3IAbWluZWNyYWZ0aW5mby5jb23fZidLAAAAk0lEQVQ4y2P4//8/AyUYwcAD+OzN/oMwshjRBoA0Gr8+DcbIhhBlAEyz+qZZ/7WPryHNAGTNMOxpJvo/w0/uP0kGgGwGaZbrKgfTGnLc/0nyAgiDbEY2BCRGdCDCnA2yGeYVog0Aae5MV4c7Gzk6CRqAbDM2w/EaQEgzXgPQnU2SAcTYjNMAYm3GaQCxNuM0gFwMAPUKd8XyBVDcAAAAAElFTkSuQmCC'), linear-gradient(135deg, #B1B6BE 0%, #FFF 100%);
}
.myinput.large.custom[type="checkbox"]:not(:disabled):checked:hover:after {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGHRFWHRBdXRob3IAbWluZWNyYWZ0aW5mby5jb23fZidLAAAAk0lEQVQ4y2P4//8/AyUYwcAD+OzN/oMwshjRBoA0Gr8+DcbIhhBlAEyz+qZZ/7WPryHNAGTNMOxpJvo/w0/uP0kGgGwGaZbrKgfTGnLc/0nyAgiDbEY2BCRGdCDCnA2yGeYVog0Aae5MV4c7Gzk6CRqAbDM2w/EaQEgzXgPQnU2SAcTYjNMAYm3GaQCxNuM0gFwMAPUKd8XyBVDcAAAAAElFTkSuQmCC'), linear-gradient(135deg, #8BB0C2 0%, #FFF 100%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table style="width:100%">
<tr>
<td>Normal:</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" checked="checked" /></td>
<td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" disabled="disabled" checked="checked" /></td>
</tr>
<tr>
<td>Small:</td>
<td><input type="checkbox" class="myinput" /></td>
<td><input type="checkbox" checked="checked" class="myinput" /></td>
<td><input type="checkbox" disabled="disabled" class="myinput" /></td>
<td><input type="checkbox" disabled="disabled" checked="checked" class="myinput" /></td>
</tr>
<tr>
<td>Large:</td>
<td><input type="checkbox" class="myinput large" /></td>
<td><input type="checkbox" checked="checked" class="myinput large" /></td>
<td><input type="checkbox" disabled="disabled" class="myinput large" /></td>
<td><input type="checkbox" disabled="disabled" checked="checked" class="myinput large" /></td>
</tr>
<tr>
<td>Custom icon:</td>
<td><input type="checkbox" class="myinput large custom" /></td>
<td><input type="checkbox" checked="checked" class="myinput large custom" /></td>
<td><input type="checkbox" disabled="disabled" class="myinput large custom" /></td>
<td><input type="checkbox" disabled="disabled" checked="checked" class="myinput large custom" /></td>
</tr>
</table>
Bonus Webkit style flipswitch fiddle
$(function() {
var f = function() {
$(this).next().text($(this).is(':checked') ? ':checked' : ':not(:checked)');
};
$('input').change(f).trigger('change');
});
body {
font-family: arial;
}
.flipswitch {
position: relative;
background: white;
width: 120px;
height: 40px;
-webkit-appearance: initial;
border-radius: 3px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
outline: none;
font-size: 14px;
font-family: Trebuchet, Arial, sans-serif;
font-weight: bold;
cursor: pointer;
border: 1px solid #ddd;
}
.flipswitch:after {
position: absolute;
top: 5%;
display: block;
line-height: 32px;
width: 45%;
height: 90%;
background: #fff;
box-sizing: border-box;
text-align: center;
transition: all 0.3s ease-in 0s;
color: black;
border: #888 1px solid;
border-radius: 3px;
}
.flipswitch:after {
left: 2%;
content: "OFF";
}
.flipswitch:checked:after {
left: 53%;
content: "ON";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<h2>Webkit friendly mobile-style checkbox/flipswitch</h2>
<input type="checkbox" class="flipswitch" />
<span></span>
<br>
<input type="checkbox" checked="checked" class="flipswitch" />
<span></span>
Before you begin (as of Jan 2015)
The original question and answer are now ~5 years old. As such, this is a little bit of an update.
Firstly, there are a number of approaches when it comes to styling checkboxes. The basic tenet is:
-
You will need to hide the default checkbox control which is styled by your browser, and cannot be overridden in any meaningful way using CSS.
-
With the control hidden, you will still need to be able to detect and toggle its checked state.
-
The checked state of the checkbox will need to be reflected by styling a new element.
The solution (in principle)
The above can be accomplished by a number of means — and you will often hear that using CSS3 pseudo-elements is the right way. Actually, there is no real right or wrong way, it depends on the approach most suitable for the context you will be using it in. That said, I have a preferred one.
-
Wrap your checkbox in a
label
element. This will mean that even when it is hidden, you can still toggle its checked state by clicking anywhere within the label. -
Hide your checkbox.
-
Add a new element after the checkbox which you will style accordingly. It must appear after the checkbox so it can be selected using CSS and styled dependent on the
:checked
state. CSS cannot select 'backwards'.
The solution (in code)
label input {
visibility: hidden;/* <-- Hide the default checkbox. The rest is to hide and allow tabbing, which display:none prevents */
display: block;
height: 0;
width: 0;
position: absolute;
overflow: hidden;
}
label span {/* <-- Style the artificial checkbox */
height: 10px;
width: 10px;
border: 1px solid grey;
display: inline-block;
}
[type=checkbox]:checked + span {/* <-- Style its checked state */
background: black;
}
<label>
<input type='checkbox'>
<span></span>
Checkbox label text
</label>
Refinement (using icons)
"But hey!" I hear you shout. What about if I want to show a nice little tick or cross in the box? And I don't want to use background images!
Well, this is where CSS3's pseudo-elements can come into play. These support the content
property which allows you to inject Unicode icons representing either state. Alternatively, you could use a third party font icon source such as font awesome (though make sure you also set the relevant font-family
, e.g. to FontAwesome
)
label input {
display: none; /* Hide the default checkbox */
}
/* Style the artificial checkbox */
label span {
height: 10px;
width: 10px;
border: 1px solid grey;
display: inline-block;
position: relative;
}
/* Style its checked state...with a ticked icon */
[type=checkbox]:checked + span:before {
content: '\2714';
position: absolute;
top: -5px;
left: 0;
}
<label>
<input type='checkbox'>
<span></span>
Checkbox label text
</label>