How can I change the speed of a CSS animation?

前端 未结 2 1332
一生所求
一生所求 2020-12-06 05:44

I have animation:

img.rotate {
  animation-name: rotate;
  animation-duration: 1.5s;
  animation-iteration-count: inf         


        
相关标签:
2条回答
  • 2020-12-06 05:59

    It's a very difficult process to do so. Currently the only way to change an animation mid-animation is to use a setInterval to approximate the current keyframes percentage, save the properties of that keyframe, update the animation (in your case just the speed) then apply the new version of the animation starting from the saved point. I created a similar example in the article I wrote for CSS Tricks called Controlling CSS Animations & Transitions with Javascript

    As the article described, it'd be easier to change the speed on animationIteration, in your case that would look like this demo, but it is still far from pretty

     var pfx = ["webkit", "moz", "MS", "o", ""],
        rotates = $('.rotate'),
        prevent = false;
    
    function PrefixedEvent(element, type, callback) {
        for (var p = 0; p < pfx.length; p++) {
            if (!pfx[p]) type = type.toLowerCase();
            element.addEventListener(pfx[p]+type, callback, false);
        }
    }
    
    function listen() {
        for(var i = 0, j = rotates.length; i < j; i ++) {
            PrefixedEvent(rotates[i], "AnimationIteration", function() {
                if(!$('#faster').is(':checked') && !prevent) {
                    var el = $(this),  
                       newOne = el.clone(true)
                                .css({'animation':'rotate 2s linear infinite'});
                    el.before(newOne);        
                    $("." + el.attr("class") + ":last").remove();
                    rotates = $('.rotate');
                    listen();
                    prevent = true;
                }
                else if($('#faster').is(':checked') && prevent) {
                    prevent = false;
                    var el = $(this),
                       newOne = el.clone(true)
                                .css({'animation':'rotate 1.5s linear infinite'});
                    el.before(newOne);
                    $("." + el.attr("class") + ":last").remove();
                    rotates = $('.rotate');
                    listen();
                }
            });
        }
    }
    listen();
    

    At the moment we cannot simply restart the animation with a different timing function (even if you pause it and run it again like Michael said). As a result you either have to use a setInterval (which gives a higher delay) or clone the element with the changed values. For more information on the approach I used look at the demo, I added comments to all the javascript I added

    EDIT based on your linked fiddle in comments

    Since you're trying to simulate a roulette, you don't need to use javascript at all! Simply change your rotation animation to change speed over time (: Here's an rough version of how you'd do so, but you should add more keyframes to make it appear more smooth than it currently behaves

    @-webkit-keyframes rotate {
        0%   { -webkit-transform: rotate(   0deg); }
        30%  { -webkit-transform: rotate(2600deg); }
        60%  { -webkit-transform: rotate(4000deg); }
        80%  { -webkit-transform: rotate(4500deg); }
        100% { -webkit-transform: rotate(4780deg); }
    }
    

    EDIT 2

    Since you need apparently need have a random ending position and likely run it multiple times you can do something like this which is much simpler, only uses CSS transforms, and incredibly useful

    var img = document.querySelector('img');
    img.addEventListener('click', onClick, false);    
    var deg = 0;
    
    function onClick() {
        this.removeAttribute('style');        
        deg += 5 * Math.abs(Math.round(Math.random() * 500));        
        var css = '-webkit-transform: rotate(' + deg + 'deg);';        
        this.setAttribute(
            'style', css
        );
    }
    

    and the CSS

    img { -webkit-transition: -webkit-transform 2s ease-out; }
    

    Edit 3

    This isn't fully relevant or irrelevant, but you can do very similar things using GSAP like I did in this project to make it more interactive/dynamic

    0 讨论(0)
  • 2020-12-06 06:13

    You can do that by setting a wrapper, and counter-rotating it.

    CSS

    .wrapper, .inner {
        position: absolute;
        width: 100px;
        height: 100px;
      -webkit-animation-name: rotate;
      -webkit-animation-iteration-count: infinite;
      -webkit-animation-timing-function: linear;
      animation-name: rotate;
      animation-iteration-count: infinite;
      animation-timing-function: linear;
    }
    .wrapper {
        left: 40px;
        top: 40px;
      -webkit-animation-duration: 2.5s;
        -webkit-animation-play-state: paused;
        -webkit-animation-direction: reverse;
      animation-duration: 2.5s;
        animation-play-state: paused;
        animation-direction: reverse;
    }
    .wrapper:hover {
        -webkit-animation-play-state: running;
        animation-play-state: running;
    }
    .inner {
        display: block;
        background-color: red;
      -webkit-animation-duration: 1.5s;
      animation-duration: 1.5s;
    }
    @keyframes rotate {
      from { transform: rotate(0deg);  }
      to {    transform: rotate(360deg);  }
    }    
    @-webkit-keyframes rotate {
      from { -webkit-transform: rotate(0deg);  }
      to {    -webkit-transform: rotate(360deg);  }
    }    
    

    demo

    (hover the square to slow it)

    0 讨论(0)
提交回复
热议问题