25

我想绕过 CSS 转换并立即更改属性。
我尝试设置transition-duration0s更改之前,然后设置transition-duration回其原始值:

$('div').css('width', '200px').delay(1000).queue(function() {
    $(this).css({
        transitionDuration: '0s',
        msTransitionDuration: '0s',
        mozTransitionDuration: '0s',
        webkitTransitionDuration: '0s',
        oTransitionDuration:'0s'
    }).css('width', '10px').css({
        transitionDuration: '2s',
        msTransitionDuration: '2s',
        mozTransitionDuration: '2s',
        webkitTransitionDuration: '2s',
        oTransitionDuration:'2s'
    })
})​

小提琴
这显然行不通。

我知道规范没有为此定义该行为:

由于本规范没有定义计算值何时更改,因此计算值的哪些更改被认为是同时发生的,因此作者应该意识到,在进行可能转换的更改后的一小段时间内更改任何转换属性可能会导致行为不同的实现之间有所不同,因为在某些实现中可能会同时考虑更改,而在其他实现中则不会。

是否有捷径可寻?

注意:我正在更改的属性transform因此.animate()不是一个选项。

4

10 回答 10

13

由于没有其他人发布有效答案,因此如下:

$('div').css('width', '200px').delay(1000).queue(function() {
    $(this).css({transition: '0s', width: '10px'}).delay(1).queue(function() {
        $(this).css({transition:'2s'});
    });
},1000)​;

小提琴

或者,如果是另一种方式:

$('div').css({
    transition: '0s'
  }).css('width', '200px').delay(1000).queue(function() {
      $(this).css({width: '10px', transition: '2s'});
});

小提琴

如今,jQuery 应该规范供应商前缀,因此您不必自己输入所有前缀。


这里的问题是 jQuery 一次附加所有样式,只保留最后一个样式,覆盖相同 CSS 属性的先前样式而不重新绘制 DOM,并且使用本机 javascript 进行测试似乎也在做同样的事情,所以它可能是浏览器试图通过添加一个样式来避免不必要的重排,只是为了让它在下一行代码中改变,这样做:

$('div').css({
    transition: '0s',
    width: 200
}).css({
    transition: '3s',
    width: 10
});

将不起作用,因为仅添加了最后一个样式。

这就是delay()发挥作用的地方,OP的问题已经在使用delay(),所以没有理由不使用它,但是删除delay()当然会导致上述问题,浏览器不会绘制第一种样式,而只会绘制最后一种样式等。

由于delay()实际上只是一个花哨的超时,它有效地推迟了样式的第二个设置的执行,导致两次浏览器重绘。

由于这很可能是浏览器问题,而不是我们可以更改的问题,因此延迟设置第二种样式是使其工作的唯一方法,即使设置为 1 毫秒或 1 毫秒,使用延迟仍然有效可以通过定期超时推迟执行,这是推迟脚本执行的常用方法:

$('div').css({
    transition: '0s',
    width: 200
});

setTimeout(function() {
    $('div').css({
        transition: '3s',
        width: 10
    });
});

小提琴

以上就可以正常工作了,因为超时导致样式的第一个设置被浏览器绘制,并将超时内的样式设置推迟到以后的时间,但是由于没有设置时间,它会尽快执行因为浏览器可以(但仍然推迟到当前脚本完成之后),这对于人眼来说似乎是立即的,这就解决了问题。

于 2012-12-02T15:33:27.970 回答
4

如果您可以控制 CSS

最简单的做法是将动画绑定到某个类,然后在您希望动画不再被绕过的时候,添加该类,否则永远不会设置动画。如果反了,一般是想要动画,偶尔也想绕过,那么就默认添加class,绕过的时候去掉。

示例 CSS

div{
    height: 100px;
    width: 200px;
    background: red;
}
div.doTransition {
    width: 10px;
    transition: width 2s linear;
    -ms-transition: width 2s linear;
    -moz-transition: width 2s linear;
    -webkit-transition: width 2s linear;
    -o-transition: width 2s linear;
}

请参阅 fiddle,它创建了一个单击事件以在需要时启动动画,但这可能是其他一些编程触发器,用于在不再希望绕过它时添加该类。这个小提琴做相反的事情,它假设动画存在,但在页面加载时立即通过删除类绕过它。

于 2013-11-26T17:09:29.510 回答
4

设置一个覆盖类来禁用应用到的元素上的 css 转换,!important非常适合:

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  -ms-transition: none !important;
  transition: none !important;
}

您现在toggleClass可以切换所需的行为(平滑过渡与即时更改):

$('div').
toggleClass('notransition', true). //or false!
css('width', '200px');

摆弄。IMO 这种方法的优点之一是您可以清楚地区分默认元素样式和禁用所有平滑动画标志。这也是一种非常“可包装”的可重用方法,即您可以轻松地将可选的布尔属性添加到现有方法中,以指示是否应该使用转换来执行它。

注意:有时您可能希望出于任何性能/用户体验原因完全禁用页面上的转换。在这种情况下,您可以将选择器更改为.notransition *并禁用所有后代元素的转换。

于 2013-11-27T23:55:46.040 回答
3

问题在于,由于浏览器没有理由放慢速度并单独执行每个操作,它会将它们结合起来并同时执行。查询offsetHeight 是强制它单独执行每个操作的一种方法,因为它必须重新计算高度。http://jsfiddle.net/markasoftware/6cTeY/15/完美运行

于 2013-11-28T00:09:09.863 回答
1

我会选择一个相当干净的 CSS 解决方案

HTML

<div id="foo"></div>
<button class="out">out</button>
<button class="in">in</button>

JS

$('button.out').click(function(){console.log($('#foo').addClass);$('#foo').addClass('out')})
$('button.in').click(function(){$('#foo').removeClass('out')})

CSS

div{
    height: 100px;
    width: 10px;
    background: red;

    transition: width 0s linear;
    -ms-transition: width 0s linear;
    -moz-transition: width 0s linear;
    -webkit-transition: width 0s linear;
    -o-transition: width 0s linear;
}
div.out {
    width: 200px;
    transition: width 2s linear;
    -ms-transition: width 2s linear;
    -moz-transition: width 2s linear;
    -webkit-transition: width 2s linear;
    -o-transition: width 2s linear;

}

http://jsfiddle.net/6cTeY/19/

于 2013-11-30T14:04:54.573 回答
1

这是我让它工作的唯一方法。jQuery 似乎有点固执。

http://fiddle.jshell.net/8qTpe/1/

PS你的方法有一些错误:

  1. 您在延迟前将大小调整为 200 像素,因此使用默认的 CSS 设置。

  2. 在将过渡更改回 2s 之前,您正在将大小调整为 10px。

现在 jQuery 似乎连续应用了所有 CSS 设置,这就是为什么整个事情似乎不起作用的原因。

于 2013-11-28T20:39:39.987 回答
1

我通常以这种香草 JS 的方式来做。

小提琴

HTML

假设你有一个元素

<div id="element"></div>

CSS

假设你的元素已经激活了 CSS 过渡并且 background: green

#element {
    background: green;
    width: 200px;
    height: 200px;
    -webkit-transition: 'all 0.5s ease-out';
    -moz-transition: 'all 0.5s ease-out';
    -ms-transition: 'all 0.5s ease-out';
    -o-transition: 'all 0.5s ease-out';
}

JS

该元素具有 CSS 过渡,但我们想立即将元素的背景更改为蓝色。

在那之后,我们希望元素的正常行为返回,以便我们可以将其背景设置为 RED。

我们需要暂时关闭过渡,然后立即恢复它们。

// grab the element
var element = document.getElementById('element');

// removeTransitions
element.style.webkitTransition   = 'none';
element.style.mozTransition      = 'none';
element.style.msTransition       = 'none';
element.style.oTransition        = 'none';

// apply desired 'instant' property
element.style.background         = 'blue'; // is applied instantly

// this 10ms timeout is necessary for the transitions to be active again
setTimeout(function() {
    element.style.webkitTransition   = 'all 5s ease-out';
    element.style.mozTransition      = 'all 5s ease-out';
    element.style.msTransition       = 'all 5s ease-out';
    element.style.oTransition        = 'all 5s ease-out';

    // apply desired 'animated' property
    element.style.background         = 'red';  // is applied smoothly
}, 10);
于 2015-07-19T05:09:40.390 回答
0

var ball = document.querySelector('.ball'),
    ballSpeed = 2,
    button = document.querySelector('button');

// Chane to random speed "instantly" (on button "click")
button.addEventListener('click', ()=>{ 
  ballSpeed = Math.random()*8 + 1;
  
  ball.style.transitionDuration = ballSpeed + 's';
  ball.classList.remove('move');
  ball.clientHeight; // <--- triggers repaint
  ball.classList.add('move');
  
  // set button text
  button.textContent = ballSpeed.toFixed(2) + 's';
})

function animate( speed ){
  ball.style.transitionDuration = '0s';
  ball.classList.remove('move');
  ball.clientHeight; // <--- triggers repaint. has to be after "move" class was removed
  
  ball.style.transitionDuration = ballSpeed + 's';
  ball.classList.add('move');
  ball.removeEventListener('transitionend', animate)
  ball.addEventListener('transitionend', animate); // keep rollin..
}

animate();
html, body{ height:100%; overflow:hidden; } 

.ball{
  position: absolute;
  width: 3em;
  height: 3em;
  left:0; right:0; top:0; bottom:0;
  margin: auto;
  
  transition-duration: 2s; /* <-- start speed  */
  transition-timing-function: linear;
}

.ball::after{
  content: '';
  display: block;
  width: 100%;
  height: 100%;
  transform: translateX(100%);
  border-radius:50%;
  background: gold;
}

.ball.move{
  transform: rotate(360deg);
}
<button>2s</button>
<div class="ball"></div>

于 2018-07-11T09:14:55.047 回答
0

我不知道这在 JQuery 中是如何工作的,但您可以在 CSS 中执行此操作(至少在撰写本文时):

div {
  animation: trans 2s;
}

@keyframes trans {
  0% {
    width: 200px;
  }
  99.9% {
    width: 200px;
  }
  100% {
    width: 10px;
  }
}
于 2021-01-08T03:37:51.120 回答
0

应该与 JQuery 一起使用的纯 JS 解决方案(尚未测试)。

接受答案的问题是为延迟设置一个值,但更好的解决方案是将延迟设置为 0。我们将在事件循环中使用一个小技巧来实现这一点:

const button = document.querySelector('button');

function reposition() {
  button.style.transition = 'none';
  button.style.transform = 'translate(-50%)';
  
  setTimeout(() => {
    button.style.transition = '1s';
    button.style.transform = 'translate(0)';
  }, 0);
}

button.addEventListener('click', reposition);
<button>
    Click Me
</button>

这称为零延迟。它仍然使用延迟,但您不必为此感到恶心,因为它会在堆栈清空时立即运行。

如果您想了解这是为什么,我建议您观看此视频

但这里有一个(凌乱的)简短解释:

基本上发生的事情是 setTimeout() 将保持该值直到一定的时间,我们这里的时间是 0,但它不会执行直到堆栈被清除,(为什么?这是,看视频)因为浏览器仍然必须重新绘制更改,重新渲染仍将在堆栈中,当它完成时,传递给 setTimeout() 的函数将被执行,从而导致另一个重新渲染。

我知道这是否 100% 有效吗?理论上应该是这样,但我不是专家。

于 2021-06-12T02:57:57.743 回答