即使在状态更改后激活,也应用CSS转换



我有一个jQuery插件,它可以在屏幕上移动元素,但有一个"animate"切换,可以显示幻灯片过渡或不显示。在尝试使用CSS转换而不是Javascript转换进行更改时,我遇到了这个问题,我不确定这是一个bug/怪癖,还是我做错了:

var $item = $('#myItem');
if (!animate) {
  $item.removeClass('csstransitions'); // Class that has "transition:left 0.25s ease-out" 
  $('#myItem').css('left', '300px'); // Move the element
  $('#myItem').addClass('csstransitions'); // Re-apply transitions class
}

当以这种方式进行时,在转换类没有应用于元素,而是在之后立即应用的情况下,css发生了更改,一些浏览器(在我的测试中,Chrome和Safari)仍然应用css转换,而根据我的逻辑,它应该只是捕捉到新位置。

在这个jsFiddle中看到这一点;在Chrome或Safari中,单击"无延迟"按钮,可以看到它仍然会对框的位置设置动画,而"延迟"按钮(使用一毫秒后设置的超时)不会对CSS更改设置动画。

正如jsFiddle中所指出的,我必须使用setTimeout调用(setTimeout(function() { $el.addClass('csstransition'); }, 1);)才能在Chrome和Safari中获得正确的行为。这仅仅是因为CSS转换正在流血,还是我做错了什么,有一种更简单的方法可以暂时"切换"转换?

EDIT:注意到这个问题很相似,虽然这个问题的答案是只分离两个调用,但问题仍然是"为什么我们(web开发人员)需要分离这两个调用?"这是我们应该用来切换CSS转换的方法吗?

我会投票支持怪癖或实现差异。

在转换之前,应用哪种顺序样式并不重要,因为在实用性中,顺序并不重要,只重要特定性。但在转换中,样式中添加了时间延迟元素,这是问题的关键。

由于不知道任何浏览器是如何应用样式的,我可以猜测Safari和Chrome会进行一些优化,以便在每次样式更新后不必重新流动页面。相反,他们可能会等待特定的时间间隔或事件来进行更新,例如在代码块的末尾。

此处详细介绍了一些差异:
http://taligarsiel.com/Projects/howbrowserswork1.htm

不过,我不知道这个具体问题是否包括在内。

作为演示,处理此问题的另一种方法是使用2个点击处理程序:

$('button#nodelay').on('click', function() {
    var $el = $('#square');
    $el.removeClass('csstransition');
    $el.css('left', '100px');
}).on('click', function() {
    $el.addClass('csstransition');
});

这基本上将两个更新划分为单独的代码块,非常类似于setTimeout方法。

此外,由于过渡仍然是草案标准,我不会依赖任何这种行为来保持一致,而且也有一些怪癖。(我遇到了一个问题,即不能在所有浏览器中同时转换lefttop)。

编辑

为了进一步解释,如果浏览器在添加到DOM后立即渲染所有CSS,则会得到以下流:

  1. CSS left: 300px添加到DOM元素
  2. 渲染样式:浏览器检查图元上是否有过渡。如果是,请设置动画;如果不是,请立即应用。在这种情况下,还没有过渡,因此不会发生动画
  3. CSS transition: left 2s ease-out添加到DOM元素
  4. 渲染样式:无渲染更改,转换适用于未来的left更改

然而,如果浏览器通过在代码块(或类似的东西)的末尾分组来优化CSS的呈现,则会得到以下结果:

  1. CSS left: 300px添加到DOM元素
  2. CSS transition: left 2s ease-out添加到DOM元素
  3. 达到渲染点(代码块结束等),渲染所有样式:
  4. 应用left时,浏览器会检查图元上是否存在过渡。如果是,请设置动画;如果不是,请立即应用。在这种情况下,存在过渡,因此会发生动画

因此,动画的长度和等待的时间是无关紧要的。重要的是left: 300px在应用转换之前被渲染。目前,在WebKit中,这意味着在一个单独的、比left样式晚的代码块中应用transition样式。这是通过建议的所有答案setTimeout(具有0延迟的事件)、单独的单击处理程序(如果第二次应用)或函数回调来实现的。

这是另一种工作方式:

$('button#nodelay').on('click', function() {
    var $el = $('#square');
    $el.removeClass('csstransition');
    $el.css('left', '100px').css('left'); // <-- This (or .show() even)
    $el.addClass('csstransition');
});

这是有效的,因为您正在强制浏览器停止并评估CSS,以便获得left的值(尽管您可以在第二个.css()调用中放入任何有效的CSS属性)。在这种情况下,它应用所有CSS并强制元素重新渲染。

最新更新