Bypassing transition and changing a property instantly

匿名 (未验证) 提交于 2019-12-03 02:56:01

问题:

I want to bypass CSS transition and change a property instantly.
I tried to set transition-duration to 0s before the change and then set transition-duration back to its original value:

Fiddle
This obviously doesn't work.

I understand that the spec does not define that behavior for this:

Since this specification does not define when computed values change, and thus what changes to computed values are considered simultaneous, authors should be aware that changing any of the transition properties a small amount of time after making a change that might transition can result in behavior that varies between implementations, since the changes might be considered simultaneous in some implementations but not others.

Is there an easy way to do this?

Note: The property I am changing is transform so .animate() would not be an option.

回答1:

Since nobody else is posting a valid answer, here goes:

FIDDLE

Or if it's the other way:

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

FIDDLE

jQuery should normalize vendor prefixes these days, so you don't have to type them all yourself.


The issue here is that jQuery attaches all the styles at once, only keeping the last styles, overwriting the previous styles of the same CSS property without ever doing a repaint of the DOM, and testing with native javascript seems to be doing the same thing, so it's probably the browser trying to avoid uneccessary reflows by adding a style just to have it changed in the next line of code, so doing:

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

won't work as only the last style is added.

This is where delay() comes into play, the OP's question was already using delay() so there was no reason not to use it, but removing delay() will of course cause the above issue, where the browser doesn't paint the first style, but only the last etc.

As delay() is really just a fancy timeout, it effectively defers the execution of the second setting of the styles, causing two browser repaints.

As this is most likely a browser issue, and not something we can change, deferring the setting of the second style is the only way to make this work, and using a delay will still work even if it's set to just 1 milliseconds, or one could defer the execution with a regular timeout, which is the usual way to defer execution of a script:

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

FIDDLE

The above will work just fine, as the timeout causes the first setting of the style to be painted by the browser, and defers the setting of the style inside the timeout to a later time, but as no time is set, it's executed as soon as the browser can (but still deferred until after the current script has completed), which for the human eye would seem like immediately, and that solves the issue.



回答2:

If you have control of the CSS

The easiest thing to do is tie the animation to some class, and then at what point you want the animation to no longer be bypassed, you add the class, otherwise no animation is ever set. If the reverse, you generally want the animation, but occasionally want to bypass it, then add the class by default and remove it at time of bypassing.

Example 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 which creates a click event to start animation when it is desired, but this could be some other programmatic trigger to add the class at the time that one no longer wants to bypass it. This fiddle does the opposite, it assumes the animation is present, but on page load immediately bypasses it by removing the class.



回答3:

Set up an override class that would disable css transitions on an element applied to, !important is perfect for this:

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

You can now toggleClass to switch the desired behaviour (smooth transition vs instant change):

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

Fiddled. IMO one of the advantages of this approach is that you have clear separation between default element styling and the disable all smooth animations flag. This is also a very "wrappable" reusable approach, i.e. you can easily add an optional boolean property to your existing methods that would indicate whether or not it should be executed with transitions.

NB: sometimes you may want to disable transitions on the page altogether for whatever performance/UX reasons. In that case, you can change the selector to .notransition * and disable transition on all descendant elements.



回答4:

The issue is that, since there is no reason for the browser to slow down and execute each operation seperately, it combines them and does both at the same time. Querying offsetHeight is one way to force it to do each operation seperately, as it has to recalculate the height. http://jsfiddle.net/markasoftware/6cTeY/15/ works perfectly



回答5:

This is the only way I could make it work. jQuery seems to be a bit stubborn.

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

P.S. There are some errors in your approach:

  1. You are re-sizing to 200px before the delay, thus using the default CSS settings.

  2. You are re-sizing to 10px before the change of the transition back to 2s.

Now jQuery seems to apply all CSS settings in a row so that's why the whole thing does not seem to work.



回答6:

I'd go for a rather clean CSS solution

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/



回答7:

I usually do it in this vanilla JS fashion.

FIDDLE

HTML

Suppose you have an element

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

CSS

Suppose your element has CSS Transitions already active and 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

The element has CSS transitions but we want to change the element's background to BLUE, instantly.

Right after that, we want the element's normal behaviour to return so we can animate it's background to RED.

We need to shut off transitions for a moment and restore them right after.

// 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); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!