CSS Animation Fill Mode - What have I done wrong? - javascript

I need to create a rotation animation. A click event spins an element 180° to point down. Another click event spins the same element back to 0° to point up.
I have animation-fill-mode to set to forwards to preserve the last keyframe state. But it does not appear to be working. All visual elements reset to the default state.
Any ideas what I may be doing wrong?
My Codepen: http://codepen.io/simspace-dev/pen/RrpGmP
My code:
(function() {
$('#btnb').on('click', function(e) {
return $('.box').addClass('spin-counter-clockwise');
});
$('#btnf').on('click', function(e) {
return $('.box').addClass('spin-clockwise');
});
$('.box').on('webkitAnimationEnd', function(e) {
return $(e.target).removeClass('spin-counter-clockwise').removeClass('spin-clockwise');
});
}.call(this));
.box {
background: red;
position: relative;
width: 176px;
height: 176px;
margin: 40px auto;
text-align: center;
}
.box .top {
background: green;
position: absolute;
top: 0;
width: 100%;
height: 28px;
}
.box .bottom {
background: purple;
position: absolute;
bottom: 0;
width: 100%;
height: 28px;
}
.box .caret {
color: white;
font-size: 88px;
position: absolute;
top: 42px;
left: 50px;
}
.spin-clockwise {
-moz-animation: spin 2s;
-webkit-animation: spin 2s;
-moz-animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
.spin-counter-clockwise {
-moz-animation: spin 2s reverse;
-webkit-animation: spin 2s reverse;
-moz-animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
#keyframes spin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
}
body {
text-align: center;
margin: 0 auto;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Keyframes are not supported in IE9 and earlier</h2>
<div class="box">
<div class="top">top</div>
<div class="caret"><i class="fa fa-caret-square-o-up"></i>
</div>
<div class="bottom">bottom</div>
</div>
<p>
<button id="btnf">SPIN CLOCKWISE</button>
</p>
<p>
<button id="btnb">SPIN COUTNER CLOCKWISE</button>
</p>

TL;DR: (straight to the suggested solution)
If all you need is a rotation from 0° to 180° on the click of one button and back from 180° to 0° on the other then I would suggest using transitions instead of animations. Transitions by default produce the reverse effect and so there is no need to code for two different states (which makes it even better).
(function() {
$('#btnb').on('click', function(e) {
return $('.box').removeClass('spin');
});
$('#btnf').on('click', function(e) {
return $('.box').addClass('spin');
});
}.call(this));
.box {
background: red;
position: relative;
width: 176px;
height: 176px;
margin: 40px auto;
text-align: center;
transition: transform 1s linear;
/* add this to enable transition */
}
.box .top {
background: green;
position: absolute;
top: 0;
width: 100%;
height: 28px;
}
.box .bottom {
background: purple;
position: absolute;
bottom: 0;
width: 100%;
height: 28px;
}
.box .caret {
color: white;
font-size: 88px;
position: absolute;
top: 42px;
left: 50px;
}
.spin {
/* this is the only thing required for rotation (along with the JS) */
transform: rotate(180deg);
}
body {
text-align: center;
margin: 0 auto;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Keyframes are not supported in IE9 and earlier</h2>
<div class="box">
<div class="top">top</div>
<div class="caret"><i class="fa fa-caret-square-o-up"></i>
</div>
<div class="bottom">bottom</div>
</div>
<p>
<button id="btnf">SPIN CLOCKWISE</button>
</p>
<p>
<button id="btnb">SPIN COUTNER CLOCKWISE</button>
</p>
If you were using animations only for learning purpose, the details provided below should still be useful to you in terms of understanding how animations work, what are the limitations because of it etc.
Chris' answer touches upon the reason for your problem but I thought the question merited a bit more detailed explanation of two things - (1) Why the element doesn't hold the state as at the last keyframe even though animation-fill-mode: forwards setting is applied (2) Why the same keyframe couldn't be used for the reverse animation (when the class with the original animation was not removed). I also wanted to suggest a different alternate to the whole thing and hence the separate answer.
Why does the element not hold the state as at the last keyframe even though fill mode is set to forwards?
This is because you are removing the class that adds the animation as soon as animation completes (inside the on('webkitAnimationEnd') event handler). Generally when animation-fill-mode is set to forwards, the UA uses the settings (or property-value pair) that are provided within last keyframe to maintain the state. But once the class is removed (and in-turn the animation settings), the UA does not keep track of (or know what) animations that were prior present on the element, their state and fill mode etc. Once animation is removed, the browser triggers a repaint and this will be performed based on classes that are present on the element as at the time of the repaint. Due to this, the element would snap back to its un-rotated state. You can read more about it in my answer here to a similar question (but not the same :)).
Why can't the same keyframe be used for the reverse animation (when the class which had the original animation was not removed)?
This again is because of how animations generally work. When any animation is added to an element, the UA maintains details about the animation's keyframes, its state etc as long as it is attached to the element. So, unless the class which added the forward (0° to 180°) animation is removed, the browser thinks that it has executed the animation to completion (as default iteration count is just 1) and so even when a class with the reverse animation is added, it does nothing. The only way to make it restart the animation in reverse direction is by removing the class with the forward animation and then adding the class with the reverse animation. You can have a look at this answer also for related reading.
Because of the aforementioned reasons, the only way to achieve what you need with animations is to create two different animations (or keyframes) for the forward and reverse animations, set them under two different classes and keep changing the classes using JavaScript. This whole process becomes tedious and is generally not necessary when all you need is a rotation from (0° to 180°) on the click of one button and back from (180° to 0°) on the other. This whole thing can be achieved using transitions and what makes this even better is the fact that transitions by default produce the reverse effect and so there is no need to code for two different states.
Further Reading:
What are the differences between Transitions and Animations
Choosing Transitions or Animations - When to use which?
If the need is to have continuous clockwise or counter-clockwise rotations with each button click (like in oMiKeY's answer) then I'd still recommend using transition with a bit of JS like in the below snippet. Let's leave animations for more complex stuff (and in specific stuff that'd happen without any triggers).
(function() {
var deg = 0;
$('#btnb').on('click', function(e) {
deg -= 180;
return $('.box').css('transform', 'rotate(' + deg + 'deg)');
});
$('#btnf').on('click', function(e) {
deg += 180;
return $('.box').css('transform', 'rotate(' + deg + 'deg)');
});
}.call(this));
.box {
background: red;
position: relative;
width: 176px;
height: 176px;
margin: 40px auto;
text-align: center;
transition: transform 1s linear; /* add this to enable transition */
}
.box .top {
background: green;
position: absolute;
top: 0;
width: 100%;
height: 28px;
}
.box .bottom {
background: purple;
position: absolute;
bottom: 0;
width: 100%;
height: 28px;
}
.box .caret {
color: white;
font-size: 88px;
position: absolute;
top: 42px;
left: 50px;
}
body {
text-align: center;
margin: 0 auto;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Keyframes are not supported in IE9 and earlier</h2>
<div class="box">
<div class="top">top</div>
<div class="caret"><i class="fa fa-caret-square-o-up"></i>
</div>
<div class="bottom">bottom</div>
</div>
<p>
<button id="btnf">SPIN CLOCKWISE</button>
</p>
<p>
<button id="btnb">SPIN COUTNER CLOCKWISE</button>
</p>

So the root issue was the class with the animation was being removed.
I couldn't get it to work using the same keyframes, but what i did was create a new keyframes for counter clockwise, and then removed the opposite class when the buttons were clicked
Changes:
css
.spin-clockwise {
-moz-animation: spin 2s;
-webkit-animation: spin 2s;
}
.spin-fill-mode {
-moz-animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
.spin-counter-clockwise {
-moz-animation: spin-counter 2s;
-webkit-animation: spin-counter 2s;
}
#keyframes spin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
}
#keyframes spin-counter {
from {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
to {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
}
js:
$('#btnb').on('click', (e)->
$('.box')
.addClass('spin-counter-clockwise')
.removeClass('spin-clockwise')
)
$('#btnf').on('click', (e) ->
$('.box')
.addClass('spin-clockwise')
.removeClass('spin-counter-clockwise')
)
And add the class spin-fill-mode to box. Though you could probably just leave the fill-mode in the animation classes...
updated codepen:
http://codepen.io/anon/pen/QypvOr

I fiddled with it for a while then decided you might need two separate rotation animations.
Check out my fiddle: http://codepen.io/anon/pen/jWBmZK
(function() {
$('#btnb').on('click', function(e) {
return $('.box')
.addClass('spin-counter-clockwise')
.toggleClass('upside-down');
});
$('#btnf').on('click', function(e) {
return $('.box')
.addClass('spin-clockwise')
.toggleClass('upside-down');
});
$('.box').on('webkitAnimationEnd', function(e) {
return $(e.target).removeClass('spin-counter-clockwise').removeClass('spin-clockwise');
});
}.call(this));
.box {
background: red;
position: relative;
width: 176px;
height: 176px;
margin: 40px auto;
text-align: center;
}
.box .top {
background: green;
position: absolute;
top: 0;
width: 100%;
height: 28px;
}
.box .bottom {
background: purple;
position: absolute;
bottom: 0;
width: 100%;
height: 28px;
}
.box .caret {
color: white;
font-size: 88px;
position: absolute;
top: 42px;
left: 50px;
}
.upside-down {
-moz-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
.spin-clockwise.upside-down {
-moz-animation: spin 2s;
-webkit-animation: spin 2s;
-moz-animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
.spin-counter-clockwise {
-moz-animation: spin 2s reverse;
-webkit-animation: spin 2s reverse;
-moz-animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
.spin-clockwise {
-moz-animation: back-spin 2s;
-webkit-animation: back-spin 2s;
-moz-animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
.spin-counter-clockwise.upside-down {
-moz-animation: back-spin 2s reverse;
-webkit-animation: back-spin 2s reverse;
-moz-animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
#keyframes spin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
}
#keyframes back-spin {
from {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
body {
text-align: center;
margin: 0 auto;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<body>
<h2>Keyframes are not supported in IE9 and earlier</h2>
<div class="box">
<div class="top">top</div>
<div class="caret"><i class="fa fa-caret-square-o-up"></i>
</div>
<div class="bottom">bottom</div>
</div>
<p>
<button id="btnf">SPIN CLOCKWISE</button>
</p>
<p>
<button id="btnb">SPIN COUTNER CLOCKWISE</button>
</p>
</body>
</html>

Related

Is there a way to make an element spin around without a variable telling how far it has already turned?

I have an experimental website that plays music, and I want the forward and backward buttons to spin when you click them. But, I also don't want to have 2 variables to be how far they have turned, or a function to get how far they have turned from the CSS transform property. They have a transition, for hover effects. I have tried
backward.classList.add("notrans");
backward.style.transform = "rotateZ(0deg)";
backward.classList.remove("notrans");
backward.style.transform = "rotateZ(-360deg)";
and some closely related things, and also have a setTimeout to reset it afterwards, which it too long for a post.
Animate is what you are searching for.
This should be a working example: (Tested in FF and Chrome)
/* THIS IS A JAVASCRIPT CLASS THAT ADDS AND
REMOVES THE CSS CLASS FROM YOUR ELEMENT
USING THE ELEMENT'S ID VALUE TO REFERENCE. */
function startStop(strstp) {
var infinite = document.getElementById("imSpinning");
var once = document.getElementById("imSpinningOnce");
if(strstp == 1)
{
infinite.classList.add("spin");
once.classList.add("spinOnce");
timer = setTimeout(function() {
once.classList.remove("spinOnce");
},1000);
}
else
{
infinite.classList.remove("spin");
once.classList.remove("spinOnce");
}
}
/* THIS IS THE CSS CLASS THAT CREATES INFINITE ROTATION */
.spin {
-webkit-animation:spin 1s linear infinite;
-moz-animation:spin 1s linear infinite;
animation:spin 1s linear infinite;
}
#-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
#-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
#keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
/* THIS IS THE CSS CLASS THAT ROTATES ONCE */
.spinOnce {
-webkit-animation:spin 1s linear;
-moz-animation:spin 1s linear;
animation:spin 1s linear;
}
#-moz-keyframes spinOnce { 100% { -moz-transform: rotate(360deg); } }
#-webkit-keyframes spinOnce { 100% { -webkit-transform: rotate(360deg); } }
#keyframes spinOnce { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
<div style="width: 100px; height: 30px; background-color: green; color: white; margin: 20px; text-align: center; cursor: pointer;" onclick="startStop(1)">
GO
</div>
<div style="width: 100px; height: 30px; background-color: red; color: white; margin: 20px; text-align: center; cursor: pointer;" onclick="startStop(0)">
STOP
</div>
<!-- ELEMENT TO ROTATE INFINITLY WITH "spin" CLASS -->
<div id="imSpinning" class="spin" style="position: absolute; top: 10px; right: 30px; height: 140px; width: 140px; background-image: url(https://icons.iconarchive.com/icons/thehoth/seo/256/seo-web-code-icon.png); background-size: 100% 100%; background-position: center center; border-radius: 50%; overflow: hidden;"></div>
<!-- ELEMENT TO ROTATE ONCE WITH "spin" CLASS -->
<div id="imSpinningOnce" class="spinOnce" style="position: absolute; top: 10px; right: 200px; height: 140px; width: 140px; background-image: url(https://icons.iconarchive.com/icons/thehoth/seo/256/seo-web-code-icon.png); background-size: 100% 100%; background-position: center center; border-radius: 50%; overflow: hidden;"></div>
Simply copy the CSS class above to the style section/sheet of your page and modify it as needed. Ensure you reference the class in your html element.
Also I edited in a small JavaScript class that add/removes the spin class from the DIV element if it helps you in starting and stopping the animation.
Hope this helps, and best of luck!

CSS rolling ball animation position

General info
I'm working on a Bingo game. Currently I'm trying to create a CSS rolling ball animation. The idea is to simulate a ball dropping from the wheel and making it roll from right to left.
The problem
The animation is working fine. But the "drop in" position is relative to the div. As a consequence of this, this position keeps moving right 75 pixels on each new ball dropping in.
Solutions I've tried
- Give the balls an absolute position. This solves the issue, but each ball will cover the previous balls due to the keyframe ending at left: 0%. This is not desirable.
- Lookup Javascript solutions to see if I can somehow change the keyframe to end with +75px on the previous ball. Unfortunately it seems impossible to manipulate animations this way, or I was unable to find a way to do it.
So now I'm hoping someone is able to help me find a solution to this problem.
Edit: I didn't tag jQuery because it's not used here, but solutions using jQuery are perfectly fine.
MCVE
const timer = setInterval(rollBall, 2000);
var ballNumber = 1;
function rollBall(){
if(document.getElementById('ball-'+(ballNumber-1))){
document.getElementById('ball-'+(ballNumber-1)).classList.remove('ball-animation');
}
let html = '<div id="ball-'+ballNumber+'" class="ball ball-animation">';
html += '<p class="ball-number">';
html += ballNumber;
html += '</p></div>';
document.getElementById('balls').innerHTML += html;
ballNumber++;
if(ballNumber > 10) {
clearInterval(timer);
document.getElementById('ball-'+(ballNumber-1)).classList.remove('ball-animation');
}
}
.ball {
display: block;
position: relative;
width: 75px;
height: 75px;
background: red;
border-radius: 50%;
background: -webkit-radial-gradient(25px 25px, circle, red, #000);
background: -moz-radial-gradient(25px 25px, circle, red, #000);
background: radial-gradient(25px 25px, circle, red, #000);
/*position: absolute;*/
float: left;
}
.ball-number {
top: -34px;
left: 25px;
font-size: 45px;
color: #fff;
position: absolute;
}
.ball-animation {
-webkit-animation: spin 1750ms linear infinite, moveRightToLeft 2s linear infinite;
-moz-animation: spin 1750ms linear infinite, moveRightToLeft 2s linear infinite;
-ms-animation: spin 1750ms linear infinite, moveRightToLeft 2s linear infinite;
animation: spin 1750ms linear infinite, moveRightToLeft 2s linear;
-webkit-transition: all 1.75s ease;
transition: all 1.75s ease;
}
#keyframes spin {
from { transform: rotate(360deg); }
to { transform: rotate(0deg); }
}
#keyframes moveRightToLeft {
0% { top: -50px; left: 200px; }
10% { top: -40px; left: 180px; }
20% { top: -25px; left: 150px; }
30% { top: 0px; left: 100px; }
100% { left: 0%; }
}
<div id="balls"></div>
This is a CSS only solution, using an intermediate div, zone to handle the ball movement .
Since this elements have varying sizes, you can set the keyframes on them to work in percentages, and adjust for a different ending point, while keeping the same origin point.
.container {
width: 600px;
height: 350px;
border: solid 1px red;
position: relative;
}
.zone {
position: absolute;
top: 0px;
right: 0px;
bottom: 40px;
left: 40px;
border: solid 1px green;
animation: move 3s linear infinite;
}
.zone:nth-child(2) {
left: calc(40px * 2);
}
.zone:nth-child(3) {
left: calc(40px * 3);
}
.zone:nth-child(4) {
left: calc(40px * 4);
}
.ball {
width: 40px;
height: 40px;
border-radius: 100%;
background-color: blue;
right: 0px;
position: absolute;
}
#keyframes move {
from {transform: translate(0px, 0px);}
50% {transform: translate(-100px, 100%);}
to {transform: translate(-100%, 100%);}
}
<div class="container">
<div class="zone">
<div class="ball">1</div>
</div>
<div class="zone">
<div class="ball">2</div>
</div>
<div class="zone">
<div class="ball">3</div>
</div>
<div class="zone">
<div class="ball">4</div>
</div>
</div>

Load each progress bar from 0 to its value in multiple progress bar animation

I am trying to add animation in grouped progress bar that will load each progress bar from 0 to its value. e.g in my sample code below I want to first load red progress bar then load the green progress bar. How can I do that?
Please check the code in this jsfiddle.
html:
<div class="progress-bar-outer">
<div class="progress-bar-inner">
</div>
<div class="progress-bar-inner2">
</div>
</div>
css:
.progress-bar-outer {
width: 300px;
height: 40px;
flex: auto;
display: flex;
flex-direction: row;
border-radius: 0.5em;
overflow: hidden;
background-color: gray;
}
.progress-bar-inner {
/* You can change the `width` to change the amount of progress. */
width: 75%;
height: 100%;
background-color: red;
}
.progress-bar-inner2 {
/* You can change the `width` to change the amount of progress. */
width: 50%;
height: 100%;
background-color: green;
}
.progress-bar-outer div {
animation:loadbar 3s;
-webkit-animation:loadbar 3s;
}
#keyframes loadbar {
0% {width: 0%;left:0;right:0}
}
I would transition transform instead for better performance. Use translateX(-100%) with opacity: 0 to move them to their default, hidden position, then animate to translateX(0); opacity: 1; to put them in place. And just add an animation-delay to the green bar that matches the animation-duration
I made the bars semi-opaque to show when the animations fire.
.progress-bar-outer {
width: 300px;
height: 40px;
border-radius: 0.5em;
overflow: hidden;
background-color: gray;
display: flex;
}
.progress-bar-inner {
/* You can change the `width` to change the amount of progress. */
width: 75%;
background-color: red;
}
.progress-bar-inner2 {
/* You can change the `width` to change the amount of progress. */
width: 100%;
background-color: green;
}
.progress-bar-outer div {
transform: translateX(-100%);
animation: loadbar 3s forwards;
-webkit-animation: loadbar 3s forwards;
opacity: 0;
}
.progress-bar-outer .progress-bar-inner2 {
animation-delay: 3s;
}
#keyframes loadbar {
0% {
opacity: 1;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress -->
<div class="progress-bar-outer">
<div class="progress-bar-inner">
</div>
<div class="progress-bar-inner2">
</div>
</div>
Modified Michael Coker's answer to better reflect my interpretation of what you're asking for.
.progress-bar-outer {
width: 300px;
height: 40px;
border-radius: 0.5em;
overflow: hidden;
background-color: gray;
position: relative;
}
.progress-bar-inner {
/* You can change the `width` to change the amount of progress. */
width: 100%;
background-color: red;
z-index: 1;
}
.progress-bar-inner2 {
/* You can change the `width` to change the amount of progress. */
width: 100%;
background-color: green;
z-index: 2;
}
.progress-bar-outer div {
position: absolute;
top: 0; bottom: 0;
transform: translateX(-100%);
animation: loadbar 3s linear;
-webkit-animation: loadbar 3s linear;
opacity: 1;
}
.progress-bar-outer .progress-bar-inner2 {
animation-delay: 3s;
}
#keyframes loadbar {
100% {
transform: translateX(0);
}
}
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress -->
<div class="progress-bar-outer">
<div class="progress-bar-inner">
</div>
<div class="progress-bar-inner2">
</div>
</div>
Apply Transition to inner classes, add delays to secondary inner and use opacity to hide the element before transition begins.
.progress-bar-inner {
animation:loadbar 2s;
-webkit-animation:loadbar 2s;
}
.progress-bar-inner2 {
-webkit-animation: loadbar 2s ease 2s forwards;
animation: loadbar 2s ease 2s forwards
animation-delay: 2s;
-webkit-animation-delay: 2s;
opacity:0;
}
#keyframes loadbar {
0% { width: 0%;left:0;right:0}
1% { opacity: 1}
100% { opacity: 1}
}
See working example:
https://jsfiddle.net/dfkLexuv/10/

Create a folding animation of a simple square

I am trying to make this animation. This animation is quite complicated, but all I would like to do is fold a square in half showing the folding animation.
I have visited this website and I tried to use the skew function in order to create the animation.
This is the code I have used so far:
.elementLeft {
display: inline-block;
background-color: #aaaaaa;
height: 100px;
width: 100px;
font-size: 1px;
animation: shakeback 2s infinite;
animation-direction: alternate;
color: white;
}
.elementRight {
display: inline-block;
background-color: #aaaaaa;
height: 100px;
width: 100px;
/* transform: skew(20deg); */
font-size: 1px;
color: white;
animation: shake 2s infinite;
animation-direction: alternate;
}
#keyframes shake {
0% {
transform: skewY(0deg);
}
100% {
transform: skewY(45deg);
}
}
#keyframes shakeback {
0% {
transform: skewY(0deg);
}
100% {
transform: skewY(-45deg);
}
}
body,
html {
height: 100%;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
<div class="elementLeft"></div>
<div class="elementRight">
</div>
However, this is not exactly what I want since the skew function also makes the square too long as I increase the degree. I have been thinking of another way to create this animation, but I am not sure what to do. I also would prefer that only one side folds in rather than both sides folding. This is like in the Google Calendar Icon animation posted above where the top half of the icon stays still whereas the bottom half folds upwards.
edit: I have also noticed that I can rotate a square upwards to form this effect. However, I am still having an issue as the animation does not look as smooth as I would like.
Any help is once again appreciated!
.element {
display: inline-block;
background-color: #000000;
height: 100px;
width: 100px;
}
.elementfold {
/* transform: rotateX(0deg); */
animation: foldup 5s;
display: inline-block;
background-color: #aaaaaa;
height: 100px;
width: 100px;
}
#keyframes foldup {
0% {
transform: rotateX(0);
}
100% {
transform: rotateX(180deg) translate(0px, 100px);
}
}
<li>
<div class="element"></div>
</li>
<li>
<div class="elementfold"></div>
</li>
This may be useful. I haven't tried it myself, but I'd look into it.
http://anime-js.com/
Code:
#container {
width: 100px;
height: 100px;
perspective: 300px;
}
.square {
width: 100px;
height: 100px;
background-color: grey;
}
#animation {
animation: anim 2s linear 0s infinite alternate;
transform-origin: 50% 100%;
}
#keyframes anim {
from {transform: rotateX(0deg);}
to {transform: rotateX(-180deg);}
}
<div id="container">
<div class="square" id="animation"></div>
<div class="square"></div>
</div>
Using CSS3's rotateX property and animations, it's pretty easy to create folding squares.
Credit goes to Bálint for the animations!
The above method will need to be slightly tweaked the object is rounded. In the case that the folding animation needs to be applied to a circle or an oval, it can be done by breaking the shape into two shapes; more specifically, the circle would be broken into two semicircles.
The following code shows one solution for this using HTML and LESS (for this reason it will not load on stackoverflow):
#size: 200px;
.origin (#x;
#y) {
-webkit-transform-origin: #x #y;
-moz-transform-origin: #x #y;
-o-transform-origin: #x #y;
transform-origin: #x #y;
}
.red {
background-color: #f24235;
}
.green {
background-color: lightgreen;
}
.top-half {
width: #size;
height: (#size / 2);
border-radius: (#size / 2) (#size / 2) 0 0;
}
.bottom-half {
width: #size;
height: (#size / 2);
border-radius: 0 0 (#size / 2) (#size / 2);
.origin(0, 0);
}
#animation {
animation: anim 2s linear 0s infinite alternate;
// transform-origin: 50% 100%;
}
#container {
width: 100px;
height: 100px;
perspective: 300px;
}
#keyframes anim {
from {
transform: rotateX(0deg);
}
to {
transform: rotateX(180deg);
}
}
<div class "container">
<div class="top-half red"></div>
<div class="bottom-half green" id="animation"></div>
</div>
Please follow this link to see the animation. If there are any other efficent ways to do this with a variable size, but through either normal css or js please let me know!

Alternative to using position absolute for page transitions in a SPA

I am building a Single Page Application and I am using position absolute on my views (pages) in order to achieve page transitions while I navigate to different pages. I am using css animations and the effect I am after is one page to slide out to the right and at the same time the next page to slide in from the left.
This works fine as it is, but the problem is that most mobile browsers render the absolute positioned elements as a different layout and this has a negative effect on performance.
I wonder if there is an alternative to absolute positioning in order to achieve the effect I described above. I have tried to use display: flex and float: left, but could not achieve the same effect.
Check a very basic example of what I am doing:
#-webkit-keyframes moveFromLeft {
from { -webkit-transform: translateX(-100%); }
}
#keyframes moveFromLeft {
from { -webkit-transform: translateX(-100%); transform: translateX(-100%); }
}
#-webkit-keyframes moveToRight {
from { }
to { -webkit-transform: translateX(100%); }
}
#keyframes moveToRight {
from { }
to { -webkit-transform: translateX(100%); transform: translateX(100%); }
}
.moveFromLeft {
-webkit-animation: moveFromLeft .7s ease both;
animation: moveFromLeft .7s ease both;
}
.moveToRight {
-webkit-animation: moveToRight .7s ease both;
animation: moveToRight .7s ease both;
}
html,
body,
.page-container {
height: 100%;
position: relative;
width: 100%;
}
.page {
height: 400px;
color: #FFF;
position: absolute;
left: -100%;
top: 0;
width: 100%;
display: none;
}
.page.active {
display: block;
left: 0;
}
.page1 {
background: #000;
}
.page2 {
background: #0F0;
}
Fiddle

Categories

Resources