Stop shaking in CSS animation - css

So I'm making a tic tac toe game right now and I'm trying to add in an animation for a line that shows who won. When the player wins by getting 3 horizontal things then the animation works perfectly but when they win vertically then there's a slight shake on it. Is there any way I can remove this?
Here is the CSS for the line:
#keyframes grow-left {
0% {
width: 0;
}
100% {
width: 1;
}
}
.winLine {
position: absolute;
width: 300%;
height: var(--borderThickness);
background-color: var(--textColor);
border-radius: 1rem;
transform-origin: center;
z-index: 2;
animation: grow-left 1s ease-in-out 0s;
opacity: 1;
}
To view the website and see what I'm talking about it's live on GitHub at this link https://bartycoding.github.io/Tic-tac-toe/

Try creating another div that increases the height instead of using the transform: rotate(90deg);

You could try with transform: scale():
#keyframes grow-left {
0% {
transform: scale(0,1);
}
100% {
transform: scale(1,1);
}
}

I actually fixed this by having the rotation as a global css variable and then changing that variable from javascript so the css looks like this:
#keyframes grow-left {
0% {
transform: rotate(var(--winLineRotation)) scaleX(0);
}
100% {
transform: rotate(var(--winLineRotation)) scaleX(100%);
}
}
.winLine {
position: absolute;
width: 300%;
height: var(--borderThickness);
background-color: var(--textColor);
border-radius: 1rem;
transform-origin: center;
z-index: 2;
animation: grow-left 1s ease-in-out 0s;
opacity: 1;
transform: rotate(var(--winLineRotation));
}

To prevent that little shake at the end of animations, you need to use : backface-visibility:hidden; to the class of the element that you've defined animation for.
#keyframes grow-left {
0% {
width: 0;
}
100% {
width: 1;
}
}
.winLine {
/* Try this */
backface-visibility: hidden;
position: absolute;
width: 300%;
height: var(--borderThickness);
background-color: var(--textColor);
border-radius: 1rem;
transform-origin: center;
z-index: 2;
animation: grow-left 1s ease-in-out 0s;
opacity: 1;
}

Related

The same CSS animations does not have the same durations (with animated background color)

I try to animate two blocks with css animation. Its have the same transform animation but one of it has background-color animation also. This animations splitted to two #keyframes.
See code (https://codepen.io/mctep/pen/Rgyaep):
<style>
.a {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background-color: red;
animation: a 1s infinite;
}
.b {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background-color: gray;
animation: b 1s infinite;
}
#keyframes a {
0% {
background-color: red;
transform: translateX(0);
}
50% {
background-color: green;
transform: translateX(100px);
}
100% {
background: red;
}
}
#keyframes b {
0% {
transform: translateX(0);
}
50% {
transform: translateX(100px);
}
}
</style>
<div class="a"></div>
<div class="b"></div>
Animation of colored block is lag from gray block In Google Chrome. In Safary and FF it works perfectly.
I can to make one #keyframes for background and other for transform and it solves problem. But I want to use single value of animation property for single element. If there are no any ways to fix it I'll separate moving and coloring animations.
Why this happens? Is it Google Chrome bug?
Couldn't give you a concrete reason why this happens, but we can un-confuse Chrome by simply specifying a background-color in animation B as well.
#keyframes b {
0% {
background-color: gray; /* add this */
transform: translateX(0);
}
}
.a {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background-color: red;
animation: a 1s infinite;
}
.b {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background-color: gray;
animation: b 1s infinite;
}
#keyframes a {
0% {
background-color: red;
transform: translateX(0);
}
50% {
background-color: green;
transform: translateX(100px);
}
100% {
background: red;
}
}
#keyframes b {
0% {
background-color: gray;
transform: translateX(0);
}
50% {
transform: translateX(100px);
}
}
<div class="a"></div>
<div class="b"></div>

Animate transform only one property (scale) override other (translate)

The problem is that the transform property's value has multiple part like translate, scale etc.
This is a theoretical question about element, let's .loader that has transform:translate(10px, 10px) and in the animation I want to animate the scale property. In this case, the browser will not take the transform:translate(10px, 10px) and will take only the scale.
I am looking for a way around this problem.
Here is an example to this question. Please, keep attention that I'm not looking for an answer to this particular example (like: wrap the element or add the translate value to the animation definition) but a generic solution (if exist, of course).
.loading {
position: relative;
width: 100px;
height: 100px;
background: #eee;
}
.loading:before,
.loading:after {
content: "";
width: 50%;
height: 50%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
background-color: #fff;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
/* the broswer doesn't take this */
transform: translate(100px, 300px);
-webkit-animation: bounce 2s infinite ease-in-out;
animation: bounce 2s infinite ease-in-out;
}
.loading:after {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
#keyframes bounce {
0%, 100% {
transform: scale(0);
-webkit-transform: scale(0);
}
50% {
transform: scale(1);
-webkit-transform: scale(1);
}
}
<div class="loading"></div>
Generally when you add an animation with changes to the transform property then the transforms that are specified in the base element should also be carried over to be present within the animation's keyframes also. That is, the new transforms (that are part of the animation) should be added over on top of the existing transform and not overwrite it. Below is how it should be done.
.loading {
position: relative;
width: 200px;
height: 200px;
background: #eee;
}
.loading:before,
.loading:after {
content: "";
width: 50%;
height: 50%;
border-radius: 50%;
background-color: #fff;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
transform: translate(100px, 300px);
animation: bounce 2s infinite ease-in-out;
}
.loading:after {
animation-delay: -1s;
}
#keyframes bounce {
0%, 100% {
transform: scale(0) translate(100px, 300px);
}
50% {
transform: scale(1) translate(100px, 300px);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="loading"></div>
I wrote a similar answer here to a question about adding multiple animations on an element with each of those animations modifying the transform property's values independent of the other. I am linking it here only for reference and don't think they are duplicates.
Having said the above, adding the the original transform to each animation's kefyrames is not possible when you are trying to create animation libraries or trying to split each animation into a separate class. Say for example, you want to add the same bounce animation to multiple elements and each of them have a different initial transform setting then it becomes impossible to add it to animation's keyframe.
In such cases, you can still achieve the desired output using CSS but it would be very difficult (almost impossible in my opinion) to get it done with a single element.
What options do you have? Well, one option is for you to add the animation on a wrapper element.
.loading-wrapper {
position: relative;
width: 200px;
height: 200px;
background: #eee;
}
.loading-before, .loading-after {
position: absolute;
width: 50%;
height: 50%;
top: 0px;
left: 0px;
animation: bounce 2s infinite ease-in-out;
}
.loading-before:before,.loading-after:before {
content: "";
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #fff;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
transform: translate(100px, 300px);
}
.loading-after {
animation-delay: -1s;
}
#keyframes bounce {
0%, 100% {
transform: scale(0);
}
50% {
transform: scale(1);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="loading-wrapper">
<div class="loading-before"></div>
<div class="loading-after"></div>
</div>
The solution is quite generic and you can apply it to almost all such cases. The drawback is that if you want to stack multiple such transformations then you'd likely end up with multiple such wrappers. There is no pure CSS way other than adding original transformations within the animation's keyframes also.
The below snippet is another sample.
.move-n-scale {
position: relative;
height: 100px;
width: 100px;
background: sandybrown;
border: 1px solid chocolate;
transform: scale(0.5);
animation: move 1s linear infinite alternate-reverse;
}
.move {
position: relative;
display: inline-block;
animation: move-only 1s linear infinite alternate-reverse;
}
.scale {
position: absolute;
height: 100px;
width: 100px;
top: 0px;
left: 0px;
background: sandybrown;
border: 1px solid chocolate;
transform: scale(0.5);
}
#keyframes move {
from {
transform: translateX(0px) scale(0.5);
}
to {
transform: translateX(300px) scale(0.5);
}
}
#keyframes move-only {
from {
transform: translateX(0px);
}
to {
transform: translateX(300px);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='move-n-scale'></div>
<div class='move'>
<div class='scale'></div>
</div>
Note: Just to clarify, I did notice that you had mentioned about not wanting a solution which is very specific to this problem like wrap it etc. But, I had still added this solution as an answer because it is the only generic solution which I am aware of. I had added the second snippet only to show that is is indeed generic.
You can delete the translate(100px, 300px); in .loading:after, then set the translate(100px, 300px) in #keyframes, like follows:
#keyframes bounce {
0%,
100% {
transform: scale(0)translate(100px, 300px);
-webkit-transform: scale(0)translate(100px, 300px);
}
50% {
transform: scale(1)translate(100px, 300px);
;
-webkit-transform: scale(1)translate(100px, 300px);
}
}

Moving two lines in opposite directions via CSS3 animations

I have this code: https://jsfiddle.net/xuj0uu2k/4/
Markup
<div class="lline"></div>
<div class="projekt"><h1>SERVICES</h1></div>
<div class="rline"></div>
CSS
#keyframes anima {
from {width: 0%; }
to { width: 40%; }
}
.lline {
margin-top: 20px;
width: 40%;
background-color: #333;
animation-name: anima;
animation-duration:1s;
height: 2px;
float: left; }
.projekt {
text-align: center;
width: 14%;
margin: 0 auto; }
.rline {
margin-top: -38px;
width: 40%;
background-color: #333;
animation-name: anima;
animation-duration:1s;
height: 2px;
float: right; }
I need to animate the two lines from the text SERVICES to its borders.
I tried to set it up with animation-direction property, but it didn't work. The lines must be responsive, so I have to use some mediaqueries, but if you know better way to do it, I'll be glad. Thank you
You could do it with less markup using pseudoelements and display: flex, like in this example: http://codepen.io/fcalderan/pen/aObYLK
Markup
<h1 class="animateheading">SERVICES</h1>
Css
.animateheading {
width: 100%;
text-align: center;
overflow: hidden;
display: flex;
align-items: center;
}
/* lines */
.animateheading:before,
.animateheading:after {
content: "";
flex-grow: 1;
height: 1px;
min-width: 100px;
border-top: 1px #333 solid;
}
/* animation toward left */
.animateheading:before {
margin-right: .3em;
-webkit-animation: lineleft 3s linear 1s forwards;
-moz-animation: lineleft 3s linear 1s forwards;
animation: lineleft 3s linear 1s forwards;
}
/* animation toward right */
.animateheading:after {
margin-left: .3em;
-webkit-animation: lineright 3s linear 1s forwards;
-moz-animation: lineright 3s linear 1s forwards;
animation: lineright 3s linear 1s forwards;
}
/* keyframes for left animation */
#-webkit-keyframes lineleft {
from { -webkit-transform: translate(0, 0); }
to { -webkit-transform: translate(-100%, 0); }
}
#-moz-keyframes lineleft {
from { -moz-transform: translate(0, 0); }
to { -moz-transform: translate(-100%, 0); }
}
#keyframes lineleft {
from { transform: translate(0, 0); }
to { transform: translate(-100%, 0); }
}
/* keyframes for right animation */
#-webkit-keyframes lineright {
from { -webkit-transform: translate(0, 0); }
to { -webkit-transform: translate(100%, 0); }
}
#-moz-keyframes lineright {
from { -moz-transform: translate(0, 0); }
to { -moz-transform: translate(100%, 0); }
}
#keyframes lineright {
from { transform: translate(0, 0); }
to { transform: translate(100%, 0); }
}
Just some notes about this implementation
Flexbox position could require several different syntaxes, due to its implementation across browser: see http://caniuse.com/#feat=flexbox; since it is applied on pseudoelements only for styling purpose, a lack of support can be considered as graceful degradation;
This code works with text of any length and on every viewport size, since it animates the transform property using a percentage value. No matter how many rows will take the text, the lines will be always vertically centered;
Add as many vendor prefixes as you need for the keyframes;
The animation-fill-mode property is set to forwards so the last animation frame will be retained (and the lines don't come back).
If you need to always see two lines, even for really long texts, set a min-width on pseudoelements as I did in the example, otherwise you may safely remove it.

Play first keyframe only once / queue animations

I've written the following bit of CSS:
.bulb--off {
position: relative;
z-index: 11;
}
.bulb--on {
position: absolute;
z-index: 11;
left:rem(1);
right:0;
opacity:0;
}
.bulb--on {
opacity:0.4;
animation-name: bulbFlicker;
animation-duration: 0.5s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-play-state: running;
animation-delay: 1s;
}
#keyframes bulbFlicker {
0% { opacity: 1; }
25% { opacity: 0.9; }
50% { opacity: 0.95; }
75% { opacity: 0.9; }
100% { opacity: 1; }
}
What I hope to happen here is that the bulb would fade from off (opacity:0) to on (opacity:1) and then flicker.
What actually happens is that the bulb jumps from off to on (no fade) and then starts flickering, clearly what is happening is that when the animation starts it begins keyframe 1 as it should. I've tried adding a transition on opacity so that when it starts keyframe 1 it fades to it but it seems to ignore that property. Is there a way I can chain animations or even only make it play the first keyframe once?
I think I can do this using javascript but I've managed to get this far using CSS only and ideally I'd like it to remain CSS only.
If you apply two animations and add a delay to the second one equal to the length of the first animation you get the played first effect.
.light {
-webkit-animation: fade 3s;
animation: fade 3s;
opacity: 1;
}
.light .bulb {
-webkit-animation: jitter 1s infinite;
animation: jitter 1s infinite;
-webkit-animation-delay: 4s;
animation-delay: 4s;
}
#-webkit-keyframes fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#-webkit-keyframes jitter {
0% {
opacity: 1;
}
50% {
opacity: 1;
}
55% {
opacity: 0.4;
}
60% {
opacity: 1;
}
100% {
opacity: 1;
}
}
#keyframes jitter {
0% {
opacity: 0.5;
}
50% {
opacity: 0.2;
}
100% {
opacity: 1;
}
}
/*Meaningless stuff for it to look cool*/
.bulb {
width: 50px;
height: 50px;
border: 2px solid gray;
border-top-left-radius: 100%;
border-top-right-radius: 100%;
border-bottom-left-radius: 50% 85%;
border-bottom-right-radius: 50% 85%;
background-color: yellow;
}
.metal {
margin-left: 10px;
width: 34px;
height: 10px;
background-color: gray;
border-bottom-right-radius: 10%;
border-bottom-left-radius: 10%;
}
.pole {
margin-left: 17.5px;
height: 100px;
width: 20px;
background-color: gray;
}
<div class="light">
<div class="bulb"></div>
<div class="metal"></div>
<div class="pole"></div>
</div>

How to run a CSS animation infintely forwards

So I'm looking to create a really basic snow effect.
I have a keyframe animation for the flake swaying side to side and moving down the Y axis. I want the element to retain the ending values using forwards. But I also want to then loop the animation (infinite), so that it continues where it left off.
HTML:
<div>
<figure class="small"></figure>
</div>
CSS:
div {
width: 100%;
height: 250px;
background: #184254;
}
figure {
border-radius: 50%;
}
#-webkit-keyframes snowfall {
25% {
transform: translateX(10px) translateY(20px);
}
75% {
transform: translateX(-10px) translateY(30px);
}
100% {
transform: translateX(0px) translateY(40px);
}
}
.small {
margin-left: 100px;
width: 7px;
height: 7px;
background: #DFE9ED;
-webkit-animation: snowfall 2s ease-in-out forwards infinite;
}
http://codepen.io/mildrenben/pen/PwZdXB
You can use two animations, one to move right-left and other to make it fall.
The up to down animation will work with absolute positioning, so it will depend on body height (or its first parent with absolute or relative positioning).
figure {
border-radius: 50%;
position: absolute;
}
#-webkit-keyframes snowside {
25% {
transform: translateX(10px);
}
75% {
transform: translateX(-10px);
}
100% {
transform: translateX(0px);
}
}
#-webkit-keyframes snowfall {
0% {
top: 0;
}
100% {
top: 100%;
}
}
.small {
margin-left: 100px;
width: 7px;
height: 7px;
background: #DFE9ED;
-webkit-animation: snowside 2s ease-in-out forwards infinite, snowfall 15s ease-in-out forwards infinite;
}
http://codepen.io/anon/pen/YPwOMY

Resources