2

I have a tricky problem. When a user presses on a div I want to add a css class to that div with name .active, using css transition. Then, after a short timeout, I want to handle transitionend event where I will remove the class .active from the div. The problem is, if a user presses on the button too fast, say 15-20 times per second, transitionend eventually stops firing.

You can see this effect here(clickable link), open Chrome browser(I wasn't able to reproduce it in FF) and start clicking on the button as fast as you can. After 15-20 clicks transitionend will stop triggering.

I think, when transitionend handler is still working, a user can press the button once again and the div will get .active class, but it will not trigger transition event. The question is - is it possible to write bullet-proof code to clear the .active class using transitionend event only ?

Thank you.

*edit* embedded snippet below

var blk = document.querySelector('.animated-element');
var btn = document.querySelector('.button');
var ctr = document.querySelector('.click-counter');
var lgr = document.querySelector('.logger');

btn.addEventListener('click', function() {
  var currentValue = Number(ctr.innerHTML);
  ctr.innerHTML = ++currentValue;
  if (!blk.classList.contains('active')) {
   blk.classList.add('active');
  }
});

blk.addEventListener('transitionend', function() {
  blk.classList.remove('active');
  var li = document.createElement('li');
  li.innerHTML = 'Transition end';
  lgr.appendChild(li);
});
.scene {
  position: relative;
  width: 300px;
  height: 300px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.animated-element {
  width: 200px;
  height: 200px;
  margin-bottom: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 2em;
  background-color: #ff0000;
  color: white;
  border-radius: 5px;
  transition: all 500ms;
}

.animated-element.active {
  font-weight: 700;
  /* background-color: #ff0055; */
}

.button {
  padding: 5px 10px;
  border: 2px solid black;
  border-radius: 5px;
  text-align: center;
  cursor: pointer;
  user-select: none;
}

.click-counter {
  position: absolute;
  top: 0;
  left: 0;
  min-height: 17px;
  min-width: 17px;
  padding: 2px 4px;
  color: gray;
  font-weight: bold;
  text-align: center;
  border: 2px solid gray;
  border-radius: 50%;
  user-select: none;
}

.logger {
  width: 300px;
  padding: 0;
  list-style: none;
  text-align: center;
}
<body>
  <main>
    <div class="scene">
      <div class="click-counter">0</div>
      <div class="animated-element">
        <span>ABC</span>
      </div>
      <div class="button">
        Press me several times
      </div>
    </div>
    <ul class="logger"></ul>
  </main>
</body>
rossipedia
  • 56,800
  • 10
  • 90
  • 93
  • 1
    You need to post enough code that we can reproduce your problem; see the "*[mcve]*" guidelines for help :) – David Thomas Jul 10 '17 at 14:32
  • Thanks for your reply! If you follow by the link which I've provided ( https://jsfiddle.net/qgrat8s5/ ), you will find the complete example. – Viktor Grafskiy Jul 10 '17 at 14:36
  • 'Questions seeking debugging help ("**why isn't this code working?**") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it **in the question itself**. Questions without **a clear problem statement** are not useful to other readers. See: How to create a [MCVE]'' - quoted verbatim from the 'close' dialogue. The code must be in the question, in order to guard against link-rot or deletion of the code at a later date, which renders this question useless to any future visitors. – David Thomas Jul 10 '17 at 14:40
  • I embedded the snippet directly in the post, and I was also able to reproduce the problem in Chrome. `transitionend` doesn't even fire in Safari (with this example). – rossipedia Jul 10 '17 at 14:43
  • Oddly enough, if I uncomment the `background-color` rule in the `.active` class, I am no longer able to reproduce in Chrome (ie: the bug goes away). Strange... – rossipedia Jul 10 '17 at 14:46
  • @rossipedia: because the animation of the `background-color` takes time which, I think, seems to prevent the browser from having problems. If `font-weight` is replaced by `font-size`, and `background-color` is removed, ([demo](https://jsfiddle.net/davidThomas/qgrat8s5/20/)) or commented out ([demo](https://jsfiddle.net/davidThomas/qgrat8s5/21/)) the problem similarly disappears. I think the issue with `font-weight` is that it increments in jumps of 100, and those 'jumps' require a font that supports the interim weights, which many don't. – David Thomas Jul 10 '17 at 14:57
  • Thank you Friends. Unfortunately the only solution I’ve found so far is to replace `transitionend` with setTimeout, which, in my humble opinion, is less elegant way to remove the `.active` class. – Viktor Grafskiy Jul 10 '17 at 19:48
  • Maybe it'll be helpful for someone - I filed a bug report at chrome bugtracker, please see [here](https://bugs.chromium.org/p/chromium/issues/detail?id=740486). Thank you. – Viktor Grafskiy Jul 13 '17 at 11:22

0 Answers0