GibboK
GibboK

Reputation: 73938

CSS3 Keyframe Animation issue with "timelines"

In the following example I have 3 divs they need to be animated using CSS3 Keyframe Animation with the following rules (when I mention hidden/show in the text below actually use opacity 0.1/1 in the CSS):

A) When the page load

B) When User click btnCorrect

C) When User click btnWrong

Currently:

But I am not able to fix the following cases:

I would like to know how to fix it possibly using only CSS 3.

Test the following example using only Google Chrome.

var btnCorrect = document.getElementById('btnCorrect');
var btnWrong = document.getElementById('btnWrong');
var ladyDefault = document.getElementById('ladyDefault');
var ladyCorrect = document.getElementById('ladyCorrect');
var ladyWrong = document.getElementById('ladyWrong');

btnCorrect.addEventListener('click', function(event) {
    ladyDefault.classList.add('hideLadyDefault');
    ladyWrong.classList.add('hideLadyWrong');
    ladyCorrect.classList.add('showLadyCorrect');
});
btnWrong.addEventListener('click', function(event) {
    ladyDefault.classList.add('hideLadyDefault');
    ladyCorrect.classList.add('hideLadyCorrect');
    ladyWrong.classList.add('showLadyWrong');
});
#ladyDefault,
#ladyCorrect,
#ladyWrong {
    width: 100px;
    height: 150px;
    display: inline-block;
    margin: 5px;
}

#ladyDefault {
    background-color: blue;
}

#ladyCorrect {
    background-color: green;
    opacity: 0.1;
}

#ladyWrong {
    background-color: red;
    opacity: 0.1;
}

#btnCorrect,
#btnWrong {
    height: 50px;
    width: 100px;
    display: inline-block;
    margin: 5px;
}

#btnCorrect {
    background-color: lime;
}

#btnWrong {
    background-color: darkred;
}
/*
--------------------------- lady default
*/
@keyframes hideLadyDefault {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0.1;
    }
}

.hideLadyDefault {
    animation-name: hideLadyDefault;
    animation-duration: 0;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: forwards;
    animation-delay: 0;
}
/*
--------------------------- lady correct
*/
@keyframes showLadyCorrect {
    0% {
        opacity: 0.1;
    }
    100% {
        opacity: 1;
    }
}

.showLadyCorrect {
    animation-name: showLadyCorrect;
    animation-duration: 1s;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: forwards;
    animation-delay: 0;
}

@keyframes hideLadyCorrect {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0.1;
    }
}

.hideLadyCorrect {
    animation-name: hideLadyCorrect;
    animation-duration: 0;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: both
    animation-delay: 0;
}
/*
--------------------------- lady wrong
*/
@keyframes showLadyWrong {
    0% {
        opacity: 0.1;
    }
    100% {
        opacity: 1;
    }
}

.showLadyWrong {
    animation-name: showLadyWrong;
    animation-duration: 1s;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: forwards;
    animation-delay: 0;
}

@keyframes hideLadyWrong {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0.1;
    }
}

.hideLadyWrong {
    animation-name: hideLadyWrong;
    animation-duration: 0;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: both;
    animation-delay: 0;
}
<div id="ladyDefault">ladyDefault</div>
<div id="ladyCorrect">ladyCorrect</div>
<div id="ladyWrong">ladyWrong</div>

<div id="btnCorrect">btnCorrect</div>
<div id="btnWrong">btnWrong</div>

Upvotes: 2

Views: 68

Answers (2)

Harry
Harry

Reputation: 89770

Original Answer:

You need to remove the previous classes also before adding the new ones. When you don't remove the other class before adding a new one, each of them try to set an animation on the same element and as is always the case with CSS, the selector (class) which is defined later in the CSS wins.

var btnCorrect = document.getElementById('btnCorrect');
var btnWrong = document.getElementById('btnWrong');
var ladyDefault = document.getElementById('ladyDefault');
var ladyCorrect = document.getElementById('ladyCorrect');
var ladyWrong = document.getElementById('ladyWrong');

btnCorrect.addEventListener('click', function(event) {
  ladyDefault.classList.add('hideLadyDefault');
  ladyWrong.classList.remove('showLadyWrong');
  ladyWrong.classList.add('hideLadyWrong');
  ladyCorrect.classList.remove('hideLadyCorrect');
  ladyCorrect.classList.add('showLadyCorrect');
});
btnWrong.addEventListener('click', function(event) {
  ladyDefault.classList.add('hideLadyDefault');
  ladyCorrect.classList.remove('showLadyCorrect');
  ladyCorrect.classList.add('hideLadyCorrect');
  ladyWrong.classList.remove('hideLadyWrong');
  ladyWrong.classList.add('showLadyWrong');
});
#ladyDefault,
#ladyCorrect,
#ladyWrong {
  width: 100px;
  height: 150px;
  display: inline-block;
  margin: 5px;
}
#ladyDefault {
  background-color: blue;
}
#ladyCorrect {
  background-color: green;
  opacity: 0.1;
}
#ladyWrong {
  background-color: red;
  opacity: 0.1;
}
#btnCorrect,
#btnWrong {
  height: 50px;
  width: 100px;
  display: inline-block;
  margin: 5px;
}
#btnCorrect {
  background-color: lime;
}
#btnWrong {
  background-color: darkred;
}
/*
--------------------------- lady default
*/

@keyframes hideLadyDefault {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0.1;
  }
}
.hideLadyDefault {
  animation-name: hideLadyDefault;
  animation-duration: 0;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-delay: 0;
}
/*
--------------------------- lady correct
*/

@keyframes showLadyCorrect {
  0% {
    opacity: 0.1;
  }
  100% {
    opacity: 1;
  }
}
.showLadyCorrect {
  animation-name: showLadyCorrect;
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-delay: 0;
}
@keyframes hideLadyCorrect {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0.1;
  }
}
.hideLadyCorrect {
  animation-name: hideLadyCorrect;
  animation-duration: 0;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: both animation-delay: 0;
}
/*
--------------------------- lady wrong
*/

@keyframes showLadyWrong {
  0% {
    opacity: 0.1;
  }
  100% {
    opacity: 1;
  }
}
.showLadyWrong {
  animation-name: showLadyWrong;
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-delay: 0;
}
@keyframes hideLadyWrong {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0.1;
  }
}
.hideLadyWrong {
  animation-name: hideLadyWrong;
  animation-duration: 0;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: both;
  animation-delay: 0;
}
<div id="ladyDefault">ladyDefault</div>
<div id="ladyCorrect">ladyCorrect</div>
<div id="ladyWrong">ladyWrong</div>

<div id="btnCorrect">btnCorrect</div>
<div id="btnWrong">btnWrong</div>


Solution with only one keyframe rule:

You can also achieve the same effect with a single @keyframes rule instead of using multiple. All that would be needed is to set the animation-direction as reverse for the hide. But the old class must still be removed because once an animation is set on the element, the UA remembers its execution as mentioned in this answer of mine.

var btnCorrect = document.getElementById('btnCorrect');
var btnWrong = document.getElementById('btnWrong');
var ladyDefault = document.getElementById('ladyDefault');
var ladyCorrect = document.getElementById('ladyCorrect');
var ladyWrong = document.getElementById('ladyWrong');

btnCorrect.addEventListener('click', function(event) {
  ladyDefault.classList.add('hideLadyDefault');
  ladyWrong.classList.remove('showLadyWrong');
  ladyWrong.classList.add('hideLadyWrong');
  ladyCorrect.classList.remove('hideLadyCorrect');
  ladyCorrect.classList.add('showLadyCorrect');
});
btnWrong.addEventListener('click', function(event) {
  ladyDefault.classList.add('hideLadyDefault');
  ladyCorrect.classList.remove('showLadyCorrect');
  ladyCorrect.classList.add('hideLadyCorrect');
  ladyWrong.classList.remove('hideLadyWrong');
  ladyWrong.classList.add('showLadyWrong');
});
#ladyDefault,
#ladyCorrect,
#ladyWrong {
  width: 100px;
  height: 150px;
  display: inline-block;
  margin: 5px;
}
#ladyDefault {
  background-color: blue;
}
#ladyCorrect {
  background-color: green;
  opacity: 0.1;
}
#ladyWrong {
  background-color: red;
  opacity: 0.1;
}
#btnCorrect,
#btnWrong {
  height: 50px;
  width: 100px;
  display: inline-block;
  margin: 5px;
}
#btnCorrect {
  background-color: lime;
}
#btnWrong {
  background-color: darkred;
}
/*
--------------------------- lady default
*/

.hideLadyDefault {
  animation-name: show;
  animation-duration: 0;
  animation-iteration-count: 1;
  animation-direction: reverse;
  animation-fill-mode: forwards;
  animation-delay: 0;
}
/*
--------------------------- lady correct
*/

@keyframes show {
  0% {
    opacity: 0.1;
  }
  100% {
    opacity: 1;
  }
}
.showLadyCorrect {
  animation-name: show;
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-delay: 0;
}
.hideLadyCorrect {
  animation-direction: reverse;
}
/*
--------------------------- lady wrong
*/

.showLadyWrong {
  animation-name: show;
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-delay: 0;
}
.hideLadyWrong {
  animation-direction: reverse;
}
<div id="ladyDefault">ladyDefault</div>
<div id="ladyCorrect">ladyCorrect</div>
<div id="ladyWrong">ladyWrong</div>

<div id="btnCorrect">btnCorrect</div>
<div id="btnWrong">btnWrong</div>


Solution with transition: (might be better fit)

The better option would be to use transition if you could instead of animation. Here you could just set the opacity via inline style attributes and let the transition property handle the rest. Unlike the animations, transitions can execute the reverse state by default. (This is the best bet if it only a simple change of opacity from 0.1 to 1, if it is a complex multi-step change the transitions are out of scope.)

var btnCorrect = document.getElementById('btnCorrect');
var btnWrong = document.getElementById('btnWrong');
var ladyDefault = document.getElementById('ladyDefault');
var ladyCorrect = document.getElementById('ladyCorrect');
var ladyWrong = document.getElementById('ladyWrong');

btnCorrect.addEventListener('click', function(event) {
  ladyDefault.style["opacity"] = "0.1";
  ladyWrong.style["opacity"] = "0.1";
  ladyCorrect.style["opacity"] = "1";
});
btnWrong.addEventListener('click', function(event) {
  ladyDefault.style["opacity"] = "0.1";
  ladyCorrect.style["opacity"] = "0.1";
  ladyWrong.style["opacity"] = "1";
});
#ladyDefault,
#ladyCorrect,
#ladyWrong {
  width: 100px;
  height: 150px;
  display: inline-block;
  margin: 5px;
}
#ladyDefault {
  background-color: blue;
  transition: all 1s ease;
}
#ladyCorrect {
  background-color: green;
  opacity: 0.1;
  transition: all 1s ease;
}
#ladyWrong {
  background-color: red;
  opacity: 0.1;
  transition: all 1s ease;
}
#btnCorrect,
#btnWrong {
  height: 50px;
  width: 100px;
  display: inline-block;
  margin: 5px;
}
#btnCorrect {
  background-color: lime;
}
#btnWrong {
  background-color: darkred;
}
<div id="ladyDefault">ladyDefault</div>
<div id="ladyCorrect">ladyCorrect</div>
<div id="ladyWrong">ladyWrong</div>

<div id="btnCorrect">btnCorrect</div>
<div id="btnWrong">btnWrong</div>

Upvotes: 2

Nikhil Nanjappa
Nikhil Nanjappa

Reputation: 6642

You are adding all classes correctly, but you are not removing the added classes later, thats the issue. Change your listeners to

btnCorrect.addEventListener('click', function(event) {
    ladyDefault.classList.add('hideLadyDefault');
    ladyWrong.classList.add('hideLadyWrong');
    ladyCorrect.classList.add('showLadyCorrect');
    ladyCorrect.classList.remove('hideLadyCorrect'); //added
});
btnWrong.addEventListener('click', function(event) {
    ladyDefault.classList.add('hideLadyDefault');
    ladyCorrect.classList.add('hideLadyCorrect');
    ladyWrong.classList.add('showLadyWrong');
    ladyWrong.classList.remove('hideLadyWrong'); //added
});

var btnCorrect = document.getElementById('btnCorrect');
var btnWrong = document.getElementById('btnWrong');
var ladyDefault = document.getElementById('ladyDefault');
var ladyCorrect = document.getElementById('ladyCorrect');
var ladyWrong = document.getElementById('ladyWrong');

btnCorrect.addEventListener('click', function(event) {
    ladyDefault.classList.add('hideLadyDefault');
    ladyWrong.classList.add('hideLadyWrong');
    ladyCorrect.classList.add('showLadyCorrect');
    ladyCorrect.classList.remove('hideLadyCorrect');
});
btnWrong.addEventListener('click', function(event) {
    ladyDefault.classList.add('hideLadyDefault');
    ladyCorrect.classList.add('hideLadyCorrect');
    ladyWrong.classList.add('showLadyWrong');
    ladyWrong.classList.remove('hideLadyWrong');
});
#ladyDefault,
#ladyCorrect,
#ladyWrong {
    width: 100px;
    height: 150px;
    display: inline-block;
    margin: 5px;
}

#ladyDefault {
    background-color: blue;
}

#ladyCorrect {
    background-color: green;
    opacity: 0.1;
}

#ladyWrong {
    background-color: red;
    opacity: 0.1;
}

#btnCorrect,
#btnWrong {
    height: 50px;
    width: 100px;
    display: inline-block;
    margin: 5px;
}

#btnCorrect {
    background-color: lime;
}

#btnWrong {
    background-color: darkred;
}
/*
--------------------------- lady default
*/
@keyframes hideLadyDefault {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0.1;
    }
}

.hideLadyDefault {
    animation-name: hideLadyDefault;
    animation-duration: 0;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: forwards;
    animation-delay: 0;
}
/*
--------------------------- lady correct
*/
@keyframes showLadyCorrect {
    0% {
        opacity: 0.1;
    }
    100% {
        opacity: 1;
    }
}

.showLadyCorrect {
    animation-name: showLadyCorrect;
    animation-duration: 1s;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: forwards;
    animation-delay: 0;
}

@keyframes hideLadyCorrect {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0.1;
    }
}

.hideLadyCorrect {
    animation-name: hideLadyCorrect;
    animation-duration: 0;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: both
    animation-delay: 0;
}
/*
--------------------------- lady wrong
*/
@keyframes showLadyWrong {
    0% {
        opacity: 0.1;
    }
    100% {
        opacity: 1;
    }
}

.showLadyWrong {
    animation-name: showLadyWrong;
    animation-duration: 1s;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: forwards;
    animation-delay: 0;
}

@keyframes hideLadyWrong {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0.1;
    }
}

.hideLadyWrong {
    animation-name: hideLadyWrong;
    animation-duration: 0;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: both;
    animation-delay: 0;
}
<div id="ladyDefault">ladyDefault</div>
<div id="ladyCorrect">ladyCorrect</div>
<div id="ladyWrong">ladyWrong</div>

<div id="btnCorrect">btnCorrect</div>
<div id="btnWrong">btnWrong</div>

Upvotes: 1

Related Questions