3

I'm wondering if it would be possible to achieve an "accelerate, then coast" animation with css, like in this 3D.js example

Basically, an object starts with 0 speed and accelerated its movement until a certain point, and after that, it keeps a constant speed.

I thought it could be accomplished by applying the rotation animation twice to the same element, but with different parameters: * first rotation: the object rotates during 2 seconds, with no delay, with an ease-in function; * after that: the object rotates during 1.5 seconds with a 2 seconds delay to account for the first rotation, with a linear function. This time the rotation repeats infinitely.

So I tried the following code

.square {
    width: 120px;
    height: 120px;
    background: #c00;
    -webkit-animation:
        spin 2s 0 ease-in 1,
        spin 1.5s 2s linear infinite;
    -moz-animation:
        spin 2s 0 ease-in 1,
        spin 1.5s 2s linear infinite;
    animation:
        spin 2s 0 ease-in 1,
        spin 1.5s 2s linear infinite;
    }
}
@-moz-keyframes spin {
    100% { -moz-transform: rotate(360deg); }
}
@-webkit-keyframes spin { 
    100% { -webkit-transform: rotate(360deg); } 
}
@keyframes spin { 
    100% { transform:rotate(360deg); }
}

I know it's not the same as the 3D.js example, but it's close enough. The problem is that the object stops a bit before finishing the first rotation and it looks really weird.

I've prepared a fiddle to show the problem: http://jsfiddle.net/e0sLc8sw/

Any idea?

Thanks everybody for your help!

mvicidomini
  • 143
  • 6
  • I can only suggest that you look into `cubic-bezier` timing functions. Keyword versions already exist such as `ease` - http://jsfiddle.net/e0sLc8sw/3/ – Paulie_D Nov 28 '14 at 16:25
  • http://jsfiddle.net/e0sLc8sw/6/ if you remove the delay for the second spin, the object doesn't stop – Fabrizio Calderan Nov 28 '14 at 16:29

2 Answers2

1

is it not just because you have added 2 times to the second animation?

According to MDN, the second time entry is treated as an animation-delay, which tells the animation to start after that period of time.

Removing the 2s part from the animation works fine:

.square {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 120px;
    height: 120px;
    margin:-60px 0 0 -60px;
    width: 100px;
    height: 100px;
    background: #c00;
    -webkit-animation:
        spin 2s 0 ease-in 1,
        spin 1.5s linear infinite;
    -moz-animation:
        spin 2s 0 ease-in 1,
        spin 1.5s linear infinite;
    animation:
        spin 2s 0 ease-in 1,
        spin 1.5s linear infinite;
}

@-moz-keyframes spin {
    100% { -moz-transform: rotate(360deg); }
}
@-webkit-keyframes spin { 
    100% { -webkit-transform: rotate(360deg); } 
}
@keyframes spin { 
    100% { transform:rotate(360deg); }
}
<div class="square spinning">:D</div>

UPDATED FIDDLE

Rhumborl
  • 16,349
  • 4
  • 39
  • 45
  • Thanks Rhumbor, you nailed it, I didn't know the second time entry were treated as an animation-delay. Would it work also with more animations? If you added a third, fourth… animation, would they all start after the previous ones had finished? – mvicidomini Nov 28 '14 at 17:51
  • I'm getting a weird result with the fiddle above. The expected behavior happens on page load (accelerates then spins infinitely) but when I click "run" first animation occurs and then stops. The same behavior happens if I copy the code to my pc. I can't get it produce the second animation. I'm using webkit (chrome). Tried on 2 separate machines. – Patrick Borkowicz Apr 17 '15 at 17:04
0

The previous examples don't work in modern Chrome (2018). Here's an updated example using a cubic bezier curve to handle the acceleration - you can play around with the acceleration parameters here.

The first animation handles the acceleration - the 3s here indicates it will get to the last frame after 3 seconds with the bezier acceleration function. It then terminates. The 3s in the second animation indicates this one begins exactly where the other one left off, ie it has a 3 second delay, but this one never terminates as it has "infinite" duration. It's much faster at 0.5 seconds.

Ideally the 0.5 second speed should be matched to the precise speed of the first animation caused by the Bezier acceleration. This is a manual calculation I don't think CSS helps with and I didn't perform here, just used an eye test.

.square {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 120px;
    height: 120px;
    margin:-60px 0 0 -60px;
    width: 100px;
    height: 100px;
    background: #c00;
    animation:
        spin 3s cubic-bezier(.52,.29,.83,.13),
        spin 0.5s linear 3s infinite;
}

@keyframes spin { 
    100% { transform:rotate(360deg); }
}
<div class="square spinning">:D</div>
mahemoff
  • 44,526
  • 36
  • 160
  • 222