Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix flicker when using Webkit transforms & transitions

I have a very simple demo working that uses Webkit transforms and transitions for smooth horizontal scrolling between 'panels' (divs).

The reason I want to go this route as opposed to a Javascript driven system is that it's for the iPad and Javascript performance is quite poor, but the css transforms and transitions are smooth as silk. Sadly though, I'm getting a lot of flicker on the iPad with my Demo.

You can see the demo here

You'll need safari or and iPad to see it in action. I've never seen this happening in any of the demos for transforms and transitions so I'm hopeful that this is fixable.

Anyway here's the code that powers the thing....

The HTML looks like this.

<html>
    <head>
        <title>Swipe Demo</title>
        <link href="test.css" rel="stylesheet" />
        <link href="styles.css" rel="stylesheet" />
        <script type="text/javascript" src="jquery.js"></script>
        <script type="text/javascript" src="functions.js"></script>
        <script type="text/javascript" src="swiping.js"></script>
    </head>
    <body>


    <div id="wrapper">
        <div class='panel one'>
            <h1>This is panel 1</h1>
        </div>

        <div class='panel two'>
            <h1>This is panel 2</h1>
        </div>

        <div class='panel three'>
            <h1>This is panel 3</h1>
        </div>

        <div class='panel four'>
            <h1>This is panel 4</h1>
        </div>
    </div>

    </body>
</html>

The CSS looks like this

    body,
    html
        {
            padding: 0;
            margin: 0;
            background: #000;
        }

    #wrapper
        {
            width: 10000px;
            -webkit-transform: translateX(0px);
        }

    .panel
        {
            width: 1024px;
            height: 300px;
            background: #fff;
            display: block;
            float: left;
            position: relative;
        }

and the javascript looks like this

// Mouse / iPad Touch
var touchSupport = (typeof Touch == "object"),
touchstart   = touchSupport ? 'touchstart' : 'mousedown',
touchmove    = touchSupport ? 'touchmove'  : 'mousemove',
touchend     = touchSupport ? 'touchend'   : 'mouseup';

$(document).ready(function(){

    // set top and left to zero
    $("#wrapper").css("top", 0);
    $("#wrapper").css("left", 0);

    // get total number of panels
    var panelTotal;
    $(".panel").each(function(){ panelTotal += 1 });

    // Touch Start
    // ------------------------------------------------------------------------------------------

    var touchStartX;
    var touchStartY;
    var currentX;
    var currentY;
    var shouldMove = false;
    document.addEventListener(touchstart, swipeStart, false);
    function swipeStart(event){

        touch = realEventType(event);

        touchStartX = touch.pageX;
        touchStartY = touch.pageY; 
        var pos = $("#wrapper").position();
        currentX = parseInt(pos.left);
        currentY = parseInt(pos.top);

        shouldMove = true;

    }

    // Touch Move
    // ------------------------------------------------------------------------------------------

    var touchMoveX;
    var touchMoveY;
    var distanceX;
    var distanceY;
    document.addEventListener(touchmove, swipeMove, false);
    function swipeMove(event){
        if(shouldMove){
            touch = realEventType(event);
            event.preventDefault();

            touchMoveX = touch.pageX;
            touchMoveY = touch.pageY;

            distanceX = touchMoveX - touchStartX;
            distanceY = touchMoveY - touchStartY;       
            movePanels(distanceX);

        }
    }

    function movePanels(distance){
        newX = currentX + (distance/4);    
        $("#wrapper").css("left", newX);
    }


    // Touch End
    // ------------------------------------------------------------------------------------------

    var cutOff = 100;
    var panelIndex = 0;
    document.addEventListener(touchend, swipeEnd, false);
    function swipeEnd(event){

        touch = (touchSupport) ? event.changedTouches[0] : event;

        var touchEndX = touch.pageX;
        var touchEndY = touch.pageY;

        updatePanelIndex(distanceX);

        gotToPanel();

        shouldMove = false;

    }

    // --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --

    function updatePanelIndex(distance){

        if(distanceX > cutOff)
            panelIndex -= 1;

        if(distanceX < (cutOff * -1)){
            panelIndex += 1;
        }

        if(panelIndex < 0){
            panelIndex = 0;
        }

        if(panelIndex >= panelTotal)
            panelIndex = panelTotal -1;

            console.log(panelIndex);

    }

    // --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --

    function gotToPanel(){

        var panelPos = getTotalWidthOfElement($(".panel")) * panelIndex * -1;

        $("#wrapper").css("-webkit-transition-property", "translateX");
        $("#wrapper").css("-webkit-transition-duration", "1s");
        $("#wrapper").css("-webkit-transform", "translateX("+panelPos+"px)");

    }

});

function realEventType(event){
    e = (touchSupport) ? event.targetTouches[0] : event;
    return e;
}
like image 289
gargantuan Avatar asked Jun 04 '10 14:06

gargantuan


People also ask

How do I stop Javascript from flickering?

By default, the javascript / jQuery code you write is executed at Document ready. This means that the whole page is loaded before your changes are made. This can sometimes cause “flickering”. You can avoid this by changing the way Symplify executes javascript / jQuery.

Do I need to use webkit transform?

Official Property Most major browsers now support the official CSS3 transform property. Unless you need to support a really old browser, there's no need to use the -webkit- extension. In other words, use the transform property unless you have a specific reason not to.

What is the use of Webkit transition?

The -webkit-transition Boolean non-standardCSS media feature is a WebKit extension whose value is true if the browsing context supports CSS transitions. Apple has a description in Safari CSS Reference; this is now called transition there.


3 Answers

@gargantaun is right, Webkit flickers if the element you want to animate is bigger than the screen. But there is an easy fix. Just add:

-webkit-backface-visibility: hidden;

to the element and you are good to go!

like image 146
Mario Uher Avatar answered Sep 17 '22 06:09

Mario Uher


Try using translate3d instead of translateX. It appears only translate3d is hardware accelerated on iPad 3.2.

like image 38
Nate T Avatar answered Sep 18 '22 06:09

Nate T


As mentioned above, it is better to use Translate3d due to the hardware acceleration which makes for smoother transitions.

However, the flicker is caused when the div being animated is larger than the screen. So, if you have an area that adds up to 3.5 screen widths that you wish to transition horizontally, it should be broken up into 4 divs like this

[ 1 ][ 2 ][ 3 ][.5]

None of the divs should exceed the screens height or width.

Sorry for the lateness in posting this answer. I'd completely forgotten about it until I just got a "popular question" notice.

like image 26
gargantuan Avatar answered Sep 20 '22 06:09

gargantuan