What I would like to do (broke):
There are several issues going on here. In the examples given, the reason that the transition does not occur when the first left
class is added is because in order for the rendering engine to animate a property, that property needs to have a value already. In this case, there is no value for left
and as a result the transition does not occur.
The reason why it does not work when chained is because of specificity. jQuery will add both classes and when the call to render the page is made the last added definition for left is applied due to their shared specificity.
The reason why it appears to work from adding the class at a separate time versus chained is because the rendering engine was implicitly called from jQuery when the console.log accessed the css values of the element. This was pointed out by Stryner in his answer here: https://stackoverflow.com/a/33902053/1026459 . It was a very nice find.
Here is an example of that being applied so that the value of left doesn't need to be guessed at.
The meat of what happens is the offset of the element is found to get the pixel offset for left. Then that value is applied to the left style property. At that point while the element still hasn't changed position the rendering engine is called to update the left property. The property is then removed to ensure that the specificity does not take precedence over the class definition, and then the class definition is applied. This will facilitate the transition on first encounter.
jsFiddle Demo
$('button').click(function() {
$('div').css({'transition':'left 1000ms'}).each(function(){
$(this).css('left',$(this).offset().left);
window.getComputedStyle(this,null).getPropertyValue("left");
}).css('left','').addClass('left');
});
button {
margin-top: 30px;
}
div {
position: absolute;
width: 10px;
height: 10px;
background-color: red;
}
.left {
left: 100px;
}
.left_more {
left: 400px;
}