Why does CSS animation have no duration?
I have several animations that need to transition from one state to another. The transition from state empty
to state bit
works great, which means from bit
to large
, but when I try to use the reverse animation that I add as classes, the animations have no duration. Here is a snippet of my code:
@keyframes empty-bit {
0% {width: 0%;}
100% {width: 4px;}
}
@keyframes bit-large {
0% {width: 4px;}
100% {width: 100%;}
}
.timeline-empty-bit {
animation-name: empty-bit;
animation-fill-mode: forwards;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-delay: 200ms;
}
.timeline-bit-large {
animation-name: bit-large;
animation-fill-mode: forwards;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
}
.timeline-large-bit {
animation-name: bit-large;
animation-fill-mode: forwards;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-direction: reverse;
animation-delay: 200ms;
}
.timeline-bit-empty {
animation-name: empty-bit;
animation-fill-mode: forwards;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-direction: reverse;
}
Here's a jsfiddle: https://jsfiddle.net/9tmm46fz/ Use arrows (left, right) to see animation.
source to share
Animation has a duration. The problem is that the animation is already finished, and changing the class will not play the animation from the beginning unless the animation name property changed. So one way to solve this problem would be to create separate animations for the classes bit-empty
and large-bit
:
.timeline-gauge {
height: 20px;
}
.timeline-gauge-container {
display: inline-block;
height: 100%;
}
.timeline-gauge-part {
display: block;
height: 100%;
width: 0%;
}
@keyframes empty-bit {
0% {width: 0%;}
100% {width: 4px;}
}
@keyframes bit-empty {
0% {width: 0%;}
100% {width: 4px;}
}
@keyframes bit-large {
0% {width: 4px;}
100% {width: 100%;}
}
@keyframes large-bit {
0% {width: 4px;}
100% {width: 100%;}
}
.timeline-empty-bit {
animation-name: empty-bit;
animation-fill-mode: both;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-delay: 200ms;
}
.timeline-bit-large {
animation-name: bit-large;
animation-fill-mode: both;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
}
.timeline-large-bit {
animation-name: large-bit;
animation-fill-mode: both;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-direction: reverse;
animation-delay: 200ms;
}
.timeline-bit-empty {
animation-name: bit-empty;
animation-fill-mode: both;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-direction: reverse;
}
var containers = document.getElementsByClassName("timeline-gauge-container");
var length = containers.length;
for (var i = 0; i < length; i++) {
containers[i].style.width = containers[i].getAttribute("percentage");
}
var parts = document.getElementsByClassName("timeline-gauge-part");
var length = parts.length;
for (var i = 0; i < length; i++) {
parts[i].style.backgroundColor = parts[i].getAttribute("color");
}
var index = 0;
parts[0].classList.add("timeline-empty-bit");
function removeAnimation(part) {
part.classList.remove("timeline-empty-bit");
part.classList.remove("timeline-bit-large");
part.classList.remove("timeline-large-bit");
part.classList.remove("timeline-bit-empty");
}
document.onkeydown = function(event) {
if (event.keyCode == 37 && index > 0) {
removeAnimation(parts[index - 1]);
parts[index - 1].classList.add("timeline-large-bit");
if (index != length) {
removeAnimation(parts[index]);
parts[index].classList.add("timeline-bit-empty");
}
index--;
}
if (event.keyCode == 39 && index < length) {
removeAnimation(parts[index]);
parts[index].classList.add("timeline-bit-large");
if (index != length - 1) {
removeAnimation(parts[index + 1]);
parts[index + 1].classList.add("timeline-empty-bit");
}
index++;
}
};
.timeline-gauge {
height: 20px;
}
.timeline-gauge-container {
display: inline-block;
height: 100%;
}
.timeline-gauge-part {
display: block;
height: 100%;
width: 0%;
}
@keyframes empty-bit {
0% {width: 0%;}
100% {width: 4px;}
}
@keyframes bit-empty {
0% {width: 0%;}
100% {width: 4px;}
}
@keyframes bit-large {
0% {width: 4px;}
100% {width: 100%;}
}
@keyframes large-bit {
0% {width: 4px;}
100% {width: 100%;}
}
.timeline-empty-bit {
animation-name: empty-bit;
animation-fill-mode: both;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-delay: 200ms;
}
.timeline-bit-large {
animation-name: bit-large;
animation-fill-mode: both;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
}
.timeline-large-bit {
animation-name: large-bit;
animation-fill-mode: both;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-direction: reverse;
animation-delay: 200ms;
}
.timeline-bit-empty {
animation-name: bit-empty;
animation-fill-mode: both;
animation-duration: 200ms;
animation-timing-function: ease-in-out;
animation-direction: reverse;
}
<div class="timeline-container">
<div class="timeline-gauge">
<div class="timeline-gauge-container" percentage="5%"><span class="timeline-gauge-part" color="#4f5f6b"></span></div><div class="timeline-gauge-container" percentage="20%"><span class="timeline-gauge-part" color="#237487"></span></div><div class="timeline-gauge-container" percentage="10%"><span class="timeline-gauge-part" color="#00b188"></span></div><div class="timeline-gauge-container" percentage="20%"><span class="timeline-gauge-part" color="#008e6c"></span></div><div class="timeline-gauge-container" percentage="25%"><span class="timeline-gauge-part" color="#99ca34"></span></div><div class="timeline-gauge-container" percentage="20%"><span class="timeline-gauge-part" color="#9059a2"></span></div>
</div>
</div>
The best solution, though, would be to not use animation at all. In my opinion, transitions are a much better tool to work with in this case:
.timeline-gauge {
height: 20px;
}
.timeline-gauge-container {
display: inline-block;
height: 100%;
}
.timeline-gauge-part {
display: block;
height: 100%;
width: 0%;
transition: width 200ms ease-in-out;
}
.timeline-empty-bit {
width: 4px;
transition-delay: 200ms;
}
.timeline-bit-large {
width: 100%;
}
.timeline-large-bit {
width: 4px;
transition-delay: 200ms;
}
.timeline-bit-empty {
width: 0%;
}
var containers = document.getElementsByClassName("timeline-gauge-container");
var length = containers.length;
for (var i = 0; i < length; i++) {
containers[i].style.width = containers[i].getAttribute("percentage");
}
var parts = document.getElementsByClassName("timeline-gauge-part");
var length = parts.length;
for (var i = 0; i < length; i++) {
parts[i].style.backgroundColor = parts[i].getAttribute("color");
}
var index = 0;
parts[0].classList.add("timeline-empty-bit");
function removeAnimation(part) {
part.classList.remove("timeline-empty-bit");
part.classList.remove("timeline-bit-large");
part.classList.remove("timeline-large-bit");
part.classList.remove("timeline-bit-empty");
}
document.onkeydown = function(event) {
if (event.keyCode == 37 && index > 0) {
removeAnimation(parts[index - 1]);
parts[index - 1].classList.add("timeline-large-bit");
if (index != length) {
removeAnimation(parts[index]);
parts[index].classList.add("timeline-bit-empty");
}
index--;
}
if (event.keyCode == 39 && index < length) {
removeAnimation(parts[index]);
parts[index].classList.add("timeline-bit-large");
if (index != length - 1) {
removeAnimation(parts[index + 1]);
parts[index + 1].classList.add("timeline-empty-bit");
}
index++;
}
};
.timeline-gauge {
height: 20px;
}
.timeline-gauge-container {
display: inline-block;
height: 100%;
}
.timeline-gauge-part {
display: block;
height: 100%;
width: 0%;
transition: width 200ms ease-in-out;
}
.timeline-empty-bit {
width: 4px;
transition-delay: 200ms;
}
.timeline-bit-large {
width: 100%;
}
.timeline-large-bit {
width: 4px;
transition-delay: 200ms;
}
.timeline-bit-empty {
width: 0%;
}
<div class="timeline-container">
<div class="timeline-gauge">
<div class="timeline-gauge-container" percentage="5%"><span class="timeline-gauge-part" color="#4f5f6b"></span></div><div class="timeline-gauge-container" percentage="20%"><span class="timeline-gauge-part" color="#237487"></span></div><div class="timeline-gauge-container" percentage="10%"><span class="timeline-gauge-part" color="#00b188"></span></div><div class="timeline-gauge-container" percentage="20%"><span class="timeline-gauge-part" color="#008e6c"></span></div><div class="timeline-gauge-container" percentage="25%"><span class="timeline-gauge-part" color="#99ca34"></span></div><div class="timeline-gauge-container" percentage="20%"><span class="timeline-gauge-part" color="#9059a2"></span></div>
</div>
</div>
source to share