即使在状态更改后激活,也会应用CSS过渡?

我有一个jQuery插件可以在屏幕上移动一个元素,但是有一个“动画”切换来显示幻灯片过渡与否。 在尝试使用CSS Transitions而不是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过渡是前沿,或者我做错了什么,而且有一种更简单的方法可以暂时“转变”过渡?

编辑:注意到这个问题是类似的,虽然这个问题的答案只是将两个调用分开,但问题仍然是“为什么我们(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中,这意味着将transition样式应用于与left样式不同的单独的代码块中。 这是通过建议的所有答案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并强制元素重新渲染。