0

The best way to explain my problem is these are two demos:

And that are they:

Demo 1 (works as expected in chrome, in firefox it doesn't work)

let handler = function () {
    block.classList.add("visible");
    requestAnimationFrame(() => block.classList.add("move"));
    block.addEventListener(
        "transitionend",
        () => {
            console.log("style is removed");
            this.addEventListener("click", handler, { once: true });
            block.classList.remove("move");
        },
        { once: true }
    );
};
btn.addEventListener("click", handler, { once: true });
.main {
    display: none;
    width: 100px;
    height: 100px;
    background: red;
    transition: all 5.5s ease;
}
.visible {
    display: block;
}
.move {
    transform: translateX(100px);
    background: blue;
}
<div id="block" class="main"></div>
<button id="btn">Animate</button>

Demo 2 (works incorrect)

let handler = function () {
    block.classList.add("visible");
    block.classList.add("move");
    block.addEventListener(
        "transitionend",
        () => {
            console.log("style is removed");
            this.addEventListener("click", handler, { once: true });
            block.classList.remove("move");
        },
        { once: true }
    );
};
btn.addEventListener("click", handler, { once: true });
.main {
    display: none;
    width: 100px;
    height: 100px;
    background: red;
    transition: all 5.5s ease;
}
.visible {
    display: block;
}
.move {
    transform: translateX(100px);
    background: blue;
}
<div id="block" class="main"></div>
<button id="btn">Animate</button>

I'll fast emphasize differences between two demos:

  1. first demo has requestAnimationFrame

  1. <div> block has class "visible" before starting a click handler in first demo
  2. In the click handler, it has code for adding class "visible" in the second demo

So main question is: Why second demo doesn't fire transitionend event and why I don't see transition?


Extra demo

let handler = function () {
    alert(1);
    block.classList.add("visible");
    alert(2);
    setTimeout(() => {
      alert(4);
      block.classList.add("move");
      alert(5);
    });
    block.addEventListener(
        "transitionend",
        () => {
            console.log("style is removed");
            this.addEventListener("click", handler, { once: true });
            block.classList.remove("move");
        },
        { once: true }
    );
    alert(3);
};
btn.addEventListener("click", handler, { once: true });
.main {
    display: none;
    width: 100px;
    height: 100px;
    background: red;
    transition: all 5.5s ease;
}
.visible {
    display: block;
}
.move {
    transform: translateX(100px);
    background: blue;
}
<div id="block" class="main"></div>
<button id="btn">Animate</button>

Checkout it in chrome and firefox, seems what some part of code invokes repainting earlier, if it is not, correct me and explain why.

MaximPro
  • 563
  • 8
  • 21

1 Answers1

0

Just a few things here, you first wrote block.classList.add("visible"); I think the main reason why is that you missed either intentionally or this class="main visible" as you wrote it like class="main" in your code.

You actually needed to make use of the css style technique which is use the none to hide the div and block to show it. Here is what I did to hide it at first .visible { display: none; } then to show it I used document.getElementById("block").style.display = "block";. I added a small delay to give it a time to finish displaying then start animating which works but does not work if you remove the delay.

let handler = function () {
        //block.classList.add("visible");
document.getElementById("block").style.display = "block"; 
setTimeout(() => { block.classList.add("move"); }, 300);
        //block.classList.add("move");

    block.addEventListener(
        "transitionend",
        () => {
            console.log("style is removed");
            this.addEventListener("click", handler, { once: true });
            block.classList.remove("move");
        },
        { once: true }
    );
    };
    btn.addEventListener("click", handler, { once: true });
 .main {
        display: none;
        width: 100px;
        height: 100px;
        background: red;
        transition: all 5.5s ease;
    }
    .visible {
        display: none;
    }
    .move {
        transform: translateX(100px);
        background: blue;
    }
    <div id="block" class="main visible"></div>
    <button id="btn">Animate</button>

So to answer as to why it wasn't firing, that due to the reasons I've explained on top.

  • Well, it's a nice try, but I did not expect such answer like your. Have you read my main question? It's very important. If you can explain, I'll hear you with pleasure. – MaximPro Sep 05 '21 at 21:10
  • Your second demo jumps straight to blue due to that your div doesn't have visible during the click, and on the other side you are attempting to add instead of showing it (presenting the div to the view). Please rerun your second demo on a code snippet you will see that it runs this CSS code `.move { transform: translateX(100px); background: blue; }` simply because `block.classList.add("visible");` doesn't work here, infact `block.classList.add("visible");` is the wrong approach – Mlungisi Ndlela Sep 05 '21 at 21:39
  • Alright, checkout my first example again, and try to answer why it's working (I've rewritten it) – MaximPro Sep 05 '21 at 21:54
  • Now none of your demo works as expected. Why? you remove visible in your div class. As I've stated you should make use of the CSS style approach to show or hide the div not how you are doing it. Put `class="main visible"` in your div class it will work. – Mlungisi Ndlela Sep 05 '21 at 22:04
  • First demo is still working as expected, I can see transition. Why you've said what it doesn't work? – MaximPro Sep 05 '21 at 22:09
  • It no longer working on my side, just also tested it now, first and second demo don't work they show the same thing, provided answer still work. You may have to refresh your browser and check it out – Mlungisi Ndlela Sep 05 '21 at 22:14
  • I've got fresh chrome and firefox, and I don't know why it doesn't work on your side – MaximPro Sep 05 '21 at 22:17
  • Really in firefox 91.0.2 (64-bit) my first demo is broke. But in chrome 92.0.4515.159 (64-bit) code works fine. I am confused – MaximPro Sep 05 '21 at 22:22
  • Well Chrome and Firefox don't have the same strict rules which might be a result why it work on Chrome. Also if it works then both demos should work. – Mlungisi Ndlela Sep 05 '21 at 22:26
  • Ridiculous, but they don't, in chrome first one works, second one is broke. In firefox both demos are broken. And I don't realize, why? – MaximPro Sep 05 '21 at 22:32
  • I've added special demo, if you have chrome and firefox run this code on both. You'll see different behaviour between them. – MaximPro Sep 05 '21 at 22:38
  • Extra is running on Firefox and chrome, on the first demo I see you added something else `requestAnimationFrame(() => block.classList.add("move"));`. – Mlungisi Ndlela Sep 05 '21 at 23:01
  • In "extra" I've just added alerts and changed from rAf to setTimeout. rAF is wrote in first demo. Also behaviour in different browsers is different. For example in chrome you can see how block will be rendered on alert(2), but in chrome it will be rendered on alert(4) – MaximPro Sep 05 '21 at 23:07