CSS animations - How to toggle direction with one keyframes declaration - css

I would like a div to animate to the right when a button is clicked, then animate again to the left when the same button is clicked. I would like to use only one keyframes declaration. Is this possible by swapping classes?
I've tried this in CodePen, but unfortunately, the div snaps back after the first animation, then refuses to animate the second time.
I'm not using CSS transitions because I want to be able to use features of CSS animations like a bouncing effect.
window.addEventListener("load", function() {
var movedOver = false;
document.querySelector("button").addEventListener("click", function() {
var buttonEl = document.querySelector(".one");
if (movedOver) {
buttonEl.classList.remove("do-the-slide");
buttonEl.classList.add("do-the-slide-back");
} else {
buttonEl.classList.remove("do-the-slide-back");
buttonEl.classList.add("do-the-slide");
}
});
});
.container {
position: absolute;
perspective: 800px;
>div {
position: absolute;
padding: 20px;
text-align: center;
width: 100px;
}
>div.do-the-slide {
animation: moveOver 1s ease-out;
}
>div.do-the-slide-back {
animation: moveOver 1s reverse ease-out;
}
>.one {
background: red;
}
}
button {
margin-top: 100px;
}
#keyframes moveOver {
from {
transform: translateX(0px);
}
to {
transform: translateX(100px);
}
}
<div class="container">
<div class="one">One</div>
</div>
<button>Clicky</button>
Codepen: http://codepen.io/anon/pen/Vaadao

Alright, so after fiddling with this for a while, I've come up with what I consider an acceptable solution for using one keyframes declaration to drive both directions of animations. The key to this was forcing the browser essentially reset through a redraw, as explained here: https://css-tricks.com/restart-css-animation/ (thank you Jacob Gray for posting that reference).
Once I got that working with the reset, I used javascript (yes, this requires javascript) to add the reverse direction when animating back (this could be in a separate class and just add that className).
And, it works. I'm now able to animate in both directions using one keyframes declaration. Pretty snazzy, and drastically minimizes the css code.
window.addEventListener("load", function() {
var movedOver = false;
var direction = "";
document.querySelector("button").addEventListener("click", function() {
var el = document.querySelector(".one");
el.classList.remove("do-the-slide");
el.offsetWidth = el.offsetWidth;
if (direction === "toRight") {
direction = "toLeft";
el.style.animationDirection = "reverse";
} else {
direction = "toRight";
el.style.animationDirection = "";
}
el.classList.add("do-the-slide");
});
});
.container {
position: absolute;
perspective: 800px;
>div {
position: absolute;
padding: 20px;
text-align: center;
width: 100px;
}
>div.do-the-slide {
animation: moveOver 1s ease-in-out;
animation-fill-mode: forwards;
}
>.one {
background: red;
}
}
button {
margin-top: 100px;
}
#keyframes moveOver {
from {
transform: translate3d(0px, 0, 0);
}
20% {
transform: translate3d(-20px, 0, 0);
}
80% {
transform: translate3d(120px, 0, 0);
}
to {
transform: translate3d(100px, 0, 0);
}
}
<div class="container">
<div class="one">One</div>
</div>
<button>Clicky</button>
CodePen: http://codepen.io/risingtiger/pen/zqqMpv

Maybe you are looking for forwards, but even then, a transition will be needed to make it simple.
p span {
display: inline-block;
transition: 1s;
}
p:hover span {
animation: 1s moveOver forwards;
}
#keyframes moveOver {
to {
transform: translateX(100px);
}
<p><span>span</span>
</p>
I f you want to use a single animation, you will eventually have to deal with paused and steps and i m not even sure that will be easy to handle or possible. I see no fun here :)
for a bounce effect, final value at 50% should be good enough:
p span {
display: inline-block;
transition: 1s;
}
p:hover span {
animation: 2s moveOver infinite;
}
#keyframes moveOver {
50% {
transform: translateX(100px);
}
<p><span>span</span>
</p>

I made a pen based on this post and the css-tricks article here codepen
HTML
<h2>Single keyframe-track burger collection</h2>
<p>(each span uses only one track to play for- and backwards)</p>
<div class="wrapper">
<div class="cell">
<h3>Default</h3>
<div>
<button class="burger">
<span class="burger__bar"></span>
<span class="burger__bar"></span>
<span class="burger__bar"></span>
</button>
</div>
</div>
<div class="cell">
<h3>Merge</h3>
<div>
<button class="burger burger--merge">
<span class="burger__bar"></span>
<span class="burger__bar"></span>
<span class="burger__bar"></span>
</button>
</div>
</div>
<div class="cell">
<h3>Rotate</h3>
<div>
<button class="burger burger--rotate">
<span class="burger__bar"></span>
<span class="burger__bar"></span>
<span class="burger__bar"></span>
</button>
</div>
</div>
<div class="cell">
<h3>Spin</h3>
<div>
<button class="burger burger--spin">
<span class="burger__bar"></span>
<span class="burger__bar"></span>
<span class="burger__bar"></span>
</button>
</div>
</div>
</div>
CSS
body {
position: relative;
padding: 0;
margin: 0;
width: 100%;
height: 100vh;
background: radial-gradient(#5E802B, #2F4016);
font-family: sans-serif;
text-align: center;
h2,
h3,
p {
color: rgb(255, 255, 255);
}
}
.wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
}
.cell {
flex-grow: 1;
flex-basis: 50%;
margin: 0 20px;
display: flex;
flex-direction: column;
div {
margin-top: auto;
}
}
/****************
* Burger Styles *
*****************/
.burger {
position: relative;
width: 60px;
height: 60px;
padding: 0;
border: none;
background-color: transparent;
&__bar {
height: 10%;
border-radius: 2px;
width: 80%;
background-color: white;
display: block;
position: absolute;
left: 50%;
animation-timing-function: ease-in-out;
animation-play-state: paused;
animation-duration: .4s;
animation-fill-mode: both;
&:nth-child(1) {
top: 25%;
transform: translate(-50%, 0%);
}
&:nth-child(2) {
top: 50%;
transform: translate(-50%, -50%);
}
&:nth-child(3) {
bottom: 25%;
transform: translate(-50%, 0%);
}
}
&.close .burger__bar {
animation-direction: reverse;
}
&.open .burger__bar {
animation-direction: normal;
}
// default
&.animate .burger__bar {
animation-play-state: running;
&:nth-child(1) {
animation-name: default-top;
}
&:nth-child(2) {
animation-name: default-middle;
}
&:nth-child(3) {
animation-name: default-bottom;
}
}
&--merge.animate .burger__bar {
animation-duration: .6s;
animation-timing-function: ease;
&:nth-child(1) {
animation-name: merge-top;
}
&:nth-child(2) {
animation-name: merge-middle;
}
&:nth-child(3) {
animation-name: merge-bottom;
}
}
&--rotate.animate .burger__bar {
&:nth-child(1) {
animation-name: rotate-top;
}
&:nth-child(2) {
animation-name: rotate-middle;
}
&:nth-child(3) {
animation-name: rotate-bottom;
}
}
&--spin.animate .burger__bar {
animation-duration: 1s;
animation-timing-function: ease;
&:nth-child(1) {
animation-name: spin-top;
}
&:nth-child(2) {
animation-name: spin-middle;
}
&:nth-child(3) {
animation-name: spin-bottom;
}
}
}
/*__________________
DEFAULT
____________________*/
#keyframes default-top {
50% {
top:50%;
transform: translate(-50%, -50%) rotate(0);
}
100% {
top:50%;
transform: translate(-50%, -50%) rotate(-45deg);
}
}
#keyframes default-middle {
50%, 100% {visibility:hidden;}
}
#keyframes default-bottom {
0% {}
25% {}
50% {
bottom:50%;
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
bottom:50%;
transform: translate(-50%, 50%) rotate(45deg);
}
}
/*__________________
MERGE
____________________*/
#keyframes merge-top {
20% {
top:50%;
transform: translate(-50%, -50%) rotate(0) scale(1, 1);
//width: 100%;
}
50% {
transform: translate(-50%, -50%) rotate(0) scale(0.2, 1);
//width: 20%;
}
60% {
transform: translate(-50%, -50%) rotate(-45deg) scale(0.2, 1);
//width: 20%;
}
100% {
top:50%;
transform: translate(-50%, -50%) rotate(-45deg) scale(1, 1);
//width: 100%;
}
}
#keyframes merge-middle {
50% {
transform: translate(-50%, -50%) scale(0, 1);
}
51%{visibility:hidden;}
99% {
transform: translate(-50%, -50%) scale(0, 1);
}
100% {visibility:hidden;}
}
#keyframes merge-bottom {
20% {
bottom:40%;
transform: translate(-50%, -50%) rotate(0deg) scale(1, 1);
}
50% {
transform: translate(-50%, -50%) rotate(0deg) scale(0.2, 1);
}
60% {
transform: translate(-50%, -50%) rotate(45deg) scale(0.2, 1);
}
100% {
bottom:40%;
transform: translate(-50%, -50%) rotate(45deg) scale(1, 1);
}
}
/*__________________
ROTATE
____________________*/
#keyframes rotate-top {
50% {
top:50%;
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
top:50%;
transform: translate(-50%, -50%) rotate(45deg);
}
}
#keyframes rotate-middle {
50% {transform: translate(-50%, -50%) rotate(0deg);}
100% {transform: translate(-50%, -50%) rotate(135deg);}
}
#keyframes rotate-bottom {
50% {
bottom:50%;
transform: translate(-50%, 50%) rotate(0deg);
}
100% {
bottom:50%;
transform: translate(-50%, 50%) rotate(45deg);
}
}
/*__________________
SPIN
____________________*/
#keyframes spin-top {
50% {
top:50%;
transform: translate(-50%, -50%) rotate(0deg);
}
75% {
transform: translate(-50%, -50%) rotate(360deg);
}
100% {
top:50%;
transform: translate(-50%, -50%) rotate(315deg);
}
}
#keyframes spin-middle {
50% {visibility:hidden;}
100% {visibility:hidden;}
}
#keyframes spin-bottom {
50% {
bottom:50%;
transform: translate(-50%, 50%) rotate(0deg);
}
75% {
transform: translate(-50%, 50%) rotate(450deg);
}
100% {
bottom:50%;
transform: translate(-50%, 50%) rotate(405deg);
}
}
Javascript
burgers = document.querySelectorAll('.burger');
for (let i = 0; i < burgers.length; i++) {
burgers[i].addEventListener("click", function(){
this.classList.remove("animate");
var bars = this.querySelectorAll('.burger__bar');
for (let i = 0; i < bars.length; i++) {
// Reset span animations - https://css-tricks.com/restart-css-animation/
void bars[i].offsetWidth;
}
if (this.classList.contains("open")){
this.classList.remove("open");
this.classList.add("close");
} else {
this.classList.remove("close");
this.classList.add("open");
}
this.classList.add("animate");
});
};

Related

Infinite animation of an object flying a path using CSS3

Good day, there was the task to make the animation of an airplane flying around a path. I decided to take advantage of the opportunities in CSS3. But all I have achieved is one animation cycle. The plane flies one circle around the path and the animation stops. I tried using animation-iteration-count with infinite, but all I got was the flight of a plane in chaotic directions. Below is my code, please tell me how to loop this animation so that the plane constantly flies in a circle without stopping.
Code
.wrap {
margin: 100px;
}
.route {
height: 200px;
width: 400px;
border: 3px dotted #000;
position: relative;
}
.plane {
position: absolute;
bottom: -13px;
left: 100%;
animation-iteration-count: 3;
animation: flyLeft 1.5s linear forwards, rotatePlane 0.5s linear 1.5s forwards, flyUp 1s linear forwards 2s, RotateRight 0.5s linear 2.8s forwards, MoveRight 3s linear forwards 3s, RotateDown 1s linear 6s forwards, flyDown 1s linear forwards 7s, RotateLeft 1s linear 7.8s forwards;
}
#keyframes flyLeft {
100% {
left: -14px;
}
}
#keyframes rotatePlane {
100% {
transform: rotateZ(90deg);
}
}
#keyframes flyUp {
100% {
bottom: 100%;
}
}
#keyframes RotateRight {
0% {
transform: rotateZ(90deg);
}
100% {
transform: rotateZ(180deg);
}
}
#keyframes MoveRight {
0% {
left: -14px;
}
100% {
left: 380px;
}
}
#keyframes RotateDown {
0% {
transform: rotateZ(180deg);
}
100% {
transform: rotateZ(270deg);
}
}
#keyframes flyDown {
0% {
bottom: 100%;
}
100% {
bottom: -8%;
}
}
#keyframes RotateLeft {
0% {
transform: rotateZ(270deg);
}
100% {
transform: rotateZ(360deg);
}
}
<div class="wrap">
<div class="route">
<img class="plane" src="http://p36099-290-14699.s290.upress.link/wp-content/uploads/2020/05/plane.png">
</div>
</div>
You need to wrap all the animations in one #keyframes CSS at-rules to easily make repetitions. Here's a working solution below that wraps all the animations in one #keyframes.
.wrap {
margin: 100px;
}
.route {
height: 200px;
width: 400px;
border: 3px dotted #000;
position: relative;
}
.plane {
position: absolute;
right: 0;
bottom: 0;
transform: translate(50%, 50%);
animation: travelRoundTheBorder 10s linear infinite;
}
#keyframes travelRoundTheBorder {
30% {
bottom: 0;
right: 100%;
transform: translate(50%, 50%);
}
32.5% {
bottom: 0;
right: 100%;
transform: translate(50%, 50%) rotate(90deg);
}
47.5% {
right: 100%;
bottom: 100%;
transform: translate(50%, 50%) rotate(90deg);
}
50% {
right: 100%;
bottom: 100%;
transform: translate(50%, 50%) rotate(180deg);
}
80% {
right: 0;
bottom: 100%;
transform: translate(50%, 50%) rotate(180deg);
}
82.5% {
right: 0;
bottom: 100%;
transform: translate(50%, 50%) rotate(270deg);
}
97.5% {
right: 0;
bottom: 0;
transform: translate(50%, 50%) rotate(270deg);
}
100% {
right: 0;
bottom: 0;
transform: translate(50%, 50%) rotate(360deg);
}
}
<div class="wrap">
<div class="route">
<img class="plane" src="http://p36099-290-14699.s290.upress.link/wp-content/uploads/2020/05/plane.png">
</div>
</div>
Splitting the movement along the path and the turns into TWO separate keyframes makes this easier.
The math of the percentages is based on a square but with a rectangle the percentages change.
CSS variable could help here to work out those percentages but I haven't gone deeper into that for the demo purposes.
.wrap {
margin: 10px;
}
.route {
height: 150px;
width: 150px;
margin: auto;
border: 3px dotted #000;
position: relative;
}
.plane {
position: absolute;
transform: translate(-50%, -50%) rotate(180deg);
top: 0;
left: 0;
animation: path 6s linear infinite, turn 6s ease infinite;
}
#keyframes path {
0%,
100% {
left: 0;
top: 0;
}
25% {
left: 100%;
top: 0;
}
50% {
left: 100%;
top: 100%;
}
75% {
left: 0;
top: 100%;
}
}
#keyframes turn {
0%,
24% {
transform: translate(-50%, -50%) rotate(180deg);
}
25%,
49% {
transform: translate(-50%, -50%) rotate(270deg);
}
50%,
74% {
transform: translate(-50%, -50%) rotate(0deg);
}
75%,
99% {
transform: translate(-50%, -50%) rotate(90deg);
}
100% {
transform: translate(-50%, -50%) rotate(90deg);
}
}
<div class="wrap">
<div class="route">
<img class="plane" src="http://p36099-290-14699.s290.upress.link/wp-content/uploads/2020/05/plane.png">
</div>
</div>
Just to begin testing new CSS posibilities, offset-path (not supported in IE, experimental in FF)
reference
#container {
width: 400px;
height: 300px;
border: dotted 5px black;
margin: 30px;
}
#motion-demo {
offset-path: path('M0 -10 H400 A 10 10 1 0 1 410 0 V300 A 10 10 1 0 1 400 310 H0 A 10 10 1 0 1 -10 300 V0');
animation: move 10s infinite linear;
width: 40px;
height: 40px;
background: cyan;
}
#keyframes move {
0% {
offset-distance: 0%;
}
100% {
offset-distance: 100%;
}
}
<div id="container">
<div id="motion-demo">A</div>
</div>

How to animate the transform of an element so that it falls from above coming towards the screen?

I have an element that should come towards the user in front of the screen but also like falling from above.
I have tried transitioning from rotateX(-90deg) to rotateX(0) and from rotateX(360deg) to rotateX(270deg), but it does not look the way I want.
Also I do not what would be a good way to search for this on Google.
Sketch
Source code
body {
margin: 0 0;
}
.my-class-here {
width: 100%;
height: 100vh;
animation-name: header-anim;
animation-duration: 5s;
width: 200px;
height: 200px;
background-color: yellow;
text-align: center;
}
#keyframes header-anim {
0% {
transform: rotateX(360deg);
}
100% {
transform: rotateX(270deg);
}
}
<div class="my-class-here">
TEST
</div>
How can I achieve this?
Thank you!
You need to correct your transform-origin and add some perspective:
body {
margin: 0 0;
}
.my-class-here {
animation: header-anim 2s;
width: 200px;
height: 200px;
background-color: yellow;
text-align: center;
transform-origin:top; /* don't forget this */
}
#keyframes header-anim {
0% {
transform: perspective(200px) rotateX(270deg);
}
100% {
transform: perspective(200px) rotateX(360deg);
}
}
<div class="my-class-here">
TEST
</div>
I believe that this is what you're looking for.
#-webkit-keyframes slide-in-fwd-tr {
0% {
-webkit-transform: translateZ(-1400px) translateY(-800px) translateX(1000px);
transform: translateZ(-1400px) translateY(-800px) translateX(1000px);
opacity: 0;
}
100% {
-webkit-transform: translateZ(0) translateY(0) translateX(0);
transform: translateZ(0) translateY(0) translateX(0);
opacity: 1;
}
}
#keyframes slide-in-fwd-tr {
0% {
-webkit-transform: translateZ(-1400px) translateY(-800px) translateX(1000px);
transform: translateZ(-1400px) translateY(-800px) translateX(1000px);
opacity: 0;
}
100% {
-webkit-transform: translateZ(0) translateY(0) translateX(0);
transform: translateZ(0) translateY(0) translateX(0);
opacity: 1;
}
}

Add two more items to animated slider

I am using a CSS3 text slider that was made for 3 lines of text. I wish to add two more lines but cannot figure out how to recalculate keyframes.
I added the additional items in CSS, but do not know how to recalculate the keyframes.
Any help is greatly appreciated!
HTML:
<p class="item-1">Text Line 1</p>
<p class="item-2">Text Line 2</p>
<p class="item-3">Text Line 3</p>
<p class="item-4">Text Line 4</p>
<p class="item-5">Text Line 5</p>
CSS:
.item-1,
.item-2,
.item-3,
.item-4,
.item-5 {
font-family: 'Suez One';
font-size: 72px;
line-height: 80px;
color: white !important;
-webkit-text-stroke-width: 1px;
-webkit-text-stroke-color: black;
text-shadow: 8px 8px 3px #000000;
position: absolute;
display: block;
width: 60%;
z-index: 1001;
-webkit-animation-duration: 20s;
animation-duration: 20s;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.item-1{
-webkit-animation-name: anim-1;
animation-name: anim-1;
}
.item-2{
-webkit-animation-name: anim-2;
animation-name: anim-2;
}
.item-3{
-webkit-animation-name: anim-3;
animation-name: anim-3;
}
.item-4{
-webkit-animation-name: anim-4;
animation-name: anim-4;
}
.item-5{
-webkit-animation-name: anim-5;
animation-name: anim-5;
}
#-webkit-keyframes anim-1 {
0%, 8.3% { left: -100%; opacity: 0; }
8.3%, 25% { left: 25%; opacity: 1; }
33.33%, 100% { left: 110%; opacity: 0; }
}
#keyframes anim-1 {
0%, 8.3% { left: -100%; opacity: 0; }
8.3%,25% { left: 25%; opacity: 1; }
33.33%, 100% { left: 110%; opacity: 0; }
}
#-webkit-keyframes anim-2 {
0%, 33.33% { left: -100%; opacity: 0; }
41.63%, 58.29% { left: 25%; opacity: 1; }
66.66%, 100% { left: 110%; opacity: 0; }
}
#keyframes anim-2 {
0%, 33.33% { left: -100%; opacity: 0; }
41.63%, 58.29% { left: 25%; opacity: 1; }
66.66%, 100% { left: 110%; opacity: 0; }
}
#-webkit-keyframes anim-3 {
0%, 66.66% { left: -100%; opacity: 0; }
74.96%, 91.62% { left: 25%; opacity: 1; }
100% { left: 110%; opacity: 0; }
}
#keyframes anim-3 {
0%, 66.66% { left: -100%; opacity: 0; }
74.96%, 91.62% { left: 25%; opacity: 1; }
100% { left: 110%; opacity: 0; }
}
#-webkit-keyframes anim-4 {
0%, 66.66% { left: -100%; opacity: 0; }
74.96%, 91.62% { left: 25%; opacity: 1; }
100% { left: 110%; opacity: 0; }
}
#keyframes anim-4 {
0%, 66.66% { left: -100%; opacity: 0; }
74.96%, 91.62% { left: 25%; opacity: 1; }
100% { left: 110%; opacity: 0; }
}
#-webkit-keyframes anim-5 {
0%, 66.66% { left: -100%; opacity: 0; }
74.96%, 91.62% { left: 25%; opacity: 1; }
100% { left: 110%; opacity: 0; }
}
#keyframes anim-5 {
0%, 66.66% { left: -100%; opacity: 0; }
74.96%, 91.62% { left: 25%; opacity: 1; }
100% { left: 110%; opacity: 0; }
}
When posting this question I got an error message "It looks like your post is mostly code, please add more details" That's why I am typing this. Trying to have some more words so it will let me post this question. Thanks for your patience.
Here's a script that writes the animation on the fly, based on number of slides:
'use strict';
var slider = document.querySelector('.css-slider'),
slides = slider.querySelectorAll('p'),
css = '';
for (var i = 0; i < slides.length; i++) {
css += '.css-slider>*:nth-child(' + (i + 1) + '){animation-name:a-' + i + '}' + ('#keyframes a-' + i + '{') + ('0%,' + i * 100 / slides.length + '%{transform: translatex(-100%)}') + (i * 100 / slides.length + 25 / slides.length + '%,' + ((i + 1) * 100 / slides.length - 25 / slides.length) + '%{transform: translatex(0)}') + ((i + 1) * 100 / slides.length + '%,100%{transform: translatex(100%)}') + '}';
}
css += '.css-slider>*{animation-duration:' + slides.length * 4 + 's;';
var head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
#import url('https://fonts.googleapis.com/css?family=Suez+One');
.css-slider > * {
font-family: 'Suez One';
font-size: 72px;
line-height: 55px;
color: white;
text-shadow: 5px 5px 3px rgba(0,0,0,.65);
position: absolute;
top: 0;
width: 100%;
text-align: center;
animation-timing-function: cubic-bezier(.4,0,.2,1);
animation-iteration-count: infinite;
}
.css-slider, .css-slider > *:last-child {
position: relative;
}
.css-slider {
display: flex;
align-items: center;
justify-content: center;
}
body {
margin: 0;
overflow-x: hidden;
}
<div class="css-slider">
<p>Text Line 1</p>
<p>Text Line 2</p>
<p>Text Line 3</p>
<p>Text Line 4</p>
<p>Text Line 5</p>
<p>Text Line 6</p>
<p>Text Line 7</p>
</div>
Note I changed your initial markup, as I wanted it to write a more general solution, not one tailored to your particular case.
But if you're only interested in the CSS for 5 items and you want to keep your markup here's what you're asking for:
.item-1 { -webkit-animation-name: a-0; animation-name: a-0 }
.item-2 { -webkit-animation-name: a-1; animation-name: a-1 }
.item-3 { -webkit-animation-name: a-2; animation-name: a-2 }
.item-4 { -webkit-animation-name: a-3; animation-name: a-3 }
.item-5 { -webkit-animation-name: a-4; animation-name: a-4 }
#-webkit-keyframes a-0 {
0% { -webkit-transform: translatex(-100%); transform: translatex(-100%) }
5%, 15% { -webkit-transform: translatex(0); transform: translatex(0) }
20%, 100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#keyframes a-0 {
0% { -webkit-transform: translatex(-100%); transform: translatex(-100%) }
5%, 15% { -webkit-transform: translatex(0); transform: translatex(0) }
20%, 100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#-webkit-keyframes a-1 {
0%, 20% { -webkit-transform: translatex(-100%); transform: translatex(-100%)}
25%, 35% { -webkit-transform: translatex(0); transform: translatex(0) }
40%, 100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#keyframes a-1 {
0%, 20% { -webkit-transform: translatex(-100%); transform: translatex(-100%)}
25%, 35% { -webkit-transform: translatex(0); transform: translatex(0) }
40%, 100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#-webkit-keyframes a-2 {
0%, 40% { -webkit-transform: translatex(-100%); transform: translatex(-100%) }
45%, 55% { -webkit-transform: translatex(0); transform: translatex(0) }
60%, 100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#keyframes a-2 {
0%, 40% { -webkit-transform: translatex(-100%); transform: translatex(-100%) }
45%, 55% { -webkit-transform: translatex(0); transform: translatex(0) }
60%, 100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#-webkit-keyframes a-3 {
0%, 60% { -webkit-transform: translatex(-100%); transform: translatex(-100%) }
65%, 75% { -webkit-transform: translatex(0); transform: translatex(0) }
80%, 100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#keyframes a-3 {
0%, 60% { -webkit-transform: translatex(-100%); transform: translatex(-100%) }
65%, 75% { -webkit-transform: translatex(0); transform: translatex(0) }
80%, 100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#-webkit-keyframes a-4 {
0%, 80% { -webkit-transform: translatex(-100%); transform: translatex(-100%) }
85%, 95% { -webkit-transform: translatex(0); transform: translatex(0) }
100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
#keyframes a-4 {
0%, 80% { -webkit-transform: translatex(-100%); transform: translatex(-100%) }
85%, 95% { -webkit-transform: translatex(0); transform: translatex(0) }
100% { -webkit-transform: translatex(100%); transform: translatex(100%) }
}
And the principle behind the keyframes is:
.item-${n+1} { animation-name: a-${n} }
#keyframes a-${n} {
0%, enterStart { left state ruleset }
enterEnd, leaveStart { center state ruleset }
leaveEnd, 100% { right state ruleset }
}

Revert animation on exit

I am making a menu that should have animated "hamburger" icon inside. At first, I used transform and it looked nice, but I decided to add some fancier animation ;-)
They loook like this:
#keyframes animateFirstBar {
0% {
transform: translate(-50%, -200%);
}
50% {
transform: translate(-50%, 0);
}
100% {
transform: translateX(-50%) rotate(-45deg);
}
}
#keyframes animateSecoundBar {
0%, 50% {
transform: translate(-50%, 0);
}
51%, 100% {
transform: translate(-50%, 0) scaleX(.01);
}
}
#keyframes animateThirdBar {
0% {
transform: translate(-50%, 200%);
}
50% {
transform: translate(-50%, 0);
}
100% {
transform: translateX(-50%) rotate(45deg);
}
}
And they are used like this:
.main-menu {
$mainMenu: &;
position: fixed;
width: 300px;
height: 100%;
top: 0;
left: 0;
background: #ccc;
transform: translateX(-100%);
transition: $time transform ease-in;
&--active {
transform: none;
#{$mainMenu}__toggle {
transform: none;
background: rgba(0, 0, 0, 0);
}
#{$mainMenu}__toggle-line {
&:nth-of-type(1) {
animation: $time animateFirstBar forwards;
}
&:nth-of-type(2) {
animation: $time animateSecoundBar forwards;
}
&:nth-of-type(3) {
animation: $time animateThirdBar forwards;
}
}
}
&__toggle {
width: $width;
height: $width - 1;
position: absolute;
right: 0;
transform: translateX(100%);
top: 0;
background: yellow;
border: 0;
outline: 0;
transition: $time transform ease-in, $time background linear;
transform-origin: bottom right;
}
&__toggle-line {
width: 60%;
height: $lineHeight;
display: block;
background: black;
position: absolute;
left: 50%;
transition: $time transform ease-in;
top: (50% - ($lineHeight/2));
&:nth-of-type(1) {
animation: none;
transform: translate(-50%, -200%);
}
&:nth-of-type(2) {
animation: none;
transform: translate(-50%, 0);
}
&:nth-of-type(3) {
animation: none;
transform: translate(-50%, 200%);
}
}
}
You can see the example here: http://codepen.io/tomekbuszewski/pen/jrzKKR?editors=0100
My problem is, I don't know how to revert the animation on "exit" (on removing the --active modificator). I don't want to write another animations or add another class that will be removed over time with JS.
Previously I have already implemented this hamburger button with transition and transform and I think it is satisfied what you want to archive. I haven't done it with your approach using animation. But please take a look at this snippet to see the idea.
function toggleMenu(x) {
x.classList.toggle("change");
}
/*
Orginal article - https://github.com/trungk18/Animated-Navigation-Menu-Icons-with-CSS3
*/
/*Menu container*/
.content {
max-width: 40em;
margin: 1em auto;
}
.icon-container {
float: left;
position: relative;
cursor: pointer;
margin: 0 5em 5em;
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
transition: all 0.3s;
}
.bar {
display: block;
width: 35px;
height: 5px;
background-color: #333;
margin: 6px auto;
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
transition: all 0.3s;
border-radius: 3px;
}
.change {
/*Rotate first bar*/
/*Fade out the second bar-*/
/*Reduce width the second bar-*/
/*Rotate last bar*/
}
.change.icon-5 {
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
.change .bar-10 {
-webkit-transform: rotate(45deg) translate(8px, -3px) scaleX(0.7);
-moz-transform: rotate(45deg) translate(8px, -3px) scaleX(0.7);
-ms-transform: rotate(45deg) translate(8px, -3px) scaleX(0.7);
-o-transform: rotate(45deg) translate(8px, -3px) scaleX(0.7);
transform: rotate(45deg) translate(8px, -3px) scaleX(0.7);
}
.change .bar-12 {
-webkit-transform: rotate(-45deg) translate(8px, 3px) scaleX(0.7);
-moz-transform: rotate(-45deg) translate(8px, 3px) scaleX(0.7);
-ms-transform: rotate(-45deg) translate(8px, 3px) scaleX(0.7);
-o-transform: rotate(-45deg) translate(8px, 3px) scaleX(0.7);
transform: rotate(-45deg) translate(8px, 3px) scaleX(0.7);
}
<section class="content">
<div class="icon-container icon-5" onclick="toggleMenu(this)">
<span class="bar bar-10"></span>
<span class="bar bar-11"></span>
<span class="bar bar-12"></span>
</div>
</section>
<!--Full pen: http://codepen.io/trungk18/pen/jrrXjz-->
I've managed to solve the problem. I had to add another class, trigger it with JS and write another set of animations that flowed in reverse.
Animations:
#keyframes animateFirstBar {
0% { transform: translate(-50%, $spacing * -100%); }
60% { transform: translate(-50%, 0); }
100% { transform: translateX(-50%) rotate(-#{$rotation}deg); }
}
#keyframes revertFirstBar {
100% { transform: translate(-50%, $spacing * -100%); }
60% { transform: translate(-50%, 0); }
0% { transform: translateX(-50%) rotate(-#{$rotation}deg); }
}
#keyframes animateSecoundBar {
0%, 60% { transform: translate(-50%, 0); }
61%, 100% { transform: translate(-50%, 0) scaleX(.01); }
}
#keyframes revertSecoundBar {
0%, 60% { transform: translate(-50%, 0) scaleX(.01); }
61%, 100% { transform: translate(-50%, 0); }
}
#keyframes animateThirdBar {
0% { transform: translate(-50%, $spacing * 100%); }
60% { transform: translate(-50%, 0); }
100% { transform: translateX(-50%) rotate(#{$rotation}deg); }
}
#keyframes revertThirdBar {
0% { transform: translateX(-50%) rotate(#{$rotation}deg); }
60% { transform: translate(-50%, 0); }
100% { transform: translate(-50%, $spacing * 100%); }
}
revert*Bar are going with one class, animate*Bar with another.

CSS3 spinner, preloader

I would like to build a animated spinner with CSS3.
It should behave like this :
After the last state it should start again like in the first state.
I managed to create circles using the technique explained here : stackoverflow question
Now, how can I animate the spinner between the described states? I do not know how to animate the clip-rect property. I also guess that it would behave better with a clip-poly instead (a triangle maybe) but I can't animate that either.
CSS3 spinner
This CSS preloader uses keyframe animations and transform-rotate CSS3 properties to make the circle and the filling color.
This spinner is responsive.
.sp1 {
margin: 50px auto;
position: relative;
width: 30%;
padding-bottom: 30%;
overflow: hidden;
background-color: #557733;
border-radius: 50%;
z-index: 1;
}
.sp:before,
.sp:after {
content: '';
position: absolute;
height: 100%;
width: 50%;
background-color: #99FF33;
}
.sp1:after {
width: 80%;
height: 80%;
margin: 10%;
border-radius: 50%;
background-color: #fff;
z-index: 6;
}
.sp1:before {
background-color: inherit;
z-index: 5;
}
.sp2:before {
z-index: 4;
-webkit-animation: spin1 3s linear infinite;
animation: spin1 3s linear infinite;
-webkit-transform-origin: 100% 50%;
transform-origin: 100% 50%;
}
.sp2:after {
opacity: 0;
right: 0;
z-index: 6;
-webkit-animation: spin2 3s linear infinite;
animation: spin2 3s linear infinite;
-webkit-transform-origin: 0 50%;
transform-origin: 0 50%;
}
#-webkit-keyframes spin1 {
0% { -webkit-transform: rotate(0deg); }
50%, 100% { -webkit-transform: rotate(180deg); }
}
#keyframes spin1 {
0% { transform: rotate(0deg); }
50%, 100% { transform: rotate(180deg); }
}
#-webkit-keyframes spin2 {
0% { -webkit-transform: rotate(0deg); opacity: 0; }
49.99% { opacity: 0; }
50% { -webkit-transform: rotate(0deg); opacity: 1; }
100% { -webkit-transform: rotate(180deg); opacity: 1;
}
}
#keyframes spin2 {
0% { transform: rotate(0deg); opacity: 0; }
49.99% { opacity: 0; }
50% { transform: rotate(0deg); opacity: 1; }
100% { transform: rotate(180deg); opacity: 1; }
}
<div class="sp sp1">
<div class="sp sp2"></div>
</div>
Fiddle demo

Resources