How to create custom checkbox using only HTML and CSS (no-js) #1
Originally posted on kyoshee.com
On one of the interviews I’ve had interesting task on layouts:
Using only HTML and CSS create custom checkbox, so its’ original image is not displayed but it still had functionality (checked — unchecked). Instead of original checkbox image insert custom image or text that shows current checkbox state and giving proper functionality.
My subconscious told me something about pseudoelements but even googling didn’t help me to do a task in 5 minutes, after which interviewer ended call saying “Wait for our feedback”. But I didn’t get upset. Instead, I improved my skill, so here it is: 2 ways to create custom checkbox.
First way
It is suitable for layout where <input>
connected with <label>
trough an id
and for
properties.
<input
class="custom-checkbox"
id="myCheckbox"
type="checkbox" />
<label for="myCheckbox">
Checkbox
</label>
Order of the elements is important because CSS selectors depend on it.
Hiding input
.custom-checkbox {
position: absolute;
z-index: -1;
opacity: 0;
}
Important thing about using opacity: 0
instead of display: none
is that with opacity we can get focus state of the input
element for styling.
Creating fake checkbox
.custom-checkbox + label {
cursor: pointer;
display: inline-flex;
align-items: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}.custom-checkbox + label::before {
content: '';
display: inline-block;
width: 1em;
height: 1em;
flex-shrink: 0;
flex-grow: 0;
border: 1px solid #c3c3c3;
border-radius: 0.25em;
margin-right: 0.5em;
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
Firstly, we verticaly aligning flag with align-items: center
for flex containers.
With pseudoelement ::before
we create imitation of a checkbox. For visibility paint its’ borders. Properties background-repeat, -position
and -size
define position on flag in checked
state.
Pseudoelement styles in :checked state
.custom-checkbox:checked + label::before {
border-color: blue;
background-color: blue;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
}
Styles for :hover, :active, :focus and :disabled states
.custom-checkbox:not(:disabled):not(:checked) + label:hover::before {
border-color: rgba(0, 0, 255, 0.33);
}.custom-checkbox:not(:disabled):active + label::before {
background-color: rgba(0, 0, 255, 0.66);
}.custom-checkbox:focus + label::before {
box-shadow: 0 0 0 0.2rem rgba(0, 0, 255, 0.125);
}.custom-checkbox:focus:not(:checked) + label::before {
border-color: #c3c3c3;
}.custom-checkbox:disabled + label::before {
background-color: black;
}
Second way
Second way is suitable for a layout where <input>
in placed inside <label>
:
<label class="custom-checkbox">
<input type="checkbox">
</label>
With this layout we should add <span>
element right after <input>
:
<label class="container">Checkbox
<input type="checkbox" checked="checked">
<span class="checkmark"></span>
</label>
Let’s create a simple checkbox without accounting for different states and with a fixed image position.
<label>
(container) styles:
.container {
display: block;
position: relative;
padding-left: 35px;
margin-bottom: 12px;
cursor: pointer;
font-size: 22px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
Hiding default <input>
:
.container input {
position: absolute;
z-index: -1;
opacity: 0;
}
Drawing custom checkbox inside <span>
element:
.checkmark {
position: absolute;
top: 0;
left: 0;
height: 25px;
width: 25px;
background-color: #eee;
}
Styling <span>
in :hover
and :checked
states:
.container:hover input ~ .checkmark {
background-color: #ccc;
}.container input:checked ~ .checkmark {
background-color: #2196F3;
}
Adding pseudoelement for and image:
.checkmark:after {
content: "";
position: absolute;
display: none;
}.container input:checked ~ .checkmark:after {
display: block;
}.container .checkmark:after {
left: 9px;
top: 5px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 3px 3px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
Examples
<input>
outside <label>
, checkbox<input>
outside <label>
, radio
<input>
inside <label>
, checkbox<input>
inside <label>
, radio
<input>
inside <label>
, checkbox, different style<input>
inside <label>
, radio different style
Conclusion
Now we’re able to use pseudoelements, state selectors and neighbour CSS selectors. I hope this knowledge will help you!
Thank you for reading,
kyoshee