skip to Main Content

I have an animated progress bar where I use the animation-iteration-count CSS property to specify the progress in percentage. So if the progress should be 50% I set animation-iteration-count: 0.5. On page load this works fine and the progress bar animate from 0% to 50%.

But how can I change the progress bar value and continue the CSS animation cycle to a new value? Either a bigger or smaller value. When I change the animation-iteration-count value dynamically with JavaScript the animation jumps to that new value. I want a smooth transition from one value to the next.

If I only wanted to animate the width I could use CSS transitions and have no problems. But since I also want to change the color of the progress bar relative to the progress a CSS animation it much easier.

I have tried experimenting with animation-play-state without luck, but maybe I just didn’t do it right. I have also experimented with using @container queries to change the background color of the progress and then use CSS transitions for the width, but that’s not doable either.

In the code snippet below you can see my progress bar and click the button to increase the value of the animation-iteration-count property to see that it jumps.

const progressBar = document.querySelector(".progress-bar");
const button = document.querySelector("button");
button.addEventListener("click", (e) => {
 progressBar.style.animationIterationCount = "0.75";
})
.progress-bar-container {
    width: 500px;
    outline: 1px solid black;
}

.progress-bar {
    height: 10px;
    animation: progressBarAnimation 2s linear forwards;
}


@keyframes progressBarAnimation {
    0% {
        background-color: red;
        width: 0;
    }
    30% {
        background-color: yellow;
        width: 30%;
    }
    60% {
        background-color: green;
        width: 60%;
    }
    100% {
        background-color: blue;
        width: 100%;
    }
}
<div class="progress-bar-container">
    <div class="progress-bar" style="animation-iteration-count: 0.5">
    </div>
</div>
<button>Increase progress</button>

Thank you for helping me out!

Regards,
Jeppe

2

Answers


  1. Chosen as BEST ANSWER

    Based on the first answer I tried using a linear-gradient as can be seen in the code snippet.

    const progressBarContainer = document.querySelector(".progress-bar-container");
    
    const button = document.querySelector("button");
    progressBarContainer.style.setProperty("--progress", "0")
    button.addEventListener("click", (e) => {
        const current = +progressBarContainer.style.getPropertyValue("--progress");
        progressBarContainer.style.setProperty("--progress", `${current + 10}`);
    })
    .progress-bar-container {
        outline: 1px solid black;
        position: relative;
        background: white;
          --progress: 0;
    }
    
    .progress-bar {
        height: 5px;
        transition: width 1s ease-in-out;
        position: relative;
            width: calc(var(--progress) * 1%);
    }
    
    .progress-bar:before {
        content:"";
        position:absolute;
        top:0;
        left:0;
        right:0;
        bottom:0;
        background: linear-gradient(
                    #ff4d62 0% 30%,
                    #FF6D5B 30% 40%,
                    #FF8C54 40% 50%,
                    #FFAA61 50% 60%,
                    #FFC76D 60% 65%,
                    #FFE57A 65% 70%,
                    #D9E27D 70% 80%,
                    #B3DF80 80% 85%,
                    #8EDC82 85% 90%,
                    #68D985 90% 95%,
                    #42D688 95% 100%,
                    #3EC67B 100%
            );
            background-size: auto 100px;
            background-position: 0 calc(var(--progress) * -1px);
    }
    <div class="progress-bar-container">
        <div class="progress-bar"></div>
    </div>
    <button>Increase progress</button>

    For some reason the gradient returns to the first color (red) when background-position is at 0 -96px to 0 -100px. Why is that? I didn't expect that. I also can't make it work with positive numbers going from 0px to 100px. If someone can explain that as well it will be great.


  2. animation-iteration-count isn’t a property used to stop/start the animation.

    Setting that through css will restart the animation.

    You’re probably better of creating a regular progressbar that will use width to animate the grow. Then use a :before element to apply a gradient to your liking.

    const progressBar = document.querySelector(".progress-bar");
    const button = document.querySelector("button");
    
    button.addEventListener("click", (e) => {
        const current = +progressBar.style.width.slice(0, -1);
        progressBar.style.width = (current === 100)
            ? '25%'
            : (current + 25) + '%';
    })
    .progress-bar-container {
        width: 500px;
        outline: 1px solid black;
        position: relative;
        background: white;
    }
    
    .progress-bar {
        height: 10px;
        transition: width 1s ease-in-out;
        -webkit-mask:linear-gradient(#fff 0 0);
        mask:linear-gradient(#fff 0 0);
    }
    
    .progress-bar:before {
        content:"";
        position:absolute;
        top:0;
        left:0;
        right:0;
        bottom:0;
        background: linear-gradient(
            90deg, 
            rgba(255,0,0,1) 25%, 
            rgba(247,255,0,1) 50%, 
            rgba(0,255,19,1) 80%, 
            rgba(1,0,255,1) 99%
        );
    }
    <div class="progress-bar-container">
        <div class="progress-bar" style="width: 50%"></div>
    </div>
    <button>Increase progress</button>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search