Richard Knop
Richard Knop

Reputation: 83755

Basic JS Animation Does't Work Correctly In Safari

So here is my animation function:

    function animation(el, isHorizontal, from, to, callback) {
        var start = true === isHorizontal ? from.x : from.y,
            stop = true === isHorizontal ? to.x : to.y,
            intervalId, diff;

        intervalId = setInterval(function () {
            diff = Math.abs(stop - start);
            if (stop < start) {
                if (diff < 4) {
                    start -= diff;
                } else {
                    start -= 4;
                }
            } else {
                if (diff < 4) {
                    start += diff;
                } else {
                    start += 4;
                }
            }
            if (true === isHorizontal) {
                el.style.left = start + 'px';
            } else {
                el.style.top = start + 'px';
            }
            if (start === stop) {
                clearInterval(intervalId);
                callback();
            }
        }, 1);
    }

It works perfectly in Chrome, although in Safari, the animated elements seem to stop few pixels before they are supposed to.

Let's say I am going to move from left: 8 to left: 116. In Safari, the element ends at around left: 108, when I open the Inspector to see the console and check that the left offset is correct on the element, the element repositions itself correctly.

All I need to do is open the developer console and the element jumps to correct position.

So strange.

Here's some of my CSS that might be relevant:

.box {
    position: relative;
     }
    .item {
        position: absolute;
        background-position: left top;
        background-repeat: no-repeat;
        background-size: 100% auto;
        -webkit-transform: transform;
    }

Upvotes: 1

Views: 860

Answers (2)

Richard Knop
Richard Knop

Reputation: 83755

So it seems in Safari I have to trigger hardware acceleration otherwise Safari can't keep up and repaint images fast enough:

    -webkit-transform-style: preserve-3d;
    .item {
        position: absolute;
        background-position: left top;
        background-repeat: no-repeat;
        background-size: 100% auto;
        -webkit-transform-style: preserve-3d;
    }

Upvotes: 0

Strille
Strille

Reputation: 5781

It looks like there's nothing wrong with your code, but that Safari doesn't perform a repaint when it should (since the problem goes away when you open the developer console).

Do you still get the problem if you increase the 1ms interval to say 50ms?

One hack that usually works is to force the browser to repaint the whole page by toggling a dummy class on the body at the end of the animation:

if (start === stop) {
    jQuery("body").toggleClass("forceRepaint");

    clearInterval(intervalId);
    callback();
}

You could do this without jQuery of course, but it's going to be less concise.

Also, you would most likely avoid this problem if you used requestAnimationFrame() instead of setInterval() for animations like this (as well as better performance). There's several polyfills that fall back to setInterval/setTimeout in old browsers.

Upvotes: 1

Related Questions