How to use css3 to achieve a ball bounce effect? - css

In fact I have almost successs:
I have a div needed to bounce :
<div class="container">
<div class="flipcard transition allowhover">
<h1>This is card</h1>
</div>
</div>​
then I use css3 animate to achieve bounce effect:
.container{
width: 100%;
height: 100%;
-moz-perspective: 1000px;
}
.flipcard{
background: red;
width: 200px;
height: 300px;
position: absolute;
top: 40px;
left: 20px;
-webkit-transform-style: preserve-3d;
-webkit-transition:all 0.6s ease-in-out;
}
.allowhover:hover{
-webkit-animation-name: bounce;
-webkit-animation-duration: 1.5s;
-webkit-animation-iteration-count: infinite ;
-webkit-animation-direction: normal;
}
#-webkit-keyframes bounce {
25% {
top:7px;
}
45% {
top:40px;
}
64% {
top:19px;
}
76% {
top:40px;
}
96%{
top: 25px
}
100% {
top:40px;
}
}​
now the online example is here :http://jsfiddle.net/GEEtx/
It seems work, but not good enough,how should I set the key-frames parameter to make it bounce more like a ball?Is there a formula to calculate the bounce height and countaccording to the element's width and height, or the time?

With little trial and error we can figure out the bounce effect as needed.
There is this formula that is used in all jQuery easing plugins to get the bounce effect.
easeInBounce: function (x, t, b, c, d) {
return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
},
easeOutBounce: function (x, t, b, c, d) {
if ((t/=d) < (1/2.75)) {
return c*(7.5625*t*t) + b;
} else if (t < (2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
} else if (t < (2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
} else {
return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
}
// t: current time, b: begInnIng value, c: change In value, d: duration
So applying this to current CSS keyframes.
d : the animation duration. //1.5 : 1500
b : top value at the start // 0
c : change in value //40px
t : Current time // 10
With some more work on it by applying these we might find out the values needed for the bounce effect in CSS.
I also found this CSS3 3D Bouncing Ball tutorial
Hope that might help you.

Related

CSS: How do I scale an element at a steady speed using cubic-bezier?

I have a 16384px X 16384px canvas.
I start off with my canvas scaled down to 512px.
I then scale my canvas to its original size.
The scaling (in and out) works.
The problem is that even though I've set the timing function to linear it doesn't look "linear". It speeds up at the start and slows down at the end.
You can see what I'm describing here:
let canvas = document.querySelector('canvas')
let button = document.querySelector('button')
let ctx = canvas.getContext('2d')
button.onclick = function() {
if (canvas.classList.contains('scale')) {
canvas.classList.remove('scale')
} else {
canvas.classList.add('scale')
}
}
let img = new Image()
img.height = '256px'
img.width = '256px'
img.onload = function() {
let y = 0
while (y < 16384) {
let x = 0
while (x < 16384) {
ctx.drawImage(img, x, y)
x+=256
}
y+=256
}
button.classList.remove('hidden')
}
img.src = 'https://i.etsystatic.com/16276846/r/il/ab3661/1503703028/il_570xN.1503703028_frl8.jpg'
canvas {
position: absolute;
transform: translate(-50%, -50%) scale3d(0.03125, 0.03125, 0.03125);
transition: transform 5s linear;
top: 50%;
left: 50%;
}
canvas.scale {
transform: translate(-50%, -50%) scale3d(1, 1, 1);
}
button {
position: absolute;
top: 0;
left: 0;
}
.hidden {
display: none;
}
<canvas width="16384px" height="16384px"></canvas>
<button class="hidden">
scale
</button>
I understand that this is a known "problem" related to the size of the element being scaled (in my case it's pretty huge) and (I assume) the duration (?) of the scaling (in my case it's 5 seconds).
I know that the "solution" is to use a cubic-bezier() timing function but I don't know what values to use in order to create a steady (as much as possible) scaling in (and out) animation.
Is there some "formula" to figure out the values cubic-bezier() should have in my context ?
Maybe what I'm describing as a "problem" is actually an optical illusion (that things are speeding up or slowing down even though this never actually happens) that you cannot prevent when scaling (?)
Note: I don't mind increasing the duration of the transition from 5s to whatever (<=10s) is needed in order to create a steady scale in/out.
Chrome Devtools allows you to edit timing functions and suggests "quadratic" as one on the function sets
This example uses "quadratic in" and "quadratic out"
let canvas = document.querySelector('canvas')
let button = document.querySelector('button')
let ctx = canvas.getContext('2d')
button.onclick = function() {
if (canvas.classList.contains('scale')) {
canvas.classList.remove('scale')
} else {
canvas.classList.add('scale')
}
}
let img = new Image()
img.height = '256px'
img.width = '256px'
img.onload = function() {
let y = 0
while (y < 16384) {
let x = 0
while (x < 16384) {
ctx.drawImage(img, x, y)
x+=256
}
y+=256
}
button.classList.remove('hidden')
}
img.src = 'https://i.etsystatic.com/16276846/r/il/ab3661/1503703028/il_570xN.1503703028_frl8.jpg'
canvas {
position: absolute;
transform: translate(-50%, -50%) scale3d(0.03125, 0.03125, 0.03125);
transition: transform 5s linear;
top: 50%;
left: 50%;
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
canvas.scale {
transform: translate(-50%, -50%) scale3d(1, 1, 1);
transition-timing-function: cubic-bezier(0.55, 0.09, 0.68, 0.53);
}
button {
position: absolute;
top: 0;
left: 0;
}
.hidden {
display: none;
}
<canvas width="16384px" height="16384px"></canvas>
<button class="hidden">
scale
</button>

How to skip to a specific time in css-animations by seconds?

is there any way to skip to specific time in css animation?
for example: if we have a div moving from left to right in 10 seconds, user change time to 5 and animation jumps to second 5 and continues playing.
Changing animation-delay will do exactly that.
When you change it to negative values, it will jump forward.
const selectElement = document.querySelector('.number');
selectElement.addEventListener('change', (event) => {
const result = document.querySelector('.some-div');
result.style.animationDelay = `${event.target.value}s`;
});
.some-div {
width: 100px;
height: 100px;
background-color: red;
animation-name: example;
animation-duration: 20s;
animation-delay: 0;
}
#keyframes example {
from {
transform: translateX(0px);
}
to {
transform: translateX(400px);
}
}
<div class="some-div"></div>
<input type="number" class="number" />
<br/>
change the value in the input

CSS End a keyframe looping animation and have it animate back to start

I have a looping animation that rotates a square. When I remove the class that enables the animation, the square instantly goes back to the starting position.
I need to be able to animate the square back to the starting position on a JS event.
Here is a codepen.
I have tried adding a transform to the element, and switching to another keyframe animation but neither worked.
html:
<div class="container">
<div class="animate rotating"></div>
</div>
css:
.container{
position: absolute;
width: 100%;
height: 100%;
background-color: #333;
}
.animate{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
top: 50%;
left: 50%;
margin: -50px 0 0 -50px;
transform: all 2s ease;
}
#keyframes rotating {
0%{transform: rotate(30deg);}
50%{transform: rotate(-30deg);}
100%{transform: rotate(30deg);}
}
.rotating {
animation: rotating 6s ease-in-out infinite forwards;
animation-delay: -2s;
}
jquery:
$('.animate').click(function(){
$(this).removeClass('rotating');
});
There is a little problem with your code:
transform: all 2s ease;
You mistyped transition, however I'm pretty sure this approach isn't going to work. If you're willing to accomplish this using jQuery you can get current rotation and apply to your element:
function getRotationDegrees(obj) {
var matrix = obj.css("-webkit-transform") ||
obj.css("-moz-transform") ||
obj.css("-ms-transform") ||
obj.css("-o-transform") ||
obj.css("transform");
if(matrix !== 'none') {
var values = matrix.split('(')[1].split(')')[0].split(',');
var a = values[0];
var b = values[1];
var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
} else { var angle = 0; }
return (angle < 0) ? angle + 360 : angle;
}
$('.animate').click(function(){
var el = $(this);
var elRotate = getRotationDegrees(el);
el.css('transform',`rotate(${elRotate}deg)`);
el.removeClass('rotating');
// set new transform here
});
This will freeze your element rotation, you can set your desired rotation at the end and transition will be applied.

transition for translateY(0) working, but not translateY(-50px)

I'm having some trouble with a transition on a transform. I'm making a tic-tac-toe game like in the freecodecamp front-end challenges: https://codepen.io/freeCodeCamp/full/KzXQgy.
I've been able to create most layout things no problem, but am having an issue with my transition on a div that shows which players' turn it is after hitting the reset button. Right now I'm just working on two player mode, so I click two players, then X or O, and then the tic-tac-toe board shows up and a div transform: translateY(-50px) to indicate whether it's Player 1 or Player 2's turn (based on a random number variable I set up). The first time through the div transition's perfectly. Then I hit the Reset All div and it takes me back to the beginning to choose how many players again. And the div transitions the transform: translateY(0) perfectly back to it's starting position. Where I'm struggling is, now when I cycle through the options again, if it's Player 1 or Player 2's turn again, the transition never happens and the div just transforms -50px up with the translateY.
I've tried everything I could think of, JS setting up the transition, resetting the transition, moving the transition to be on different classes, adding and removing a class that only has a transition on it. Can't figure it out, but the weird thing is, whenever I hit the "Reset All", the transform transitions back to 0px normally. Here's my codepen: https://codepen.io/rorschach1234/pen/dZMaJg?editors=0111. I know it's still very rough, but just can't figure out this transition problem. Really appreciate any help. Thanks everyone!
My relevant Html:
<div class="container">
<div class="turns">
<div class="turns__left turns__box"></div>
<div class="turns__right turns__box"></div>
</div>
</div>
My relevant CSS:
.turns {
width: 100%;
display: flex;
position: absolute;
justify-content: space-around;
top: 0;
left: 0;
z-index: -1;
&__box {
width: 40%;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 1.3em;
font-family: sans-serif;
transition: transform 1s .3s ease;
}
&__left {
background-color: $color-turn-left;
//transition: transform 1s .3s ease;
}
&__right {
background-color: $color-turn-right;
//transition: transform 1s .3s ease;
}
}
My Javascript:
let numOfPlayers = document.querySelectorAll(".player .choices h2");
let playerScreen = document.querySelector(".player");
let markerScreen = document.querySelector(".markers");
let singlePlayer = true;
let backBtn = document.querySelector(".markers__back");
let gameScreen = document.querySelector(".game");
let playerOne; let playerTwo; let activePlayer;
let turnBoxes = document.querySelectorAll(".turns__box");
let resetBtn = document.querySelector(".scoreboard__reset");
game();
function game() {
playerModeSelection();
markerSelection();
}
function boardChange(active, inactive) {
inactive.style.opacity = "0";
inactive.style.zIndex = "0";
active.style.opacity = "1";
active.style.zIndex = "1";
}
//One or Two player Selection & transition to Marker Selector
function playerModeSelection() {
for (let i = 0; i < numOfPlayers.length; i++) {
numOfPlayers[i].addEventListener("click", function() {
if(i === 1) {
singlePlayer = false;
}
boardChange(markerScreen, playerScreen);
})
}
}
function markerSelection() {
//Back Button Functionality
backBtn.addEventListener("click", function() {
boardChange(playerScreen, markerScreen);
})
//Listen for choice of X or O
for (let i = 0; i < markers.length; i ++) {
markers[i].addEventListener("click", function() {
boardChange(gameScreen, markerScreen);
if (i === 1) {
playerArr = ["O", "X"];
}
//Starts Two Player Game; Here begin is the function that calls transition
if(!singlePlayer) {
twoPlayerMode();
}
})
}
}
function twoPlayerMode() {
activePlayer = Math.floor(Math.random() * 2);
turnBoxes[activePlayer].textContent = "Go Player " + (activePlayer + 1) + "!";
turnBoxes[activePlayer].style.transform = "translateY(-50px)";
resetBtn.addEventListener("click", function() {
boardChange(playerScreen, gameScreen);
turnBoxes[activePlayer].style.transform = "translateY(0px)";
})
}

Queued CSS animations using delay or keyframes that can be interrupted smoothly

First, a fiddle: http://jsfiddle.net/AATLz/
The essence here is that there's a set of animations queued using -webkit-transition-delay. First element 0.4s, second 0.8s, third 1.4s, etc. They're queued last to first by default, and first to last when the parent has the 'expanded' class (toggled with that button).
This means that the animation when '.expanded' is added brings the boxes out one by one, and in reverse when the class is removed.
That's dandy. The problems start to arise when the class is toggled mid-animation. If you toggle, say, after the second box has animated, there's a delay before they start animating back, because a couple delay timers are being waited out.
Delays are obviously a bit clunky here.
The two alternatives I have in mind are 1) CSS keyframe animations, which I'm not entirely sure of how to activate on multiple elements in succession, and 2), JS controlled timing - using something like jQuery Transit. I'm not sure which would be more capable/graceful or if I'm missing another option.
Any input would be awesome!
jsfiddle: http://jsfiddle.net/Bushwazi/fZwTT/
Changed it up a bit. Control the timing with js. Animations with css.
CSS:
* {
margin:0;
padding:0;
}
#container {
background: orange;
height: 100px;
position: relative;
width: 100px;
}
.box {
height: 100px;
left: 0;
position: absolute;
top: 0;
width: 100px;
-webkit-transition:all 0.5s ease-in-out 0s;
-moz-transition:all 0.5s ease-in-out 0s;
-o-transition:all 0.5s ease-in-out 0s;
transition:all 0.5s ease-in-out 0s;
-webkit-transform: translate3d(0,0,0);
}
.box-1 {
background: red;
}
.box-2 {
background: green;
}
.box-3 {
background: yellow;
}
.box-4 {
background: blue;
}
.box-1 .box-1 {
left:100px;
}
.box-2 .box-2 {
left:200px;
}
.box-3 .box-3 {
left:300px;
}
.box-4 .box-4 {
left:400px;
}
HTML:
<div id="container" class="box-0" data-status="default" data-box="0">
<div class="box box-1"></div>
<div class="box box-2"></div>
<div class="box box-3"></div>
<div class="box box-4"></div>
</div>
<button id="ToggleAnim">Toggle</button>
JS:
(function(){
var testies = {
to: 0,
init: function(){
$button = $('#ToggleAnim');
$anim_elm = $('#container');
$(function(){
testies.el();
});
},
el: function(){ // el ==> event listeners
$button.on('click', testies.toggleBoxes);
},
toggleBoxes: function(evt){
var status = $anim_elm.attr('data-status'),
pos = $anim_elm.attr('data-box');
window.clearTimeout(testies.to);
// if default ==> build
// if killing ==> build
// if building ==> kill
// if done ==> kill
if(status == 'build' || status == 'done'){
testies.kill();
} else {
testies.build();
}
evt.preventDefault();
},
build: function(){
bpos = $anim_elm.attr('data-box');
if(bpos < 4){
bpos++;
$anim_elm.attr('data-status', "build").attr('data-box', bpos).addClass('box-' + bpos);
testies.to = window.setTimeout(testies.build, 500);
}
if(bpos == 4)$anim_elm.attr('data-status', "done");
console.log('BUILD: ' + bpos);
},
kill: function(){
kpos = $anim_elm.attr('data-box');
if(kpos > 0){
db = kpos - 1;
$anim_elm.attr('data-status', "kill").attr('data-box', db).removeClass('box-' + kpos);
testies.to = window.setTimeout(testies.kill, 500);
}
console.log('KILL: ' + kpos);
if(kpos == 0)$anim_elm.attr('data-status', "default")
}
}
testies.init();
})();

Resources