Как исправить мерцание при использовании преобразований и переходов Webkit

У меня есть очень простая демонстрационная работа, которая использует преобразования и переходы Webkit для плавной горизонтальной прокрутки между "панелями" (divs).

Причина, по которой я хочу пойти по этому пути в отличие от системы, управляемой Javascript, заключается в том, что она для iPad, а производительность Javascript довольно низкая, но преобразования CSS и переходы плавные, как шелк. К сожалению, с моим демо я получаю много мерцания на iPad.

Вы можете увидеть демо здесь

Вам понадобится сафари или iPad, чтобы увидеть его в действии. Я никогда не видел, чтобы это происходило ни в одной из демонстраций трансформаций и переходов, поэтому я надеюсь, что это поправимо.

В любом случае вот код, который приводит в действие вещь....

HTML выглядит следующим образом.

<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>

CSS выглядит так

    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;
        }

и JavaScript выглядит так

// 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;
}

6 ответов

Решение

Попробуйте использовать translate3d вместо translateX. Похоже, только translate3d является аппаратно ускоренным на iPad 3.2.

@gargantaun прав, Webkit мерцает, если элемент, который вы хотите анимировать, больше экрана. Но это легко исправить. Просто добавь:

-webkit-backface-visibility: hidden;

к стихии, и вы готовы идти!

Как упоминалось выше, лучше использовать Translate3d из-за аппаратного ускорения, которое обеспечивает более плавные переходы.

Однако мерцание возникает, когда анимация div больше, чем экран. Итак, если у вас есть область шириной до 3,5 экранов, которую вы хотите переместить горизонтально, она должна быть разбита на 4 деления, как это

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

Ни один из элементов div не должен превышать высоту или ширину экрана.

Извините за опоздание в публикации этого ответа. Я полностью забыл об этом, пока не получил уведомление "популярный вопрос".

Я получил мерцание, чтобы уйти, сначала приведя вид в "трехмерное" состояние. Во-первых, у меня есть все мои виды, в которых присутствует preserve-3D. Тогда у меня есть этот код,

MyNamespace.flickerFixer = function(children) {
 children.css({
  "-webkitTransform": "translate3D(0px, 0px, 0px)",
  "-webkit-transition": "1s ease-in-out"
 });
}

И затем я инициализирую его перед анимацией webkit:

MyNamespace.flickerFixer($this.parent(".ui-content"));

На основе @tobiasahlin говорить на WebExpo.

Решение проблемы мерцания в Safari - лучшее решение

transform: translateZ(0);

В настоящее время, с iOS8, еще одним хорошим решением является применение overflow: hiddenинкриминированным элементам (или их контейнеру).

Я обнаружил, что translate3D - лучшее решение, чем анимация классов left: или right:. Он хорошо работает на сафари и более плавный. У меня были серьезные проблемы с мерцанием даже на iOS13.

Это слайд:

.cartout-enter-active {
  -webkit-animation: cartout 0.2s;
  animation: cartout 0.2s;
}
.cartout-leave-active {
  -webkit-animation: cartout 0.2s reverse;
  animation: cartout 0.15s reverse;
}
@-webkit-keyframes cartout {
  from {
    transform: translate3d(100%, 0, 0);
  }

  to {
    transform: translate3d(0%, 0, 0);
  }
}
Другие вопросы по тегам