2

I want to do the following things:

  1. show a div element;
  2. move it to a an initial position;
  3. set transition properties;
  4. move it to the target position using CSS transition.

A minimal example:

function bla() {
  /*
    var obj = $('#box');
    obj.css("left", "200px");
    obj.css("display", "initial");
    obj.addClass("trans");
    obj.css("left", "500px");
  */

  var elem = document.getElementById('box');
  elem.style.left = "200px";
  elem.style.display = "initial";
  elem.className = "box trans";
  elem.style.left = "500px";
}
#btn {
  position: fixed;
  top: 60px;
  left: 0px;
  width: 50px;
  height: 50px;
  background-color: #FEDCBA;
}
.box {
  display: none;
  position: fixed;
  top: 0px;
  left: 0px;
  width: 50px;
  height: 50px;
  background-color: #ABCDEF;
}
.box.trans {
  -webkit-transition: left 2s;
  -moz-transition: left 2s;
  transition: left 2s;
}
<div id="box" class="box"></div>
<div id="btn" onclick="bla()">click here</div>

JSFiddle.

It does not work at all. What is wrong?

If I set the element initially visible, I get a smooth transition starting from the origin left:0 which is totally strange because I assign elem.style.left = "200px"; before I actually add the transition properties...

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
DyingSoul
  • 231
  • 5
  • 11

4 Answers4

2

You should avoid using style in javascript, just switch class years put all your animation in your css file.

You can't put transition together with display: none;, you have to use opacity: 0; instead.

function bla()
{
 var obj = $('#box');
 obj.toggleClass("trans");
}
#btn
{
  position:fixed;
  top:60px;
  left:0px;
  width:50px;
  height:50px;
  background-color:#FEDCBA;
}

.box
{
  opacity: 0;
  position:fixed;
  top:0px;
  left:0px;
  width:50px;
  height:50px;
  background-color:#ABCDEF;
  -webkit-transition: transform  2s,opacity  2s;
  transition: transform  2s,opacity  2s;
}

.box.trans
{
  opacity: 1;
  -ms-transform: translate(500px,0); /* IE 9 */
  -webkit-transform: translate(500px,0); /* Safari */
  transform: translate(500px,0);
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box" class="box">
</div>
<div id="btn" onclick="bla()">
click here
</div>
EikiProg
  • 83
  • 9
2

DOM changes don't take effect until they can be rendered. Javascript is single-threaded (meaning you cannot run two pieces of code simultaneously), and run on the same thread as the render cycle.

Because of this, the renderer cannot fire unless you give it time to look at the new state of the DOM by deferring execution of your JS code (using setTimeout or requestAnimationFrame). So unless you give the browser time to render, only the final value before the renderer gets to look at the DOM is what matters.

This answer to a previous question goes over the exceptions to the rule.

Here's an updated version of your jsfidde that uses requestAnimationFrame to get around the issue.

kevin.groat
  • 1,274
  • 12
  • 21
1

I can not explain why. Maybe someone could, I'd be curious too, but with a time-out works.

setTimeout(function(){
    elem.style.left = "500px";
},1);

It is probably too fast assigning properties left 500 and the transition to record the old location 200?

https://jsfiddle.net/StepBaro/s82rj48q/2/

Baro
  • 5,300
  • 2
  • 17
  • 39
  • Yes i thought about that it could be a timing thing.. but it does not make sense because this would violate the order of the calls. When i set the position to 200 then it should set the position. It must not wait with the change after the next instructions.. – DyingSoul Feb 10 '17 at 16:06
  • Evidently the instructions running simultaneously. I tried to replace the timeout with a very long for loop, and does not work, I think it not refresh the dom, I do not know if you have other solutions. Or jquery, but it is the same logic https://jsfiddle.net/StepBaro/s82rj48q/9/ – Baro Feb 10 '17 at 16:34
0

It's because you have the div hidden, so it first need to display it and then add the transition, that is why it needs the delay.

Joan Miquel
  • 286
  • 2
  • 8
  • Yeah that's why i call `elem.style.display = "initial";` first to display it. I even change its position after i displayed it. – DyingSoul Feb 10 '17 at 16:12
  • Yes, but you are doing both things at the same time – Joan Miquel Feb 10 '17 at 16:17
  • You could bind the animation to the display change. Once you display it then launch the animation. But you definitely need to first display it, otherwise it will do both things at the same time. – Joan Miquel Feb 10 '17 at 16:22