Creating a "Checkmark Spinner" using HTML Code
<!DOCtype html>
<html>
<style>
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--hue: 223;
--bg: hsl(var(--hue), 90%, 20%);
--fg: hsl(var(--hue), 10%, 90%);
--primary: hsl(var(--hue), 90%, 55%);
--primary-dn: hsl(var(--hue), 90%, 45%);
font-size: calc(16px + (24 - 16) * (100vw - 320px) / (1280 - 320));
}
body,
button {
font: 1em/1.5 Hind, sans-serif;
}
body {
background: var(--bg);
color: var(--fg);
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
button {
animation: reappear 3s steps(1) forwards;
background-color: var(--primary);
border-radius: 0.2em;
color: hsl(0, 0%, 100%);
padding: 0.5em 1em;
transition: background-color 0.1s linear;
-webkit-appearance: none;
appearance: none;
}
button:focus,
button:hover {
background-color: var(--primary-dn);
}
button:focus {
outline: none;
}
button,
.check-spinner__worm-a,
.check-spinner__worm-b {
visibility: hidden;
}
.check-spinner {
margin-bottom: 3em;
overflow: visible;
width: 6.25em;
height: 6.25em;
}
.check-spinner__worm-a {
animation: worm-a 1.2s linear;
}
.check-spinner__worm-b {
animation: worm-b 1.2s 1.2s linear forwards;
stroke-dashoffset: 0.01;
}
.check-spinner__circle {
animation: circle 0.2s 2.3s cubic-bezier(0, 0, .42, 1.33) forwards;
}
/* Animations */
@keyframes worm-a {
from {
stroke-dashoffset: 36.1;
visibility: visible;
}
to {
stroke-dashoffset: -252.9;
visibility: visible;
}
}
@keyframes worm-b {
from {
animation-timing-function: linear;
stroke-dasharray: 0 0 72.2 341.3;
visibility: visible;
}
69.7% {
animation-timing-function: ease-out;
stroke-dasharray: 0 207 45 341.3;
visibility: visible;
}
to {
animation-timing-function: ease-out;
stroke-dasharray: 0 297 45 341.3;
visibility: visible;
}
}
@keyframes circle {
from {
r: 0;
}
to {
r: 50px;
}
}
@keyframes reappear {
from {
visibility: hidden;
}
to {
visibility: visible;
}
}
</style>
<body>
<svg class="check-spinner" viewBox="0 0 100 100" width="100px" height="100px">
<defs>
<linearGradient id="cs-grad-1" x1="0.5" y1="0" x2="0.5" y2="1">
<stop offset="0%" stop-color="hsl(0,0%,100%)" />
<stop offset="100%" stop-color="hsl(0,0%,80%)" />
</linearGradient>
<linearGradient id="cs-grad-2a" x1="0.5" y1="0" x2="0.5" y2="1" gradientTransform="rotate(90,0.5,0.5)">
<stop offset="0%" stop-color="hsl(123,90%,55%)" />
<stop offset="100%" stop-color="hsl(183,90%,25%)" />
</linearGradient>
<linearGradient id="cs-grad-2b" x1="0.5" y1="0" x2="0.5" y2="1">
<stop offset="0%" stop-color="hsl(123,90%,55%)" />
<stop offset="100%" stop-color="hsl(183,90%,25%)" />
</linearGradient>
</defs>
<circle class="check-spinner__circle" cx="50" cy="50" r="0" fill="url(#cs-grad-1)" />
<circle class="check-spinner__worm-a" cx="50" cy="50" r="46" fill="none" stroke="url(#cs-grad-2a)" stroke-width="8" stroke-linecap="round" stroke-dasharray="72.2 216.8" stroke-dashoffset="36.1" transform="rotate(-90,50,50)" />
<path class="check-spinner__worm-b" d="M 17.473 17.473 C 25.797 9.15 37.297 4 50 4 C 75.4 4 96 24.6 96 50 C 96 75.4 75.4 96 50 96 C 24.6 96 4 75.4 4 50 C 4 44.253 6.909 36.33 12.5 35 C 21.269 32.913 35 50 35 50 L 45 60 L 65 40" fill="none" stroke="url(#cs-grad-2b)" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="0 0 72.2 341.3" />
</svg>
<button id="replay" type="button" disabled>Replay</button>
<script>
// for restarting the animation
window.addEventListener("DOMContentLoaded", () =>
{
const replay = document.getElementById("replay");
let resetTimeout = null;
let btnTimeout = null;
// prevent keyboard interaction while the button is hidden
const tempHideBtn = btn =>
{
if (btn)
{
const btnCS = window.getComputedStyle(btn);
let btnAnimDur = btnCS.getPropertyValue("animation-duration");
btnAnimDur = +btnAnimDur.split("s")[0] * 1e3;
btn.disabled = true;
clearTimeout(btnTimeout);
btnTimeout = setTimeout(() =>
{
btn.disabled = false;
}, btnAnimDur);
}
};
if (replay)
{
let spinnerEls = [
"circle",
"worm-a",
"worm-b"
];
spinnerEls = spinnerEls.map(e => document.querySelector(`.check-spinner__${e}`));
// hide the button at start
tempHideBtn(replay);
replay.addEventListener("click", function()
{
// kill the animations
spinnerEls.forEach(e =>
{
e.style.animation = "none";
});
this.style.animation = "none";
// restore them, hide the button again
clearTimeout(resetTimeout);
resetTimeout = setTimeout(() =>
{
spinnerEls.forEach(e =>
{
e.removeAttribute("style");
});
this.removeAttribute("style");
tempHideBtn(this);
}, 0);
});
}
});
</script>
</body>
<h1>
<span>MADE by DEVANSH MISHRA</span>
</h1>
</html>
Comments
Post a Comment