绕过转换并立即更改属性

时间:2012-12-02 14:52:36

标签: javascript jquery css

我想绕过CSS过渡并立即更改属性 我尝试在更改前将transition-duration设置为0s,然后将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'
    })
})​

Fiddle
这显然不起作用。

我理解spec没有为此定义该行为:

  

由于此规范未定义计算值何时更改,   因此,计算值的哪些变化被认为是同时的,   作者应该意识到改变任何过渡属性   在进行可能转换的更改之后的少量时间   导致实现之间的行为不同,因为   在某些实现中可能会同时考虑更改但是   不是其他人。

有一种简单的方法吗?

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

10 个答案:

答案 0 :(得分:13)

由于没有其他人发布有效答案,所以请点击:

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

FIDDLE

或者如果是另一种方式:

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

FIDDLE

jQuery现在应该规范供应商前缀,因此您不必自己键入它们。


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

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

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

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

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

由于这很可能是一个浏览器问题,而不是我们可以改变的东西,推迟第二种风格的设置是使这项工作成功的唯一方法,使用延迟仍然可以工作,即使它设置为仅1毫秒或者可以通过常规超时推迟执行,这是推迟执行脚本的常用方法:

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

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

FIDDLE

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

答案 1 :(得分:4)

如果您可以控制CSS

最简单的方法是将动画绑定到某个类,然后在不想再绕过动画的位置,添加类,否则不会设置任何动画。如果相反,您通常需要动画,但偶尔想要绕过它,然后默认添加该类并在绕过时将其删除。

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

See fiddle创建一个click事件,以便在需要时启动动画,但这可能是一个其他程序触发器,用于在不再想要绕过它时添加类。 This fiddle does the opposite ,它假定动画存在,但在页面加载时会立即通过删除类来绕过它。

答案 2 :(得分:3)

设置一个覆盖类来禁用应用于的元素上的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');

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

NB:有时您可能希望完全禁用页面上的转换,无论出于性能/用户体验的原因。在这种情况下,您可以change the selector to .notransition *并禁用所有后代元素的转换。

答案 3 :(得分:2)

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

答案 4 :(得分:1)

这是我能让它发挥作用的唯一方法。 jQuery似乎有点顽固。

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

P.S。您的方法存在一些错误:

  1. 您在延迟之前重新调整为200px,因此使用默认的CSS设置。

  2. 在将转换更改回2s之前,您正在重新调整为10px。

  3. 现在jQuery似乎连续应用了所有CSS设置,这就是为什么整件事似乎不起作用。

答案 5 :(得分: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/

答案 6 :(得分:0)

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

FIDDLE

HTML

假设您有一个元素

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

CSS

假设您的元素已经激活了CSS Transitions且背景为: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过渡但我们想立即将元素的背景更改为BLUE。

在此之后,我们希望元素的正常行为返回,以便我们可以将其背景设置为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);

答案 7 :(得分: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>

答案 8 :(得分:0)

我不知道这在 JQuery 中是如何工作的,但您可以在 CSS 中做到这一点(至少在撰写本文时):

div {
  animation: trans 2s;
}

@keyframes trans {
  0% {
    width: 200px;
  }
  99.9% {
    width: 200px;
  }
  100% {
    width: 10px;
  }
}

答案 9 :(得分: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>

这称为零延迟。它仍然使用延迟,但您不必为此感到讨厌,因为当堆栈清除时,它会立即运行。

如果您想了解这是为什么,我建议您观看this video

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

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

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