<form>
<label><input type="checkbox" name="checkboxes" value="A"> A</label>
<label><input type="checkbox" name="checkboxes" value="B"> B</label>
<label><input type="checkbox" name="checkboxes" value="C"> C</label>
<br>
<label><input type="radio" name="radios" value="1"> 1</label>
<label><input type="radio" name="radios" value="2"> 2</label>
<label><input type="radio" name="radios" value="3"> 3</label>
</form>
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg: #e3e4e8;
--fg: #17181c;
--inputBg: #ffffff;
--inputBgDown: #e3e4e8;
--inputBorder: #c7cad1;
--inputBorderDown: #c7cad1;
--primary: #255ff4;
--primaryDown: #5583f6;
--duration: 0.5s;
font-size: calc(20px + (30 - 20)*(100vw - 320px)/(1280 - 320));
}
body, input {
font: 1em/1.5 Hind, sans-serif;
}
body, label {
display: flex;
}
body {
background: var(--bg);
color: var(--fg);
height: 100vh;
}
form {
margin: auto;
}
label, input {
cursor: pointer;
}
input {
margin-right: 0.5em;
width: 1.5em;
height: 1.5em;
-webkit-appearance: none;
appearance: none;
}
input:focus {
outline: transparent;
}
input[type=checkbox], input[type=checkbox]:after, input[type=radio] {
transition: all 0.1s linear;
}
input[type=checkbox] {
background: var(--inputBg);
border-radius: 0.25em;
box-shadow: 0 0 0 0.1em var(--inputBorder) inset;
}
input[type=checkbox]:after {
color: #255ff4;
content: "\2713";
display: block;
font-size: 1.5em;
line-height: 1;
text-align: center;
transform: scale(0);
transform-origin: 50% 67%;
width: 100%;
height: 100%;
}
input[type=checkbox]:checked {
animation: popOutCheckbox var(--duration) linear;
}
input[type=checkbox]:checked:after {
transform: scale(1);
transition:
background 0.1s linear,
color 0.1s linear,
transform calc(var(--duration) / 5) calc(var(--duration) / 2) linear;
}
input[type=checkbox]:active, input[type=checkbox]:focus {
background: var(--inputBgDown);
box-shadow: 0 0 0 0.1em var(--inputBorderDown) inset;
}
input[type=checkbox]:active:after, input[type=checkbox]:focus:after {
color: var(--primaryDown);
}
input[type=radio] {
background: var(--primary);
border-radius: 50%;
box-shadow:
0 0 0 0.1em var(--inputBorder) inset,
0 0 0 0.76em var(--inputBg) inset;
}
input[type=radio]:checked {
animation: popOutRadio var(--duration) linear;
box-shadow:
0 0 0 0.1em var(--inputBorder) inset,
0 0 0 0.375em var(--inputBg) inset;
}
input[type=radio]:active, input[type=radio]:focus {
background: var(--primaryDown);
box-shadow:
0 0 0 0.1em var(--inputBorderDown) inset,
0 0 0 0.76em var(--inputBgDown) inset;
}
input[type=radio]:checked:active, input[type=radio]:checked:focus {
box-shadow:
0 0 0 0.1em var(--inputBorderDown) inset,
0 0 0 0.375em var(--inputBgDown) inset;
}
label {
align-items: center;
margin: 0.75em 0;
position: relative;
-webkit-tap-highlight-color: transparent;
}
label span {
border-radius: 50%;
display: block;
pointer-events: none;
position: absolute;
top: 0.5em;
left: 0.5em;
width: 0.5em;
height: 0.5em;
transform: scale(0);
}
label span:nth-of-type(even) {
top: 0.625em;
left: 0.625em;
width: 0.25em;
height: 0.25em;
}
/* Animations */
@keyframes popOutCheckbox {
from {
background: transparent;
border-radius: 50%;
box-shadow:
0 0 0 0.375em var(--primary),
0 0 0 0.76em var(--primary) inset;
transform: scale(0);
}
25% {
background: transparent;
border-radius: 50%;
box-shadow:
0 0 0 0.375em #db0bdb,
0 0 0 0.375em #db0bdb inset;
transform: scale(1);
}
50% {
background: transparent;
border-radius: 50%;
box-shadow:
0 0 0 0 #db0b0b,
0 0 0 0 #db0b0b inset;
transform: scale(1);
}
50.1% {
background: var(--inputBg);
border-radius: 0.25em;
box-shadow:
0 0 0 0 var(--primary),
0 0 0 0.1em var(--inputBorder) inset;
transform: scale(0);
}
75% {
background: var(--inputBg);
border-radius: 0.25em;
box-shadow:
0 0 0 0 var(--primary),
0 0 0 0.1em var(--inputBorder) inset;
transform: scale(1.1);
}
87.5% {
background: var(--inputBg);
border-radius: 0.25em;
box-shadow:
0 0 0 0 var(--primary),
0 0 0 0.1em var(--inputBorder) inset;
transform: scale(0.95);
}
to {
background: var(--inputBg);
border-radius: 0.25em;
box-shadow:
0 0 0 0 var(--primary),
0 0 0 0.1em var(--inputBorder) inset;
transform: scale(1);
}
}
@keyframes popOutRadio {
from {
background: transparent;
box-shadow:
0 0 0 0.375em var(--primary),
0 0 0 0.76em var(--primary) inset;
transform: scale(0);
}
25% {
background: transparent;
box-shadow:
0 0 0 0.375em #db0bdb,
0 0 0 0.76em #db0bdb inset;
transform: scale(1);
}
50% {
background: transparent;
box-shadow:
0 0 0 0 #db0b0b,
0 0 0 0 #db0b0b inset;
transform: scale(1);
}
50.1% {
background: var(--primary);
box-shadow:
0 0 0 0.1em var(--inputBorder) inset,
0 0 0 0.375em var(--inputBg) inset;
transform: scale(0);
}
75% {
background: var(--primary);
box-shadow:
0 0 0 0.1em var(--inputBorder) inset,
0 0 0 0.375em var(--inputBg) inset;
transform: scale(1.2);
}
87.5% {
background: var(--primary);
box-shadow:
0 0 0 0.1em var(--inputBorder) inset,
0 0 0 0.375em var(--inputBg) inset;
transform: scale(0.9);
}
to {
background: var(--primary);
box-shadow:
0 0 0 0.1em var(--inputBorder) inset,
0 0 0 0.375em var(--inputBg) inset;
transform: scale(1);
}
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
:root {
--bg: #17181c;
--fg: #e3e4e8;
--inputBg: #2e3138;
--inputBgDown: #454954;
--inputBorder: #2e3138;
--inputBorderDown: #454954;
}
}
document.addEventListener("DOMContentLoaded",init);
function init() {
if (document.body.animate)
document.addEventListener("change",partyPop);
}
function partyPop(e) {
let input = e.target,
label = input.closest("label");
if (input && label) {
// do the effect
if (input.checked) {
let particles = 14;
for (let p = 0; p < particles; ++p) {
let angleInc = 360/particles,
angle = angleInc * p;
if (p % 2 === 1)
angle -= angleInc/2;
confetti(label,angle);
}
} else {
// cut the effect short if running
while (label.querySelector("span"))
label.removeChild(label.lastChild);
}
}
}
function confetti(el,angle,hue = 0) {
let particle = document.createElement("span"),
start = 0.75,
end = 2.25,
middle = (start + end) / 2,
angleInRad = angle * Math.PI/180,
angleSin = Math.sin(angleInRad),
angleCos = Math.cos(angleInRad),
pointA = {
x: start * angleSin,
y: start * angleCos
},
pointB = {
x: middle * angleSin,
y: middle * angleCos
},
pointC = {
x: end * angleSin,
y: end * angleCos
},
rootEl = document.querySelector(":root"),
durationInMs = propertyUnitsStripped(rootEl,"--duration","s") * 1e3,
animation = particle.animate([
{
transform: `translate(${pointA.x}em,${pointA.y}em) scale(0)`
},
{
transform: `translate(${pointB.x}em,${pointB.y}em) scale(1)`
},
{
transform: `translate(${pointC.x}em,${pointC.y}em) scale(0)`
}
], {
duration: durationInMs * 0.75,
easing: "linear",
delay: durationInMs * 0.25
}),
bgHue = Math.round(angle);
// color the particle
particle.style.background = `hsl(${bgHue},90%,45%)`;
// spawn the particle
el.appendChild(particle);
animation.onfinish = particle.remove.bind(particle);
}
function propertyUnitsStripped(el,property,unit) {
let cs = window.getComputedStyle(el),
valueRaw = cs.getPropertyValue(property),
value = +valueRaw.substr(0,valueRaw.indexOf(unit));
return value;
}
This Pen doesn't use any external JavaScript resources.