0

I am trying to execute a transition for an image gallery. When the gallery transitions to the next slide, I will put it just to the left of the current slide, and slide it over the current slide by transitioning on its left style.

My current markup:

 <section id="nd-gallery">
    <div class="nd-slide nd-slide-current">
        slide 1
    </div>
    <div class="nd-slide nd-slide-next">
        slide 2
    </div>
</section>

Relevant CSS:

#nd-gallery{
    position:relative;
    height:100px;
    width:100px;
}

#nd-gallery > .nd-slide{
    position:absolute;
    height:100px;
    height:100px;
    outline:1px solid red;
    left:-40px;
}

#nd-gallery > .nd-slide.nd-slide-current{
    z-index:5;
    left:0;
}

So, by default, I offset slides by moving them left by 40px (obviously I will hide them better outside of this demo with a larger offset)

Now, with some script, I want to:

  • Apply a new left value to the next slide to offset it (for the purpose of this demo, 50px which offset the next slide over the current slide by half)

  • Assign the appropriate transition properties

  • Assign a new left value so that the next slide will slide over the current slide

SCRIPT:

var next = document.querySelector('.nd-slide-next');
next.style.left = '-50px';
next.style.transitionProperty = 'left';
next.style.transitionDuration = '5s';
next.style.left = '0';

However, when I run this, the next slide appears on top of the current slide without a transition:

http://jsfiddle.net/ACdc7/4/

Note: Apparently Firefox performs the transition properly. In Chrome v.32 on Windows 7, the transition is not performed. Can anyone point out if I've done something incorrect, or perhaps I'm dealing with a bug in Chrome?

Mister Epic
  • 16,295
  • 13
  • 76
  • 147
  • possible duplicate of [Cannot dynamically set initial element translation before transition in same call stack](http://stackoverflow.com/questions/9303080/cannot-dynamically-set-initial-element-translation-before-transition-in-same-cal) - use a small delay – Bergi Mar 09 '14 at 21:58

1 Answers1

0

Like it happens with many UI frameworks that execute all UI operations in only one thread (Windows Forms, WPF ...), most layout operations are blocked while user code is executing. Why? Well, while Javascript code is executing, the browser is tipically unresponsive, because its UI thread is occupied processing your code. So, if you change the value of the same property multiple times before relinquishing control to the browser, only the last value remains. It would be a waste of processing power to go through a layout process when you change, let's say, the left value of an element, when maybe you can change it later in the same event handler. So, the browser just creates a queue of pending layout operations an performs them when it has nothing else to do.

Applied to your case, the browser adds to the queue the operation {next.style, 'left', -50px}. When you update left again, the browser doesn't add a new operation. As there is one pending that does the same, it just updates it. So, to the browser, you aren't changing the left property from -50px to 0px, you are just setting it to 0px.

You need to relinquish control to the browser after setting left to -50px. Then, you set it back to 0px. You can do it this way:

var next = document.querySelector('.nd-slide-next');
next.style.left = '-50px';
setTimeout(function() {
    next.style.transitionProperty = 'left';
    next.style.transitionDuration = '5s';
    next.style.left = '0';
}, 10);

It also could work if you force a synchronous layout (which is often undesirable). You can achieve this by accessing some properties of a DOM node, like the offset- or client- properties. These properties always return the most updated values, so, if there are layout operations pending, the browser stops the execution of javascript code, performs the layout, and continues executing:

var next = document.querySelector('.nd-slide-next');
next.style.left = '-50px';
var offset = next.offsetLeft; //force layout. The broswer know acknowledges that next.style.left is -50px.
next.style.transitionProperty = 'left';
next.style.transitionDuration = '5s';
next.style.left = '0';
Oscar Paz
  • 18,084
  • 3
  • 27
  • 42
  • Appreciate the comprehensive answer. Any insight as to why it works as expected with Firefox? – Mister Epic Mar 10 '14 at 12:07
  • Well, I suppose Firefox is doing a synchronous layout... Or maybe just they optimised this case, when you want to animate two values, I don't know. If Firefox does this always (applying values synchronously) then it's wasting resources uselessly most of the time (and would be a reason for the poor performance of Firefox compared to Chrome - and event to latest versions of IE -). – Oscar Paz Mar 10 '14 at 14:10