Search code examples
csstimercss-animationsprogress

Simple Countdown Circle Animation with Pure CSS


There are many scss samples, but only a few with CSS. Somebody know a simple way to animate a circle countdown made with pure CSS.


Solution

  • Here is a simple and short CSS-only example:

    .timer {
        background: -webkit-linear-gradient(left, skyBlue 50%, #eee 50%);
        border-radius: 100%;
        height: calc(var(--size) * 1px);
        width: calc(var(--size) * 1px);
        position: relative;
        -webkit-animation: time calc(var(--duration) * 1s) steps(1000, start) infinite;
          -webkit-mask: radial-gradient(transparent 50%,#000 50%);
          mask: radial-gradient(transparent 50%,#000 50%);
    }
    .mask {
        border-radius: 100% 0 0 100% / 50% 0 0 50%;
        height: 100%;
        left: 0;
        position: absolute;
        top: 0;
        width: 50%;
        -webkit-animation: mask calc(var(--duration) * 1s) steps(500, start) infinite;
        -webkit-transform-origin: 100% 50%;
    }
    @-webkit-keyframes time {
        100% {
            -webkit-transform: rotate(360deg);
        }
    }
    @-webkit-keyframes mask {
        0% {
            background: #eee;
            -webkit-transform: rotate(0deg);
        }
        50% {
            background: #eee;
            -webkit-transform: rotate(-180deg);
        }
        50.01% {
            background: skyBlue;
            -webkit-transform: rotate(0deg);
        }
        100% {
            background: skyBlue;
            -webkit-transform: rotate(-180deg);
        }
    }
    <div class="timer" style="--duration: 3;--size: 30;">
        <div class="mask"></div>
    </div>
    
    <div class="timer" style="--duration: 10;--size: 100;">
        <div class="mask"></div>
    </div>

    Like shown above, you can control the size and duration with variables.

    Edit:

    To answer the comment from @COil, asking for a text countdown: Thanks to the answers on these questions: https://stackoverflow.com/a/53602554/7965241 and https://stackoverflow.com/a/40179718/7965241 I was able to piece together a solution, but it is very static, as it requires a minumum of X animation steps (X being the duration in seconds) to display the number in steps of 1:

    .countdown:after {
        counter-reset: duration calc(var(--duration) * 1.0);
        content: counter(duration); 
        animation: spin calc(var(--duration) * 1s) infinite;
    }
    
    @keyframes spin {
        1% {
            counter-reset: duration calc(var(--duration) * 1.0);
            content: counter(duration); 
        }
        11% {
            counter-reset: duration calc(var(--duration) * 0.9);
            content: counter(duration); 
        }
        21% {
            counter-reset: duration calc(var(--duration) * 0.8);
            content: counter(duration); 
        }
        31% {
            counter-reset: duration calc(var(--duration) * 0.7);
            content: counter(duration); 
        }
        41% {
            counter-reset: duration calc(var(--duration) * 0.6);
            content: counter(duration); 
        }
        51% {
            counter-reset: duration calc(var(--duration) * 0.5);
            content: counter(duration); 
        }
        61% {
            counter-reset: duration calc(var(--duration) * 0.4);
            content: counter(duration); 
        }
        71% {
            counter-reset: duration calc(var(--duration) * 0.3);
            content: counter(duration); 
        }
        81% {
            counter-reset: duration calc(var(--duration) * 0.2);
            content: counter(duration); 
        }
        91% {
            counter-reset: duration calc(var(--duration) * 0.1);
            content: counter(duration); 
        }
        100% {
            counter-reset: duration calc(var(--duration) * 0);
            content: counter(duration); 
        }
    }
    <p class="countdown" style="--duration: 10;">
    </p>