Animated Checkbox CSS
I've always wanted to make a realistic checkbox input that animates the checkmark in a way that draws the checkmark naturally, down from the left and then up to the right. I finally have!
Choose multiple.
Works in both Light and Dark mode.
I tried many methods to animate a checkbox including using clip-path
, but I think this one is most natural and customizable.
First, I didn't want to simply hide the input[type=checkbox]
and replace it with a label
that has an animated GIF or SVG. That's not what we are doing here. We are looking at a fully-accessible and backwards-compatible actual checkbox input field.
Pure CSS Animated Checkbox Tutorial
The first step is the HTML markup. Specify an input
field with a type=checkbox
property. If there needs to be text assigned to it, it is wrapped in a label
tag. Include a name
property in the input
to make it valid and to work with forms.
<label>
<input type="checkbox" name="option"> Check this
</label>
That's all for the HTML. The default checkbox is pretty ugly, eh?
The CSS will control the look and the animation transition.
My concept is so stupidy simple, I should have tried this years ago. We'll use the :before
and :after
pseudo-elements on the input
to represent the short left-tick and the longer right-tick respectively in their starting position.
The :checked
property for both :before
and :after
will draw the completed ticks of the checkmark using CSS3 transition
to make a smoothly-timed animated effect.
Apply appearance:none;
to the input field to remove the default checkmark that doesn't even animate. Set it to position:relative;
because the :before
and :after
pseudo-elements will be set absolutely positioned inside the input
. Make the input as large as you want with width
and height
, and style it with whatever borders and box-shadows you like to make it pretty. Here's an ugly box because I don't know you.
The :before
and :after
pseudo-elements need a background-colour and width/height to draw the lines of the ticks. Use transform
to rotate the 2 ticks to make the full checkmark. Use top/left positioning to place them just right inside the input. I like my example overlapping the outer edge of the box, but on paper I stay inside the lines.
input[type=checkbox] {
appearance: none;
position: relative;
width: 2em;
height: 2em;
border: .125em solid green;
font: inherit;
}
input[type=checkbox]:before,
input[type=checkbox]:after {
content: "";
position: absolute;
background: green;
width: .25em;
}
input[type=checkbox]:before {
height: 45%;
top: 46%;
left: 22%;
border-bottom-left-radius: 0;
transform: rotate(-32deg);
transform-origin: top left;
}
input[type=checkbox]:after {
height: 100%;
left: 42%;
top: -18%;
transform: rotate(35deg);
transform-origin: bottom left;
}
Now that we've drawn the checkmark ticks using CSS we need to prepare them for animating.
I've already set transform-origin
to the location where the checkmark drawing animation starts. From the top left
on the left tick, and from the bottom left
on the right tick.
Now here's the thing with CSS transform animations. They will animate backwards as well. It will basically undraw the checkmark (instead of disappear it) unless we do something different. We don't have to account for that, but we will for completeness.
We'll set the transition to 0 seconds on the :before
and :after
pseudo-elements like so.
transition: transform 0s;
Then, when they are in the :checked
state later on in the code, they will each have a longer animation time applied.
input[type=checkbox]:before,
input[type=checkbox]:after {
transition: transform 0s;
}
To begin the animation we will scale down both the checkmark ticks to 0 on the transform property where we already specified the ticks' rotation.
input[type=checkbox]:before {
transform: scale(0) rotate(-32deg);
}
input[type=checkbox]:after {
transform: scale(0) rotate(35deg);
}
Awww, but now we have no checkmark showing. We'll get it back by specifying what happens to the :before
and :after
pseudo-elements when the checkbox is checked with :checked:before
and :checked:after
.
So to recap, scale(0)
squished down the checkmark to 0 — nothing — nada, but we'll unsquish it for when the checkbox is checked.
input[type=checkbox]:checked:before {
transform: scale(1) rotate(-32deg);
}
input[type=checkbox]:checked:after {
transform: scale(1) rotate(35deg);
}
Both ticks that make up the checkmark now reappear. Now to control the delay and timing so that it's an animated effect.
input[type=checkbox]:checked:before {
transition: transform .15s;
transition-delay: 0s;
}
input[type=checkbox]:checked:after {
transition: transform .25s;
transition-delay: .15s;
}
The left tick takes 0.15 seconds to animate, so the unless you are drawing a checkmark with two hands, the right-tick must be delayed by 0.15 seconds before it can be drawn. Since the left tick has more height, let's make it take longer to draw, like 0.25 seconds.
Note: It will take a lot of perfection and attention to detail connect the two lines seamlessly and make a beautiful checkmark. This will all depend on the width of the lines and your borders. I took you most of the way. You can also animate the background-color
of the actual checkbox to give a nice backdrop to your checkmark. So many possibilites.
Now who will make radio inputs that animate scribbled in? That seems like the next obvious task. I'll give you a long headstart.