A disc of color grows out of the middle of the box until it fills every corner, then the checkmark rises into place. Unchecking drops the tick and shrinks the fill back to a point.
Also known as: checkbox fill animation css, css checkbox checked background color.
<label class="chk-fill-from-center-checkbox">
<input type="checkbox">
<span class="chk-fill-from-center-checkbox-box">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5.5 12.5l4 4L18.5 7.5"/></svg>
</span>
Enable notifications
</label>.chk-fill-from-center-checkbox {
--c: var(--chk-color, #3b82f6);
font-size: var(--chk-size, 24px);
position: relative;
display: inline-flex;
align-items: center;
gap: 0.6em;
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.3;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.chk-fill-from-center-checkbox input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
z-index: 1;
}
.chk-fill-from-center-checkbox-box {
position: relative;
box-sizing: border-box;
display: grid;
place-items: center;
flex: none;
width: 1.3em;
height: 1.3em;
overflow: hidden;
border: 0.125em solid color-mix(in srgb, currentColor 38%, transparent);
border-radius: 0.3em;
transition: border-color 0.2s ease 0.1s;
}
.chk-fill-from-center-checkbox-box::before {
content: "";
position: absolute;
left: 50%;
top: 50%;
width: 1.6em;
height: 1.6em;
margin: -0.8em 0 0 -0.8em;
border-radius: 50%;
background: var(--c);
transform: scale(0);
transition: transform 0.25s cubic-bezier(0.5, 0, 1, 1) 0.1s;
}
.chk-fill-from-center-checkbox-box svg {
display: block;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
position: relative;
width: 0.85em;
height: 0.85em;
stroke: #fff;
stroke-width: 3.2;
opacity: 0;
transform: translateY(0.3em) scale(0.6);
transition: opacity 0.12s ease, transform 0.15s ease-in;
}
.chk-fill-from-center-checkbox input:checked + .chk-fill-from-center-checkbox-box {
border-color: var(--c);
transition-delay: 0s;
}
.chk-fill-from-center-checkbox input:checked + .chk-fill-from-center-checkbox-box::before {
transform: scale(1);
transition: transform 0.35s cubic-bezier(0, 0, 0.2, 1);
}
.chk-fill-from-center-checkbox input:checked + .chk-fill-from-center-checkbox-box svg {
opacity: 1;
transform: none;
transition: opacity 0.2s ease 0.18s, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) 0.18s;
}
.chk-fill-from-center-checkbox input:focus-visible + .chk-fill-from-center-checkbox-box {
outline: 0.125em solid var(--c);
outline-offset: 0.18em;
}
@media (prefers-reduced-motion: reduce) {
.chk-fill-from-center-checkbox, .chk-fill-from-center-checkbox *, .chk-fill-from-center-checkbox::before, .chk-fill-from-center-checkbox::after, .chk-fill-from-center-checkbox *::before, .chk-fill-from-center-checkbox *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--chk-color on the element or a parent.
Currently previewing #3b82f6.--chk-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 24px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.