CSS3过渡中止导致动画丑陋

8
我正在使用CSS3步进转换来将精灵从一个状态动画到另一个状态。
当我开始一个动画时,它会逐帧显示,并具有漂亮的过渡效果(在示例中单击“show / hide”链接)。但是,当第二个转换在第一个转换仍在运行时被触发时,帧位置会丢失,看起来像是滚动到另一侧,而不是维护逐帧动画(在示例中单击“trigger bug”)。
.tree {
    width: 26px; /* one frame */
    height: 31px; /* frame height */
    background-image: url("http://rolandschuetz.at/docs/tree-animated.png");
    background-repeat: no-repeat;
    background-position: -234px 0; /* last frame */
    transition: background-position .8s steps(10); /* this triggers the CSS3 step transition */
}
.tree-hidden {
    background-position: 26px 0; /* clear, before first frame */
}

是否有一种方法可以强制动画正确工作,即使它中止了旧动画?

PS:请不要尝试通过触发错误按钮进行“修复”,它仅用于演示目的。真正的问题是由快速用户交互引起的,应该立即反馈。


你按了“触发错误”链接吗?如果是的话,使用的是哪个浏览器? - Roland Schütz
是的,我看到了,但既然这是你的动画,你必须解释哪里不好看,这样我才能找到丑陋的部分。 - sanoj lawrence
当我点击时,树的大小会减小到很小,并从左向右滚动。 - sanoj lawrence
我知道发生了什么。问题在于,“显示/隐藏”按钮应该能够在用户连续点击两次且间隔小于0.5秒的情况下正常工作。因此,您的建议并不能解决这个问题。 - Roland Schütz
你必须使用JavaScript来检测交易事件的开始和结束,否则无法解决它。 - Mehmet Otkun
显示剩余4条评论
4个回答

2

更新的代码

看看这是否能帮助您。

HTML

<div class="outer"> <!--Added this div-->
  <div class="tree"></div>        
</div>

CSS(层叠样式表):
.outer {
    width: 26px;
    border: 1px solid grey;
}
.tree {
    width: 26px; /* one frame */
    height: 31px;

    background-image: url("http://rolandschuetz.at/docs/tree-animated.png");
    background-repeat: no-repeat;
    background-position: -234px 0; /* last frame */
    -webkit-transform: scale(1);
    margin: 0 auto;    
    /*Changed transition*/
    -webkit-transition: all .8s;
       -moz-transition: all .8s;
        -ms-transition: all .8s;
            transition: all .8s;
}
.tree-hidden {
    /* background-position: 26px 0; */ /* empty, before first frame */
    width: 0;
    -webkit-transform: scale(0);
}

这是一个不错的想法,但它看起来没有逐帧动画那么好。 - Roland Schütz

2
如ThePav所说,CSS无法知道当前处于哪个状态。因此,即使从之前的转换中间开始,并且背景位置需要较少的步骤,它仍将始终应用一个10步(steps(10))函数。
解决这个问题最简单的方法(虽然也不容易)是设置一个与background-position设置相同的平行z-index转换。如果您可以给它们任何z-index,那么它们的z-index将从0到10。
.tree {
    background-position: -234px 0; 
    z-index: 0;
    transition: all .8s steps(10); // will apply both to bkg-position and z-index
}
.tree-hidden {
    background-position: 26px 0; 
    z-index: 10;
}

然后,z-index属性作为进行中的转换的指示器,您可以相应地设置steps函数,在脚本中更改类。

也就是说,获取z-index的值,并将其设置为transitionTimingFunction:'steps('+ zindexval +')'

(您也可以使用background-position属性完成此操作,但要难得多。)

代码如下:

function change () {
    var tree = $('.tree').eq(0);
    if (tree.hasClass('tree-hidden')) {
        var where = tree.css("zIndex");
        if (where != 10) {
            tree.css({transitionTimingFunction: 'steps(' + where + ')'})
        } else {
            tree.css({transitionTimingFunction: ''})
        }
        tree.removeClass('tree-hidden');
    } else {
        tree.css({transitionTimingFunction: ''})
        tree.addClass('tree-hidden');
    }

}

demo


并行z-index转换是什么意思?谢谢 :) - Roland Schütz
增加了更多细节 :-) - vals
感谢所有的工作。可惜这在我的浏览器里不起作用。无论如何,我认为我将会找到另一个解决方案,因为代码变得太臃肿了。我将会简单地在 JS 中保留一个计时器。 - Roland Schütz
好的,不用担心。祝你好运 :-) - vals

2

问题是:

有10个框架,因此您为动画使用10步。 因此,CSS对于tree-active和tree-not-active分别将树向前移动10次。

如果在第8个框架处停用树,则会按预期反转动画方向,但它将步进10次而不是8次。这使它看起来像是滑动,实际上只是在8个框架的10个间隔位置上停止。

这有道理吗?

对于这种类型的动画,您最好使用JS解决方案,以便它知道当前帧位置并正确计算所需的步骤。

希望这可以帮助!


是的,这就是问题所在。如果有一种仅使用CSS的解决方案,那将非常酷。 - Roland Schütz
1
很遗憾,我不这么认为。我可以用最少的JS来做一个快速的fiddle,但我认为在这里使用JS是正确的选择。CSS不能存储数据,因此它无法知道当前位置(你需要重新计算所需的步骤)。 - PavKR
由于我大约运行了70个具有不同过渡持续时间的转换,非硬件加速版本可能会导致性能问题。 - Roland Schütz
一个不太理想的错误解决方案是,如果中断的动画能从上一个过渡的结束点开始,那将会更好。这样树就会突然改变大小,但不会产生奇怪的滚动效果。 - Roland Schütz
@RolandSchütz 所以,像这样吗?http://jsfiddle.net/pavkr/Lc31fjt6/19/ 我只是给它提供了替代的转换时间。 - PavKR
显示剩余2条评论

0
使用transitionend来等待删除'tree-hidden'类。否则,你无法通过其他方式解决。
$('.show-hide').click(function() {
    !$('.tree').hasClass('tree-hidden') &&
    $('.tree').addClass('tree-hidden').one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(e) {
        $('.tree').removeClass('tree-hidden')
    });
});

更新

 $('.show-hide').click(function(evt) {
    //JUST CHECK ALREADY HAS HIDDEN CLASS
    if($('.tree').hasClass('tree-hidden'))
     //you can event prevent defaul if there is no another work
     evt.preventDefault();
     return false;
    $('.tree').addClass('tree-hidden').one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(e) {
        $('.tree').removeClass('tree-hidden')
    });
});     

通过这种方式,无论点击多少次,事务都不会中断,直到动画完成。

CSS 事务回退

如果需要回退,可以使用下面的代码

function supportsTransitions() {
   var b = document.body || document.documentElement,
    s = b.style,
    p = 'transition';

    if (typeof s[p] == 'string') { return true; }

    // Tests for vendor specific prop
    var v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms'];
    p = p.charAt(0).toUpperCase() + p.substr(1);

    for (var i=0; i<v.length; i++) {
        if (typeof s[v[i] + p] == 'string') { return true; }
    }

    return false;
}

这样做不会立即给用户反馈,可能会让他感到困惑。因此,他会点击三次,然后出现很多无用的动画。 - Roland Schütz
只需检查交易是否仍在进行中,我已为您更新。 - Mehmet Otkun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接