strange keyframes setting in CSS animation - css

Inspired by this tutorial http://tympanus.net/codrops/2014/01/07/shape-hover-effect-with-svg/ I decided to make pure css version of similar effect.
And it looks good and work pretty smooth. What bothers me is why after few attempts I had to set keyframes at 24% and 74% instead of 50%? With 50% animation looks choppy. I really don't like to do things blindfolded, so I'll be grateful for help.
Here is quick dirty implementation:
html {
background: #ccc;
}
.card {
position: relative;
display: inline-block;
height: 400px;
width: 200px;
background: #000;
margin: 50px;
overflow: hidden;
}
.card-head {
position: absolute;
background: #000;
height: 400px;
width: 400px;
border-radius: 50%;
left: -100px;
top: -173px;
z-index: 10;
-webkit-animation-name: carda;
animation-name: carda;
}
.card-extend {
position: absolute;
background: #fff;
height: 400px;
width: 400px;
bottom: -200px;
left: -100px;
z-index: 5;
-webkit-animation-name: cardb;
animation-name: cardb;
}
.card-animated {
-webkit-animation-duration: .2s;
animation-duration: .2s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
-webkit-animation-timing-function:ease-in-out;
animation-timing-function:ease-in-out;
}
.card:hover .card-head,
.card:focus .card-head{
-webkit-animation-name: cardhovera;
animation-name: cardhovera;
}
.card:hover .card-extend,
.card:focus .card-extend{
-webkit-animation-name: cardhoverb;
animation-name: cardhoverb;
}
#-webkit-keyframes carda {
from {
border-radius: 0%;
top: -320px;
z-index: 2;
}
24% {
top: -320px;
border-radius: 25%;
z-index: 2;
}
to {
border-radius: 50%;
top: -173px;
}
}
#keyframes carda {
from {
border-radius: 0%;
top: -320px;
z-index: 2;
}
24% {
top: -320px;
border-radius: 25%;
z-index: 2;
}
to {
border-radius: 50%;
top: -173px;
}
}
#-webkit-keyframes cardhovera {
from {
border-radius: 50%;
top: -173px;
}
76% {
top: -320px;
border-radius: 25%;
z-index: 2;
}
to {
border-radius: 0%;
top: -320px;
z-index: 2;
}
}
#keyframes cardhovera {
from {
border-radius: 50%;
top: -173px;
}
76% {
top: -320px;
border-radius: 25%;
z-index: 2;
}
to {
border-radius: 0%;
top: -320px;
z-index: 2;
}
}
#-webkit-keyframes cardb {
from {
bottom: -53px;
border-radius: 50%;
}
76% {
bottom: -200px;
border-radius: 25%;
}
to {
border-radius: 0;
z-index: 5;
bottom: -200px;
}
}
#keyframes cardb {
from {
bottom: -53px;
border-radius: 50%;
}
76% {
bottom: -200px;
border-radius: 25%;
}
to {
border-radius: 0;
z-index: 5;
bottom: -200px;
}
}
#-webkit-keyframes cardhoverb {
from {
border-radius: 0;
z-index: 5;
bottom: -200px;
}
24% {
bottom: -200px;
border-radius: 25%;
}
to {
bottom: -53px;
border-radius: 50%;
}
}
#keyframes cardhoverb {
from {
border-radius: 0;
z-index: 5;
bottom: -200px;
}
24% {
bottom: -200px;
border-radius: 25%;
}
to {
bottom: -53px;
border-radius: 50%;
}
}
<div tabindex="0" class="card">
<div class="card-head card-animated">
</div>
<div class="card-extend card-animated">
</div>
</div>

I think this choppy effect you are talking about has more to do with the way animation in css work. As the easing is applied to the whole extension of it, this means, imagine some keyframes like this:
#keyframes exampleFrames {
0% {
transform: translateX(50px)
}
50% {
transform: translateX(0)
}
100% {
transform: translateX(50px)
}
}
Even though you can add easing to the animation the element affected will start at 50 pixels to the right and start moving to the left to it's initial position and in the center frame will suddenly change direction to get to the last position again. The issue is with this sudden change, this is what makes it choppy.
To avoid this you might need to use javascript or, as you've seen tweak the keyframes to minimise this undesirable visual effect.

Related

CSS animations with transform: translate

Please help, when I'm trying to play animation with moving ball in position X and Y at the same time it doesn't work, some strange behaviour. I would like to look like a batted and falling ball
.ball {
position: absolute;
left: 18%;
bottom: 100px;
width: 40px;
height: 40px;
background-color: cadetblue;
border-radius: 50%;
animation: fly-ball-x 2s, fly-ball-y 2s;
}
#keyframes fly-ball-x {
100% {
transform: translateX(300px);
}
}
#keyframes fly-ball-y {
100% {
transform: translateY(100px);
}
}
<div class="ball"></div>
**The result I'm expecting is like the code below:**
#keyframes fly-ball-x {
100% {
left: 300px;
}
}
#keyframes fly-ball-y {
100% {
bottom: 0;
}
}
.ball {
position: absolute;
left: 18%;
bottom: 100px;
width: 40px;
height: 40px;
background-color: cadetblue;
border-radius: 50%;
animation: fly-ball-x 2s cubic-bezier(0.17, 0.67, 0.6, 1), fly-
ball-y 2s;
}
<div class="ball"></div>
.ball {
position: absolute;
left: 18%;
bottom: 100px;
width: 40px;
height: 40px;
background-color: cadetblue;
border-radius: 50%;
animation: fly-ball 2s
}
#keyframes fly-ball {
100% {
transform: translateX(300px) translateY(100px);
}
}
<div class="ball"></div>
It is because you weren't running the animations concurrently. Here both translations are just being run at the same time. You just had a bit more than you needed.
EDIT
Check out this blog post. It gives explanations on the kinds of curves it seems you are going for Curved Path Animations In CSS

Adding a bounce effect using CSS animation

I'm playing round with CSS animation by trying to replicate the following new google ads logo - example.
What is the best way to add the bounce effect on the green ball?
My current animation:
#keyframes greenblock {
0% {
top: 0px;
}
50% {
top: 45px;
}
100% {
bottom: 0px;
}
}
My code (fiddle):
.wrap {
border: 1px solid red;
height: 300px;
width: 300px;
position: relative
}
.blue-shape {
position: absolute;
left: 100px;
top: 0px;
width: 45px;
height: 45px;
background: #4285F4;
display: block;
border-radius: 45px;
animation: blueblock 2s forwards;
transform-origin: top center;
}
.yellow-shape {
position: absolute;
left: 122px;
top: 0px;
width: 45px;
height: 45px;
background: #FBBC04;
display: block;
border-radius: 45px;
animation: yellowblock 2s forwards;
transform-origin: top center;
}
.green-ball {
position: absolute;
border-radius: 45px;
width: 45px;
height: 45px;
background: #34A853;
animation: greenblock 1.5s forwards;
}
#keyframes blueblock {
0% {
height: 45px;
}
25% {
height: 140px;
transform: rotate(0deg);
}
50% {
transform: rotate(-30deg);
}
100% {
height: 140px;
transform: rotate(-30deg);
}
}
#keyframes yellowblock {
0% {
height: 45px;
opacity: 0;
}
25% {
height: 140px;
transform: rotate(0deg);
opacity: 0;
}
50% {
transform: rotate(30deg);
}
100% {
height: 140px;
transform: rotate(30deg);
opacity: 100;
left: 122px;
}
}
#keyframes greenblock {
0% {
top: 0px;
}
50% {
top: 45px;
}
100% {
bottom: 0px;
}
}
<div class="wrap">
<div class="yellow-shape">
<div class="green-ball">
</div>
</div>
<div class="blue-shape">
</div>
</div>
I've tried with this animation
animation: greenblock .6s ease-in-out .5s forwards;
and this set of keyframes
#keyframes greenblock {
0% { top: 0px; }
75% { top: calc(100% - 55px); }
50%, 100% { top: calc(100% - 45px); }
}
Demo
.wrap {
border: 1px solid red;
height: 300px;
width: 300px;
position: relative
}
.blue-shape {
position: absolute;
left: 100px;
top: 0px;
width: 45px;
height: 45px;
background: #4285F4;
display: block;
border-radius: 45px;
animation: blueblock 2s forwards;
transform-origin: top center;
}
.yellow-shape {
position: absolute;
left: 122px;
top: 0px;
width: 45px;
height: 45px;
background: #FBBC04;
display: block;
border-radius: 45px;
animation: yellowblock 2s forwards;
transform-origin: top center;
}
.green-ball {
position: absolute;
border-radius: 45px;
width: 45px;
height: 45px;
background: #34A853;
animation: greenblock .6s ease-in-out .5s forwards;
}
#keyframes blueblock {
0% {
height: 45px;
}
25% {
height: 140px;
transform: rotate(0deg);
}
50% {
transform: rotate(-30deg);
}
100% {
height: 140px;
transform: rotate(-30deg);
}
}
#keyframes yellowblock {
0% {
height: 45px;
opacity: 0;
}
25% {
height: 140px;
transform: rotate(0deg);
opacity: 0;
}
50% {
transform: rotate(30deg);
}
100% {
height: 140px;
transform: rotate(30deg);
opacity: 100;
left: 122px;
}
}
#keyframes greenblock {
0% { top: 0px; }
75% { top: calc(100% - 55px); }
50%, 100% { top: calc(100% - 45px); }
}
<div class="wrap">
<div class="yellow-shape">
<div class="green-ball">
</div>
</div>
<div class="blue-shape">
</div>
</div>

"transform: rotate()" causes unwanted "wagging" motion

I was playing around with some #keyframes animations and i got this funky "wagging" kind of motion, problem is I don't know why...
.spinner {
position: relative;
border: 16px solid #e7e7e7;
border-radius: 50%;
height: var(--size);
width: var(--size);
--size: 100px;
}
.spinner>* {
position: absolute;
border: 8px solid transparent;
border-radius: 50%;
animation-direction: alternate;
border-top-color: var(--color);
top: var(--distance); bottom: var(--distance);
left: var(--distance); right: var(--distance);
}
.spinner>:nth-child(1) {
--color: orangered;
--distance: -16px;
animation: spin1 1.8s ease-in-out infinite;
}
.spinner>:nth-child(2) {
--color: skyblue;
--distance: -8px;
animation: spin2 1.8s ease-in-out infinite;
}
#keyframes spin1 {
0% {
transform: rotate(0deg);
}
25% {
top: -16px; bottom: -16px;
left: -16px; right: -16px;
}
50% {
top: -8px; bottom: -8px;
left: -8px; right: -8px;
}
75% {
top: -16px; bottom: -16px;
left: -16px; right: -16px;
}
100% {
transform: rotate(-360deg);
}
}
#keyframes spin2 {
0% {
transform: rotate(-360deg);
}
25% {
top: -8px; bottom: -8px;
left: -8px; right: -8px;
}
50% {
top: -16px; bottom: -16px;
left: -16px; right: -16px;
}
75% {
top: -8px; bottom: -8px;
left: -8px; right: -8px;
}
100% {
transform: rotate(0deg);
}
}
<div class="spinner">
<div></div>
<div></div>
</div>
I'm guessing the "wagging" is caused by the resizing of the 2 inner div:s, however I haven't been able to figure out how to get rid of it.. I'd appreciate both a solution and a better explanation as to why this happens so i can avoid it in the future.
Never mind... after capturing a gif of the animation I realized that the "wagging" was just an optical illusion caused by the way I animate the two slivers...

Css Animation - animation delay

Update - The pen below has been updated to show the end results.
I am trying to mimic signal animation using css animation but I cant seem to grasp the idea of animation delay. If you look here
http://codepen.io/anon/pen/YwZOmK?editors=110
.real-time-animation {
margin-top: 20px;
position: relative;
transform: scale(0.5) rotate(45deg);
transform-origin: 5% 0%;
}
.real-time-animation>div {
animation: sk-bouncedelay 3s infinite forwards;
}
.circle1 {
animation-delay: 2s;
}
.circle2 {
animation-delay: 1s;
}
#keyframes sk-bouncedelay {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.circle {
position: relative;
width: 16em;
height: 16em;
border-radius: 50%;
background: transparent;
border: 20px solid transparent;
border-top-color: darkblue;
position: absolute;
top: 0;
left: 0;
opacity: 0;
}
.circle2 {
top: 40px;
width: 12em;
height: 12em;
left: 33px;
}
.circle3 {
top: 80px;
width: 8em;
height: 8em;
left: 66px;
}
<div class="real-time-animation">
<div class="circle circle1"> </div>
<div class="circle circle2"> </div>
<div class="circle circle3"> </div>
</div>
You should be able to understand what I am trying to accomplish. I want to start from showing nothing, then after 1 sec show the first bar, then after 1 sec, show the 2nd bar and finally after another 1 sec show the 3rd bar.
My solution:
http://codepen.io/anon/pen/JGWmJg?editors=110
.real-time-animation{
margin-top: 20px;
position: relative;
transform: scale(0.5) rotate(45deg);
transform-origin: 5% 0%;
}
.circle1, .circle2, .circle3{
animation: 4s infinite ease-in;
animation-delay: 1s;
}
.circle1{
animation-name: circle1;
}
.circle2{
animation-name: circle2;
}
.circle3{
animation-name: circle3;
}
#keyframes circle1 {
0%{
opacity: 0;
}
25%{
opacity: 0;
}
50%{
opacity: 0;
}
75%{
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes circle2 {
0%{
opacity: 0;
}
25%{
opacity: 0;
}
50%{
opacity: 1;
}
75% {
opacity: 1;
}
100%{
opacity: 0;
}
}
#keyframes circle3 {
0%{
opacity: 0;
}
25%{
opacity: 1;
}
50%{
opacity: 1;
}
75% {
opacity: 1;
}
100%{
opacity: 0;
}
}
.circle {
position: relative;
width: 16em; height: 16em;
border-radius: 50%;
background: transparent;
border: 20px solid transparent;
border-top-color: darkblue;
position: absolute;
top: 0;
left: 0;
opacity: 0;
}
.circle2{
top: 40px;
width: 12em;
height: 12em;
left: 33px;
}
.circle3{
top: 80px;
width: 8em;
height: 8em;
left: 66px;
}
You can change the speed of the animation duration: "animation: 4s infinite ease-in;"
As I understand your question animated opacity needs to be like this:
Progress \ Element
.circle1
.circle2
.circle3
0%
0
0
0
25%
0
0
1
50%
0
1
1
75%
1
1
1
100%
0
0
0
The opacity property is clamped which means if you set negative values, it will have the same effect as setting it to 0. The same goes for values larger than 1.
Using this property, we can subtract a constant value from predefined CSS variables and use that as opacity.
.real-time-animation {
zoom: 10;
width: 8px;
height: 8px;
position: relative;
display: inline-block;
}
.real-time-animation>.circle {
animation: circle 4s infinite ease-in;
}
.circle1 {
--circle: 1;
}
.circle2 {
--circle: 2;
}
.circle3 {
--circle: 3;
}
#keyframes circle {
0%, 100% {
opacity: 0;
}
25% {
opacity: calc(var(--circle) - 2);
}
50% {
opacity: calc(var(--circle) - 1);
}
75% {
opacity: 1;
}
}
.circle {
border-radius: 50%;
background: transparent;
border: 1px solid transparent;
border-top-color: darkblue;
position: absolute;
margin: 0;
box-sizing: border-box;
top: 100%;
left: 0%;
width: calc(16px - (var(--circle) - 1)*4px);
height: calc(16px - (var(--circle) - 1)*4px);;
transform: rotate(45deg) translate(-50%, -50%);
transform-origin: 0 0;
}
<div class="real-time-animation">
<div class="circle circle1"> </div>
<div class="circle circle2"> </div>
<div class="circle circle3"> </div>
</div>

CSS3 transform: translateX equivalent for right

I want to do this: -webkit-transform: translateX(300px) but from the right instead of having the origin on left.
I tried -webkit-transform-origin: 100% 100% and even top right and it didn't affect it.
Is there a way to do it?
By the power of CSS:
body {
padding: 0;
margin: 0;
}
#page {
position: absolute;
width: 100%;
height: 100%;
background-color: black;
z-index:2;
right:0;
}
#left_drawer {
background-color: #222222;
position: absolute;
top: 0;
right: 0;
width: 300px;
height: 100%;
z-index: 1;
}
#toggle {
width: 50px;
height: 50px;
background-color: red;
float: right;
}
.open_drawer {
-webkit-animation: open_drawer 300ms ease-in-out;
-webkit-animation-fill-mode: forwards;
-webkit-transform: translateX(0);
}
#-webkit-keyframes open_drawer {
to {
-webkit-transform: translateX(-300px);
}
}
This will make it slide in from the right. Fiddle.

Resources