3

The Problem

I want to position an element using javascript and then add a transition-appliance class to it, so that after positioning, any further changes will be animated by that transition.

Generally that is not a big deal.

But in order to achieve it, i find myself writing code like this:

$('#someWindow').center('#someParent');
$('#someWindow').addClass('transition visible');

So what's the catch?

Both calls are (as i understand it) rendered by the browser within one processing step. And that results in either no transition at all, or in all changes to the element being animated by the transition - including those that were applied before the transition-class was applied to the element.

Solution?

My first thought was to wrap the second call in a setTimeout() call.

$('#someWindow').center('#someParent');
window.setTimeout(function(){
    $('#someWindow').addClass('transition visible');
},1);

It works! Using setTimeout() the rendering is now somehow stacked and the browser does it all correctly.

So what's the question?

I assume this is a known problem. My solution doesn't satisfy me. It 'feels' inconsistent, as if i could not fully rely on it.

So, is this the only way to do it? Or are there any more clean ways to work around that problem?

UPDATE

See this fiddle for a demonstration

(Remember to press the reset button in between testing).

SquareCat
  • 5,699
  • 9
  • 41
  • 75
  • Where did you get `.center` from? I don't know that as being a part of jquery. – Jacob Schatz Oct 10 '13 at 19:02
  • Correct. Its a custom extension. It will simply call .css() on the element with positioning modifications. – SquareCat Oct 10 '13 at 19:05
  • So why wouldn't you roll the centering animation into your transition? – Mister Epic Oct 10 '13 at 19:08
  • So you are saying that by adding those classes `transition visible` it is performing an animation? Normally I would do something like this (assuming I had that `.center` available to me. ) `$("#something").center("#somethingelse");` `$("#something").fadeIn();` Or some other jquery transition. Normally just adding a class isn't going to made an animation or transition happen. Unless I am not understanding you. Normally a function call would put something into action. – Jacob Schatz Oct 10 '13 at 19:10
  • In this particular case i want to first center the element while its still hidden to the user, then i want to run some nice transition to pop it into view. In any case, the above serves merely as an example. – SquareCat Oct 10 '13 at 19:10
  • I created a fiddle (tested by now only in Safari). Please check it out. – SquareCat Oct 10 '13 at 19:13
  • Does the `.center` have any callbacks? I don't know the plugin. It shouldn't need any callbacks but if it did have them that would be a sure fire way to know that it is indeed finished centering the items. – Jacob Schatz Oct 10 '13 at 19:19
  • use a small transition-delay value in CSS to stagger the effects and avoid jitter. – dandavis Oct 10 '13 at 19:19
  • Jacob: .center() is not the issue. Its an example. See the fiddle - it demonstrates the issue without the use of .center() – SquareCat Oct 10 '13 at 19:20
  • possible duplicate of [very simple JavaScript / jQuery example: unexpected evaluation order of instructions](http://stackoverflow.com/questions/15186245/very-simple-javascript-jquery-example-unexpected-evaluation-order-of-instruct) – Bergi Oct 10 '13 at 19:32
  • Using the example from the question @Bergi linked, calling `offsetWidth` forces the browser to paint and fixes the problem: http://jsfiddle.net/nCe6n/4/ – Ross Allen Oct 10 '13 at 19:36
  • Thank You. As Dennis (in the linked question) points out, calling `offsetWidth` results basically in the same as using the `setTimeout()`-workaround. As i stated, i already have a solution/workaround, but i am looking for a 'better' one, which is not provided in the linked answer. – SquareCat Oct 10 '13 at 19:39
  • I took a little of what others said and combined it into a plugin. It's still not completely ideal but it is smoother. Check my answer. – Jacob Schatz Oct 10 '13 at 19:58

1 Answers1

0

Since your issue is with redrawing/repainting.
How about this

$('#el').css({
    top: '150px'
})
.redraw()
.addClass('transition visible');

$.fn.redraw = function(){
  $(this).each(function(){
    var redraw = this.offsetHeight;
  });
  return this;
};

http://jsfiddle.net/nCe6n/6/

Jacob Schatz
  • 103
  • 6
  • Thank You, that is a very kind contribution. Nonetheless it is not what i am looking for. My question is not how to implement this solution but if there is another one that is not actually a work-around. Obviously there is a high chance that no such solution exists. But i want to find out which is why i asked. – SquareCat Oct 10 '13 at 21:23