0

The following snippet creates a blue box, then turns it purple. Ideally there would be a smooth transition from blue to purple, but it's practically instant instead. The only way I can achieve this is effect is with a timeout (see the second snippet).

let DOM = document.createElement('div');

DOM.classList.add('box');

document.body.appendChild(DOM);

DOM.classList.add('purple');
.box {
  width: 100px;
  height: 100px;
  
  background-color: blue;
 
  transition: background-color 0.25s;
}

.box.purple {
  background-color: purple;
}

let DOM = document.createElement('div');

DOM.classList.add('box');

document.body.appendChild(DOM);

window.setTimeout(() => {
  DOM.classList.add('purple');
}, 100);
.box {
  width: 100px;
  height: 100px;
  
  background-color: blue;
 
  transition: background-color 0.25s;
}

.box.purple {
  background-color: purple;
}

A timeout seems like a bit of a hacky solution that could fail if the machine was slow or cause excess delay on faster machines. Primarily though, I'm looking for a better solution for this problem. Is there a way to await appendChild so that the class is added as soon as the element has been added?

Jack
  • 1,893
  • 1
  • 11
  • 28

2 Answers2

1

Actually any value of delay will work here. Even this works:

window.setTimeout(() => {
    DOM.classList.add('purple');
}, 0);

jsfiddle: https://jsfiddle.net/OscarSaharoy/x46wnehs/1/

This is because of the browser's event loop. All normal code runs, then its effects happen, then any setTimout functions run. So without setTimeout around the classList.add call, the box is added with its background-color being purple already. But with the setTimout, the box is added and then afterwards its background-color changes, causing the smooth transition.

A better solution is maybe to use css keyframes, see here for an implementation using them: https://codepen.io/ericwshea/pen/EyzZQg

So you can specify in css something like animation: color-change 0.25s; on the element you add in and also

@keyframes color-change {
    from {
        background-color: blue;
    }
    to {
        background-color: purple;
    }
}

in the css body.

  • 1
    Thanks, this is great. I'm aware of the animation method. In this situation, I'm hinging a lot of the functionality on the behavior of the transition and this is just an edge case. In my mind it makes more sense to just use this method, rather than maintaining an animation along with a transition. – Jack Apr 04 '21 at 02:13
  • Yep makes sense to me :) – Oscar Saharoy Apr 04 '21 at 06:51
0

Try "onload". it works here. I only added extra CSS b/c I had nothing better to do.

let DOM = document.createElement('div');

DOM.classList.add('box');

document.body.appendChild(DOM);

onload = ()=>DOM.classList.add('purple');
.box {
  width: 100px;
  height: 100px;
  margin: 50px 0px 0px 50px;
  
  background-color: blue;
 
  transition: all 10s cubic-bezier(0.3, 5, 0.5, -2);
}

.box.purple {
  background-color: purple;
  width: 200px;
  height: 200px;
  margin: 0px;
  transform: rotate(1080deg);
}