pause/resume svg animation on android webview - javascript
I want to pause/resume SVG animation on Android WebView using JavaScript.
tried on jsfiddle but not working either http://jsfiddle.net/ysbo5zdw/1/
/assets/svg/trial.html
<!DOCTYPE html>
<html>
<head>
<title>dynamic Image</title>
</head>
<body>
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="cloudDrizzleSunFillAlt" class="climacon climacon_cloudDrizzleSunFillAlt" x="0px" y="0px"
viewBox="15 15 70 70" enable-background="new 15 15 70 70" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
svg{
shape-rendering: geometricPrecision
}
g, path, circle, rect{
-webkit-transform-origin: 50% 50%;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
-webkit-animation-duration: 12s;
-webkit-animation-direction: normal;
-moz-transform-origin: 50% 50%;
-moz-animation-iteration-count: infinite;
-moz-animation-timing-function: linear;
-moz-animation-duration: 12s;
-moz-animation-direction: normal;
-o-transform-origin: 50% 50%;
-o-animation-iteration-count: infinite;
-o-animation-timing-function: linear;
-o-animation-duration: 12s;
-o-animation-direction: normal;
transform-origin: 50% 50%;
transform-box: fill-box;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-duration: 12s;
animation-direction: normal;
}
.climacon_componentWrap-sun_cloud {
-webkit-animation-name: behindCloudMove, rotate;
-moz-animation-name: behindCloudMove, rotate;
-o-animation-name: behindCloudMove, rotate;
animation-name: behindCloudMove, rotate;
-webkit-animation-iteration-count: 1, infinite;
-moz-animation-iteration-count: 1, infinite;
-o-animation-iteration-count: 1, infinite;
animation-iteration-count: 1, infinite;
-webkit-animation-timing-function: ease-out, linear;
-moz-animation-timing-function: ease-out, linear;
-o-animation-timing-function: ease-out, linear;
animation-timing-function: ease-out, linear;
-webkit-animation-delay: 0, 3s;
-moz-animation-delay: 0, 3s;
-o-animation-delay: 0, 3s;
animation-delay: 0, 3s;
-webkit-animation-duration: 3s, 12s;
-moz-animation-duration: 3s, 12s;
-o-animation-duration: 3s, 12s;
animation-duration: 3s, 12s;
}
.climacon_component-stroke_sunSpoke {
fill-opacity: 0;
-webkit-animation-name: fillOpacity, scale;
-moz-animation-name: fillOpacity, scale;
-o-animation-name: fillOpacity, scale;
animation-name: fillOpacity, scale;
-webkit-animation-direction: alternate;
-moz-animation-direction: alternate;
-o-animation-direction: alternate;
animation-direction: alternate;
-webkit-animation-iteration-count: 1, infinite;
-moz-animation-iteration-count: 1, infinite;
-o-animation-iteration-count: 1, infinite;
animation-iteration-count: 1, infinite;
-webkit-animation-delay: 3s, 0;
-moz-animation-delay: 3s, 0;
-o-animation-delay: 3s, 0;
animation-delay: 3s, 0;
-webkit-animation-duration: 3s;
-moz-animation-duration: 3s;
-o-animation-duration: 3s;
animation-duration: 3s;
-webkit-animation-fill-mode: both;
-moz-animation-fill-mode: both;
-o-animation-fill-mode: both;
animation-fill-mode: both;
}
.climacon_component-stroke_sunSpoke:nth-child(even) {
-webkit-animation-delay: 3s;
-moz-animation-delay: 3s;
-o-animation-delay: 3s;
animation-delay: 3s;
}
.climacon_component-stroke_drizzle {
fill-opacity: 0;
-webkit-animation-name: drizzleFall, fillOpacity2;
-moz-animation-name: drizzleFall, fillOpacity2;
-o-animation-name: drizzleFall, fillOpacity2;
animation-name: drizzleFall, fillOpacity2;
-webkit-animation-timing-function: ease-in;
-moz-animation-timing-function: ease-in;
-o-animation-timing-function: ease-in;
animation-timing-function: ease-in;
-webkit-animation-duration: 1s;
-moz-animation-duration: 1s;
-o-animation-duration: 1s;
animation-duration: 1s;
}
.climacon_component-stroke_drizzle:nth-child(1) {
-webkit-animation-delay: 0s;
-moz-animation-delay: 0s;
-o-animation-delay: 0s;
animation-delay: 0s;
}
.climacon_component-stroke_drizzle:nth-child(2) {
-webkit-animation-delay: 0.6s;
-moz-animation-delay: 0.6s;
-o-animation-delay: 0.6s;
animation-delay: 0.6s;
}
.climacon_component-stroke_drizzle:nth-child(3) {
-webkit-animation-delay: 1.2s;
-moz-animation-delay: 1.2s;
-o-animation-delay: 1.2s;
animation-delay: 1.2s;
}
#-webkit-keyframes rotate{
0%{
-webkit-transform: rotate(0);
}
100%{
-webkit-transform: rotate(360deg);
}
}
#-moz-keyframes rotate{
0%{
-moz-transform: rotate(0);
}
100%{
-moz-transform: rotate(360deg);
}
}
#-o-keyframes rotate{
0%{
-o-transform: rotate(0);
}
100%{
-o-transform: rotate(360deg);
}
}
#keyframes rotate{
0%{
transform: rotate(0);
}
100%{
transform: rotate(360deg);
}
}
#-webkit-keyframes scale{
0%{
-webkit-transform: scale(1,1)
}
100%{
-webkit-transform: scale(.5,.5)
}
}
#-moz-keyframes scale{
0%{
-moz-transform: scale(1,1)
}
100%{
-moz-transform: scale(.5,.5)
}
}
#-o-keyframes scale{
0%{
-o-transform: scale(1,1)
}
100%{
-o-transform: scale(.5,.5)
}
}
#keyframes scale{
0%{
transform: scale(1,1)
}
100%{
transform: scale(.5,.5)
}
}
#-webkit-keyframes behindCloudMove {
0% {
-webkit-transform: translateX(-1.75px) translateY(1.75px);
}
100% {
-webkit-transform: translateX(0) translateY(0);
}
}
#-moz-keyframes behindCloudMove {
0% {
-moz-transform: translateX(-1.75px) translateY(1.75px);
}
100% {
-moz-transform: translateX(0) translateY(0);
}
}
#-o-keyframes behindCloudMove {
0% {
-o-transform: translateX(-1.75px) translateY(1.75px);
}
100% {
-o-transform: translateX(0) translateY(0);
}
}
#keyframes behindCloudMove {
0% {
transform: translateX(-1.75px) translateY(1.75px);
}
100% {
transform: translateX(0) translateY(0);
}
}
#-webkit-keyframes drizzleFall {
0% {
-webkit-transform: translateY(0);
}
100% {
-webkit-transform: translateY(21px);
}
}
#-moz-keyframes drizzleFall {
0% {
-moz-transform: translateY(0);
}
100% {
-moz-transform: translateY(21px);
}
}
#-o-keyframes drizzleFall {
0% {
-o-transform: translateY(0);
}
100% {
-o-transform: translateY(21px);
}
}
#keyframes drizzleFall {
0% {
transform: translateY(0);
}
100% {
transform: translateY(21px);
}
}
#-webkit-keyframes fillOpacity {
0% {
fill-opacity: 0;
stroke-opacity: 0;
}
100% {
fill-opacity: 1;
stroke-opacity: 1;
}
}
#-moz-keyframes fillOpacity {
0% {
fill-opacity: 0;
stroke-opacity: 0;
}
100% {
fill-opacity: 1;
stroke-opacity: 1;
}
}
#-o-keyframes fillOpacity {
0% {
fill-opacity: 0;
stroke-opacity: 0;
}
100% {
fill-opacity: 1;
stroke-opacity: 1;
}
}
#keyframes fillOpacity {
0% {
fill-opacity: 0;
stroke-opacity: 0;
}
100% {
fill-opacity: 1;
stroke-opacity: 1;
}
}
#-webkit-keyframes fillOpacity2 {
0% {
fill-opacity: 0;
stroke-opacity: 0;
}
50% {
fill-opacity: 1;
stroke-opacity: 1;
}
100% {
fill-opacity: 0;
stroke-opacity: 0;
}
}
#-moz-keyframes fillOpacity2 {
0% {
fill-opacity: 0;
stroke-opacity: 0;
}
50% {
fill-opacity: 1;
stroke-opacity: 1;
}
100% {
fill-opacity: 0;
stroke-opacity: 0;
}
}
#-o-keyframes fillOpacity2 {
0% {
fill-opacity: 0;
stroke-opacity: 0;
}
50% {
fill-opacity: 1;
stroke-opacity: 1;
}
100% {
fill-opacity: 0;
stroke-opacity: 0;
}
}
#keyframes fillOpacity2 {
0% {
fill-opacity: 0;
stroke-opacity: 0;
}
50% {
fill-opacity: 1;
stroke-opacity: 1;
}
100% {
fill-opacity: 0;
stroke-opacity: 0;
}
}
</style>
<g class="climacon_iconWrap climacon_iconWrap-cloudDrizzleSunFillAlt" transform="matrix(1, 0, 0, 1, -8.226453, -0.543087)">
<g class="climacon_componentWrap climacon_componentWrap-sun climacon_componentWrap-sun_cloud">
<g class="climacon_componentWrap climacon_componentWrap_sunSpoke">
<path class="climacon_component climacon_component-stroke climacon_component-stroke_sunSpoke climacon_component-stroke_sunSpoke-north" d="M80.029,43.611h-3.998c-1.105,0-2-0.896-2-1.999s0.895-2,2-2h3.998c1.104,0,2,0.896,2,2S81.135,43.611,80.029,43.611z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_sunSpoke climacon_component-stroke_sunSpoke-north" d="M72.174,30.3c-0.781,0.781-2.049,0.781-2.828,0c-0.781-0.781-0.781-2.047,0-2.828l2.828-2.828c0.779-0.781,2.047-0.781,2.828,0c0.779,0.781,0.779,2.047,0,2.828L72.174,30.3z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_sunSpoke climacon_component-stroke_sunSpoke-north" d="M58.033,25.614c-1.105,0-2-0.896-2-2v-3.999c0-1.104,0.895-2,2-2c1.104,0,2,0.896,2,2v3.999C60.033,24.718,59.135,25.614,58.033,25.614z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_sunSpoke climacon_component-stroke_sunSpoke-north" d="M43.892,30.3l-2.827-2.828c-0.781-0.781-0.781-2.047,0-2.828c0.78-0.781,2.047-0.781,2.827,0l2.827,2.828c0.781,0.781,0.781,2.047,0,2.828C45.939,31.081,44.673,31.081,43.892,30.3z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_sunSpoke climacon_component-stroke_sunSpoke-north" d="M42.033,41.612c0,1.104-0.896,1.999-2,1.999h-4c-1.104,0-1.998-0.896-1.998-1.999s0.896-2,1.998-2h4C41.139,39.612,42.033,40.509,42.033,41.612z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_sunSpoke climacon_component-stroke_sunSpoke-north" d="M43.892,52.925c0.781-0.78,2.048-0.78,2.827,0c0.781,0.78,0.781,2.047,0,2.828l-2.827,2.827c-0.78,0.781-2.047,0.781-2.827,0c-0.781-0.78-0.781-2.047,0-2.827L43.892,52.925z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_sunSpoke climacon_component-stroke_sunSpoke-north" d="M58.033,57.61c1.104,0,2,0.895,2,1.999v4c0,1.104-0.896,2-2,2c-1.105,0-2-0.896-2-2v-4C56.033,58.505,56.928,57.61,58.033,57.61z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_sunSpoke climacon_component-stroke_sunSpoke-north" d="M72.174,52.925l2.828,2.828c0.779,0.78,0.779,2.047,0,2.827c-0.781,0.781-2.049,0.781-2.828,0l-2.828-2.827c-0.781-0.781-0.781-2.048,0-2.828C70.125,52.144,71.391,52.144,72.174,52.925z" style="fill: rgb(87, 248, 7);"/>
</g>
<g class="climacon_wrapperComponent climacon_wrapperComponent-sunBody">
<circle class="climacon_component climacon_component-stroke climacon_component-stroke_sunBody" cx="58.033" cy="41.612" r="11.999" style="fill: rgb(87, 248, 7);"/>
<circle class="climacon_component climacon_component-fill climacon_component-fill_sunBody" fill="#FFFFFF" cx="58.033" cy="41.612" r="7.999"/>
</g>
</g>
<g class="climacon_wrapperComponent climacon_wrapperComponent-drizzle">
<path class="climacon_component climacon_component-stroke climacon_component-stroke_drizzle climacon_component-stroke_drizzle-left" id="Drizzle-Left_1_" d="M56.969,57.672l-2.121,2.121c-1.172,1.172-1.172,3.072,0,4.242c1.17,1.172,3.07,1.172,4.24,0c1.172-1.17,1.172-3.07,0-4.242L56.969,57.672z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_drizzle climacon_component-stroke_drizzle-middle" d="M50.088,57.672l-2.119,2.121c-1.174,1.172-1.174,3.07,0,4.242c1.17,1.172,3.068,1.172,4.24,0s1.172-3.07,0-4.242L50.088,57.672z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-stroke climacon_component-stroke_drizzle climacon_component-stroke_drizzle-right" d="M43.033,57.672l-2.121,2.121c-1.172,1.172-1.172,3.07,0,4.242s3.07,1.172,4.244,0c1.172-1.172,1.172-3.07,0-4.242L43.033,57.672z" style="fill: rgb(87, 248, 7);"/>
</g>
<g class="climacon_componentWrap climacon_componentWrap_cloud">
<path class="climacon_component climacon_component-stroke climacon_component-stroke_cloud" d="M43.945,65.639c-8.835,0-15.998-7.162-15.998-15.998c0-8.836,7.163-15.998,15.998-15.998c6.004,0,11.229,3.312,13.965,8.203c0.664-0.113,1.338-0.205,2.033-0.205c6.627,0,11.998,5.373,11.998,12c0,6.625-5.371,11.998-11.998,11.998C57.168,65.639,47.143,65.639,43.945,65.639z" style="fill: rgb(87, 248, 7);"/>
<path class="climacon_component climacon_component-fill climacon_component-fill_cloud" d="M59.943,61.639c4.418,0,8-3.582,8-7.998c0-4.417-3.582-8-8-8c-1.601,0-3.082,0.481-4.334,1.291c-1.23-5.316-5.973-9.29-11.665-9.29c-6.626,0-11.998,5.372-11.998,11.999c0,6.626,5.372,11.998,11.998,11.998C47.562,61.639,56.924,61.639,59.943,61.639z" style="fill: rgb(255, 255, 255);"/>
</g>
</g>
<script type="text/javascript">
function pauseAnim(){
document.getElementById('cloudDrizzleSunFillAlt').pauseAnimations();
}
</script>
</svg>
</body>
</html>
MainActivity.java
svgWebView = (WebView) findViewById(R.id.svg_web_view);
svgWebView.setWebViewClient(new WebViewClient());
svgWebView.getSettings().setJavaScriptEnabled(true);
svgWebView.loadUrl("file:///android_asset/svg/trial.html");
svgWebView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
svgWebView.loadUrl("javascript:pauseAnim();");
return false;
}
});
javascript is inside SVG element but it is not working.
According to John Ktejik answered Can svg animations be suspended without loosing accumulative information? but no luck
My problem is I dont want to change SVG file as there are lot of SVGs I need to modify and It will be huge task.
I want to use something like SVGroot.pauseAnimations() documented on https://developer.mozilla.org/en-US/docs/Web/API/SVGSVGElement or any work around
This answer here Pause an external SVG animation sounds working but I dont know how to implement it in Android!
I would suggest you put
the animation start/stop functionality in different css classes:
svg.animation-on * {
animation-iteration-count: infinite;
}
svg.animation-off * {
animation-iteration-count: 0;
}
remove any other animation-iteration-count settings from existing stylesheet
Use javascript to set the appropriate class animation-on or animation off to the top level <svg> node
Related
How to know programmatically which is the last object that has the animation
Is there a way for me to know programmatically on which object the CSS animation applies last For example, .r1 { animation-name: move1; animation-delay: 2.5s; animation-duration: 1s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } .c1 { animation-name: blink; animation-delay: 0.5s; animation-duration: 1s; animation-iteration-count: 2; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } /*.text1 { animation-name: scl; animation-delay: 5.5s; animation-duration: 1s; animation-iteration-count: 2; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; }*/ .r2 { transform-origin: center; transform-box: fill-box; animation-name: gr; animation-delay: 3.5s; animation-duration: 2s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } .r3 { animation-name: move2; animation-delay: 7.5s; animation-duration: 1s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } #keyframes move1 { to { transform: translateX(200px); } } #keyframes blink { from { opacity: 0; } to { opacity: 1; } } #keyframes gr { from { transform: rotate(0deg); } to { transform: rotate(359deg); } } #keyframes scl { to { transform: scale(1.1); } } #keyframes move2 { to { transform: translateY(400px); } } } <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720"> <rect id="r1" class="r1" x="10" y="20" width="100" height="100" fill="red" /> <rect id="r2" class="r2" x="10" y="130" width="100" height="100" fill="green" /> <rect id="r3" class="r3" x="10" y="240" width="100" height="100" fill="blue" /> <circle id="c1" class="c1" cx="50" cy="400" r="40" fill="orange" /> <text class="text1" id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text> </svg> In this, I have 5 elements and I am applying animation on 4 of them and r3 is the last element on which the animation applies. Is there a way I can detect the animation-delay+animation-duration for r3- the last element on which the animation applies with javascript.
The Web Animations API can inspect animations. document.getAnimations() returns all animations found in the document. Each of them has an effect property, and in your case, they are all of the type KeyframeEffect. animation.animationName returns the animation name as stated in the CSS #keyframes declaration. animation.effect.target returns the element targeted by the animation. animation.effect.getComputedTiming().endTime returns the time the animation ends. From there you can compare and filter the information you need. document.getAnimations().forEach(animation => { console.log( animation.animationName, animation.effect.target.id, animation.effect.getComputedTiming().endTime ); }); .r1 { animation-name: move1; animation-delay: 2.5s; animation-duration: 1s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } .c1 { animation-name: blink; animation-delay: 0.5s; animation-duration: 1s; animation-iteration-count: 2; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } /*.text1 { animation-name: scl; animation-delay: 5.5s; animation-duration: 1s; animation-iteration-count: 2; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; }*/ .r2 { transform-origin: center; transform-box: fill-box; animation-name: gr; animation-delay: 3.5s; animation-duration: 2s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } .r3 { animation-name: move2; animation-delay: 7.5s; animation-duration: 1s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } #keyframes move1 { to { transform: translateX(200px); } } #keyframes blink { from { opacity: 0; } to { opacity: 1; } } #keyframes gr { from { transform: rotate(0deg); } to { transform: rotate(359deg); } } #keyframes scl { to { transform: scale(1.1); } } #keyframes move2 { to { transform: translateY(400px); } } <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720"> <rect id="r1" class="r1" x="10" y="20" width="100" height="100" fill="red" /> <rect id="r2" class="r2" x="10" y="130" width="100" height="100" fill="green" /> <rect id="r3" class="r3" x="10" y="240" width="100" height="100" fill="blue" /> <circle id="c1" class="c1" cx="50" cy="400" r="40" fill="orange" /> <text class="text1" id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text> </svg>
You can try to achieve this using animationend like so :- const animatedElements = []; const noOfElementsToAnimate = 4; const svgLayer = document.querySelector('#Layer_1'); const onAnimationEnd = (e) => { animatedElements.push(e.target.id); if (animatedElements.length === noOfElementsToAnimate) { svgLayer.removeEventListener('animationend', onAnimationEnd); console.log(animatedElements[animatedElements.length - 1]) } } svgLayer.addEventListener('animationend', onAnimationEnd); .r1 { animation-name: move1; animation-delay: 2.5s; animation-duration: 1s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } .c1 { animation-name: blink; animation-delay: 0.5s; animation-duration: 1s; animation-iteration-count: 2; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } /*.text1 { animation-name: scl; animation-delay: 5.5s; animation-duration: 1s; animation-iteration-count: 2; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; }*/ .r2 { transform-origin: center; transform-box: fill-box; animation-name: gr; animation-delay: 3.5s; animation-duration: 2s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } .r3 { animation-name: move2; animation-delay: 7.5s; animation-duration: 1s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } #keyframes move1 { to { transform: translateX(200px); } } #keyframes blink { from { opacity: 0; } to { opacity: 1; } } #keyframes gr { from { transform: rotate(0deg); } to { transform: rotate(359deg); } } #keyframes scl { to { transform: scale(1.1); } } #keyframes move2 { to { transform: translateY(400px); } } } <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720"> <rect id="r1" class="r1" x="10" y="20" width="100" height="100" fill="red" /> <rect id="r2" class="r2" x="10" y="130" width="100" height="100" fill="green" /> <rect id="r3" class="r3" x="10" y="240" width="100" height="100" fill="blue" /> <circle id="c1" class="c1" cx="50" cy="400" r="40" fill="orange" /> <text class="text1" id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text> </svg> Explanation: - Here I attached the event listener for animationend event to the parent element i.e. Layer_1 svg. Whenever the animation will end for its children elements, I push the id of that element to an array and compare it with an existing no which denote the no of animated elements that are in the DOM (can use a unique class to fetch these dynamically as well). When the animatedElements and noOfElementsToAnimate are equal, I remove the listener and log/use the last value of animatedElements array. Alternatively, you can also ditch the array and just use one variable to keep track of last animated element, say, lastAnimatedElement and decrement noOfElementsToAnimate and log the lastAnimatedElement when noOfElementsToAnimate is 0.
I came up with this which calculates the Delay+(Duration*Iteration-Count) for each of the svg elements and at the end returns the max value of that expression, which would be the total duration of the last element on which the animation ran. The last element with the animation logically will have the longest Delay+(Duration*Iteration-Count) which I need to pass on as an animation-delay for my next element for animation. var _layer1 = document.querySelectorAll('svg > *'); var _max = -1; for (const el of _layer1) { var __del = getComputedStyle(el).animationDelay; var __del = __del.split(','); var __delLast = parseFloat(__del[__del.length - 1]); var __duration = getComputedStyle(el).animationDuration; var __duration = __duration.split(','); var __durationLast = parseFloat(__duration[__del.length - 1]); var __iterationCount = getComputedStyle(el).animationIterationCount; var __iterationCount = __iterationCount.split(','); var __iterationCountLast = parseFloat(__iterationCount[__iterationCount.length - 1]); function alternate(a, b) { if (isNaN(a)) { return b } else { return a } }; var modified = alternate(__iterationCountLast, __durationLast); var _expression = __delLast + (__durationLast * modified); //Delay+(Duration*Iteration-Count) _max = Math.max(_max, _expression); }; .r1 { animation-name: move1; animation-delay: 2.5s; animation-duration: 1s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } .c1 { animation-name: blink; animation-delay: 0.5s; animation-duration: 1s; animation-iteration-count: 2; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } /*.text1 { animation-name: scl; animation-delay: 5.5s; animation-duration: 1s; animation-iteration-count: 2; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; }*/ .r2 { transform-origin: center; transform-box: fill-box; animation-name: gr; animation-delay: 3.5s; animation-duration: 2s; animation-iteration-count: 1; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } .r3 { animation-name: move2; animation-delay: 7.5s; animation-duration: 2s; animation-iteration-count: infinite; animation-timing-function: ease-in; animation-direction: normal; animation-fill-mode: forwards; } #keyframes move1 { to { transform: translateX(200px); } } #keyframes blink { from { opacity: 0; } to { opacity: 1; } } #keyframes gr { from { transform: rotate(0deg); } to { transform: rotate(359deg); } } #keyframes scl { to { transform: scale(1.1); } } #keyframes move2 { to { transform: translateY(400px); } } } <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720"> </svg>
Changes to the element's text breaks it's parent delegated event handlers
I'm working on a drop down menu as part of a school project. I've gotten most everything to work properly but I ran into an issue with JQuery events that I couldn't quite find the answer to, whenever I click on my list item it sets the list name properly but after that none of the events work. I put the handlers on parent elements to see if that helped but still nothing. Here's a quick look at the JQuery. $(document).ready(function(){ $('nav ul').on('mouseenter', '.menu1', function(){ $('.menu1 ul').removeClass("hidden"); }); $('nav ul').on('mouseleave', '.menu1', function(){ setTimeout(function(){ $('.menu1 ul').addClass("hidden"); }, 300); }); $('nav ul').on('click', '.menu1 ul li', function(){ $('.menu1').text($(this).text()); }); }); I have a code pen for the list as well. https://codepen.io/JFarenci/pen/gvoQvq
The issue is in $('.menu1').text($(this).text()); After this line gets executed on choosing an option, the portion inside the li tag changes to this: <li class="menu1">one</li> (assuming you had chosen 'one'). The ul tag along with the dropdown menu is overwritten. To fix this, have a separate space to display the selected option above the li tag. HTML: <p id="selected"></p> JAVASCRIPT: $('nav ul').on('click', '.menu1 ul li',function({ $('#selected').text($(this).text()); }); Hope this helps!
I removed your mouseenter and mouseleave events and replaced it with mouseover. On each click I added a span containing $(this).text(). Note that it's preceded by a remove() to handle for prior clicks when the text was set. See runnable snippet to test. $(document).ready(function() { $('nav ul').on('mouseover', '.menu1', function() { setTimeout(function() { $('.menu1 ul').show(); }, 300); }); $('nav ul').on('click', '.menu1 ul li', function() { $('.menu1').find("#click").remove(); $('.menu1').append('<span id="click">' + $(this).text() + '<span>'); }); }); nav { padding: 50px; text-align: center; } nav>ul { list-style: none; padding: 0; margin: 0; display: inline-block; background: #ddd; border-radius: 5px; } nav>ul>li { float: left; width: 150px; height: 65px; line-height: 65px; position: relative; text-transform: uppercase; font-size: 14px; color: rgba(0, 0, 0, 0.7); cursor: pointer; } nav>ul>li:hover { background: #d5d5d5; border-radius: 5px; } ul.dropMenu { position: absolute; top: 100%; left: 0%; width: 100%; padding: 0; } ul.dropMenu li { background: #666; color: rgba(255, 255, 255, 0.7); } ul.dropMenu li:hover { background: #606060; } ul.dropMenu li:last-child { border-radius: 0px 0px 5px 5px; } .hidden { display: none; /*opacity: 0;*/ } li:hover>ul.dropMenu { -webkit-perspective: 1000px; perspective: 1000px; } li:hover>ul.dropMenu li { opacity: 0; -webkit-transform-origin: top center; transform-origin: top center; } li:hover>ul.dropMenu li:nth-child(1) { -webkit-animation-name: fold-out; animation-name: fold-out; -webkit-animation-duration: 120ms; animation-duration: 120ms; -webkit-animation-delay: 0ms; animation-delay: 0ms; -webkit-animation-timing-function: ease; animation-timing-function: ease; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } li:hover>ul.dropMenu li:nth-child(2) { -webkit-animation-name: fold-out; animation-name: fold-out; -webkit-animation-duration: 120ms; animation-duration: 120ms; -webkit-animation-delay: 60ms; animation-delay: 60ms; -webkit-animation-timing-function: ease; animation-timing-function: ease; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } li:hover>ul.dropMenu li:nth-child(3) { -webkit-animation-name: fold-out; animation-name: fold-out; -webkit-animation-duration: 120ms; animation-duration: 120ms; -webkit-animation-delay: 120ms; animation-delay: 120ms; -webkit-animation-timing-function: ease; animation-timing-function: ease; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } li:hover>ul.dropMenu li:nth-child(4) { -webkit-animation-name: fold-out; animation-name: fold-out; -webkit-animation-duration: 120ms; animation-duration: 120ms; -webkit-animation-delay: 180ms; animation-delay: 180ms; -webkit-animation-timing-function: ease; animation-timing-function: ease; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } #-webkit-keyframes fold-out { 0% { opacity: 0; -webkit-transform: rotateX(-90deg) translateY(10px); transform: rotateX(-90deg) translateY(10px); } 60% { -webkit-transform: rotateX(15deg); transform: rotateX(15deg); } 100% { opacity: 1; -webkit-transform: rotateX(0deg) translateY(0px); transform: rotateX(0deg) translateY(0px); } } #keyframes fold-out { 0% { opacity: 0; -webkit-transform: rotateX(-90deg) translateY(10px); transform: rotateX(-90deg) translateY(10px); } 60% { -webkit-transform: rotateX(15deg); transform: rotateX(15deg); } 100% { opacity: 1; -webkit-transform: rotateX(0deg) translateY(0px); transform: rotateX(0deg) translateY(0px); } } li>ul.dropMenu { -webkit-perspective: 1000px; perspective: 1000px; } li>ul.dropMenu li { -webkit-transform-origin: top center; transform-origin: top center; } li>ul.dropMenu li:nth-child(4) { -webkit-animation-name: fold-in; animation-name: fold-in; -webkit-animation-duration: 120ms; animation-duration: 120ms; -webkit-animation-delay: 0ms; animation-delay: 0ms; -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } li>ul.dropMenu li:nth-child(3) { -webkit-animation-name: fold-in; animation-name: fold-in; -webkit-animation-duration: 120ms; animation-duration: 120ms; -webkit-animation-delay: 60ms; animation-delay: 60ms; -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } li>ul.dropMenu li:nth-child(2) { -webkit-animation-name: fold-in; animation-name: fold-in; -webkit-animation-duration: 120ms; animation-duration: 120ms; -webkit-animation-delay: 120ms; animation-delay: 120ms; -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } li>ul.dropMenu li:nth-child(1) { -webkit-animation-name: fold-in; animation-name: fold-in; -webkit-animation-duration: 120ms; animation-duration: 120ms; -webkit-animation-delay: 180ms; animation-delay: 180ms; -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } #-webkit-keyframes fold-in { 0% { -webkit-transform: rotateX(0deg) translateY(0px); transform: rotateX(0deg) translateY(0px); } 100% { opacity: 0; -webkit-transform: rotateX(-90deg) translateY(10px); transform: rotateX(-90deg) translateY(10px); } } #keyframes fold-in { 0% { -webkit-transform: rotateX(0deg) translateY(0px); transform: rotateX(0deg) translateY(0px); } 100% { opacity: 0; -webkit-transform: rotateX(-90deg) translateY(10px); transform: rotateX(-90deg) translateY(10px); } } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <nav> <ul> <li class="menu1"> <ul class="dropMenu hidden"> <li>one</li> <li>two</li> <li>three</li> <li>fork</li> </ul> </li> </ul> </nav>
Why div animation keyframe is not working when javascript engine is busy?
I have page structure as bellow: <head> <style> .windows8 { position: relative; width: 78px; height:78px; margin:auto; margin-top: 200px; } .windows8 .wBall { position: absolute; width: 74px; height: 74px; opacity: 0; transform: rotate(225deg); -o-transform: rotate(225deg); -ms-transform: rotate(225deg); -webkit-transform: rotate(225deg); -moz-transform: rotate(225deg); animation: orbit 6.96s infinite; -o-animation: orbit 6.96s infinite; -ms-animation: orbit 6.96s infinite; -webkit-animation: orbit 6.96s infinite; -moz-animation: orbit 6.96s infinite; } .windows8 .wBall .wInnerBall{ position: absolute; width: 10px; height: 10px; background: rgb(93, 147, 195); left:0px; top:0px; border-radius: 10px; } .windows8 #1wBall_1,.windows8 #wBall_1 { animation-delay: 1.52s; -o-animation-delay: 1.52s; -ms-animation-delay: 1.52s; -webkit-animation-delay: 1.52s; -moz-animation-delay: 1.52s; } .windows8 #1wBall_2,.windows8 #wBall_2 { animation-delay: 0.3s; -o-animation-delay: 0.3s; -ms-animation-delay: 0.3s; -webkit-animation-delay: 0.3s; -moz-animation-delay: 0.3s; } .windows8 #1wBall_3,.windows8 #wBall_3 { animation-delay: 0.61s; -o-animation-delay: 0.61s; -ms-animation-delay: 0.61s; -webkit-animation-delay: 0.61s; -moz-animation-delay: 0.61s; } .windows8 #1wBall_4,.windows8 #wBall_4 { animation-delay: 0.91s; -o-animation-delay: 0.91s; -ms-animation-delay: 0.91s; -webkit-animation-delay: 0.91s; -moz-animation-delay: 0.91s; } .windows8 #1wBall_5,.windows8 #wBall_5 { animation-delay: 1.22s; -o-animation-delay: 1.22s; -ms-animation-delay: 1.22s; -webkit-animation-delay: 1.22s; -moz-animation-delay: 1.22s; } #keyframes orbit { 0% { opacity: 1; z-index:99; transform: rotate(180deg); animation-timing-function: ease-out; } 7% { opacity: 1; transform: rotate(300deg); animation-timing-function: linear; origin:0%; } 30% { opacity: 1; transform:rotate(410deg); animation-timing-function: ease-in-out; origin:7%; } 39% { opacity: 1; transform: rotate(645deg); animation-timing-function: linear; origin:30%; } 70% { opacity: 1; transform: rotate(770deg); animation-timing-function: ease-out; origin:39%; } 75% { opacity: 1; transform: rotate(900deg); animation-timing-function: ease-out; origin:70%; } 76% { opacity: 0; transform:rotate(900deg); } 100% { opacity: 0; transform: rotate(900deg); } } #-o-keyframes orbit { 0% { opacity: 1; z-index:99; -o-transform: rotate(180deg); -o-animation-timing-function: ease-out; } 7% { opacity: 1; -o-transform: rotate(300deg); -o-animation-timing-function: linear; -o-origin:0%; } 30% { opacity: 1; -o-transform:rotate(410deg); -o-animation-timing-function: ease-in-out; -o-origin:7%; } 39% { opacity: 1; -o-transform: rotate(645deg); -o-animation-timing-function: linear; -o-origin:30%; } 70% { opacity: 1; -o-transform: rotate(770deg); -o-animation-timing-function: ease-out; -o-origin:39%; } 75% { opacity: 1; -o-transform: rotate(900deg); -o-animation-timing-function: ease-out; -o-origin:70%; } 76% { opacity: 0; -o-transform:rotate(900deg); } 100% { opacity: 0; -o-transform: rotate(900deg); } } #-ms-keyframes orbit { 0% { opacity: 1; z-index:99; -ms-transform: rotate(180deg); -ms-animation-timing-function: ease-out; } 7% { opacity: 1; -ms-transform: rotate(300deg); -ms-animation-timing-function: linear; -ms-origin:0%; } 30% { opacity: 1; -ms-transform:rotate(410deg); -ms-animation-timing-function: ease-in-out; -ms-origin:7%; } 39% { opacity: 1; -ms-transform: rotate(645deg); -ms-animation-timing-function: linear; -ms-origin:30%; } 70% { opacity: 1; -ms-transform: rotate(770deg); -ms-animation-timing-function: ease-out; -ms-origin:39%; } 75% { opacity: 1; -ms-transform: rotate(900deg); -ms-animation-timing-function: ease-out; -ms-origin:70%; } 76% { opacity: 0; -ms-transform:rotate(900deg); } 100% { opacity: 0; -ms-transform: rotate(900deg); } } #-webkit-keyframes orbit { 0% { opacity: 1; z-index:99; -webkit-transform: rotate(180deg); -webkit-animation-timing-function: ease-out; } 7% { opacity: 1; -webkit-transform: rotate(300deg); -webkit-animation-timing-function: linear; -webkit-origin:0%; } 30% { opacity: 1; -webkit-transform:rotate(410deg); -webkit-animation-timing-function: ease-in-out; -webkit-origin:7%; } 39% { opacity: 1; -webkit-transform: rotate(645deg); -webkit-animation-timing-function: linear; -webkit-origin:30%; } 70% { opacity: 1; -webkit-transform: rotate(770deg); -webkit-animation-timing-function: ease-out; -webkit-origin:39%; } 75% { opacity: 1; -webkit-transform: rotate(900deg); -webkit-animation-timing-function: ease-out; -webkit-origin:70%; } 76% { opacity: 0; -webkit-transform:rotate(900deg); } 100% { opacity: 0; -webkit-transform: rotate(900deg); } } #-moz-keyframes orbit { 0% { opacity: 1; z-index:99; -moz-transform: rotate(180deg); -moz-animation-timing-function: ease-out; } 7% { opacity: 1; -moz-transform: rotate(300deg); -moz-animation-timing-function: linear; -moz-origin:0%; } 30% { opacity: 1; -moz-transform:rotate(410deg); -moz-animation-timing-function: ease-in-out; -moz-origin:7%; } 39% { opacity: 1; -moz-transform: rotate(645deg); -moz-animation-timing-function: linear; -moz-origin:30%; } 70% { opacity: 1; -moz-transform: rotate(770deg); -moz-animation-timing-function: ease-out; -moz-origin:39%; } 75% { opacity: 1; -moz-transform: rotate(900deg); -moz-animation-timing-function: ease-out; -moz-origin:70%; } 76% { opacity: 0; -moz-transform:rotate(900deg); } 100% { opacity: 0; -moz-transform: rotate(900deg); } } </style> <!-- 4-5 style links--> <!-- 4-5 scripts --> <!-- for testing you can put following code for(var i=0;i<-1;i++){console.log(i)} --> </head> <body> <app> <div class="windows8"> <div class="wBall" id="wBall_1"> <div class="wInnerBall"></div> </div> <div class="wBall" id="wBall_2"> <div class="wInnerBall"></div> </div> <div class="wBall" id="wBall_3"> <div class="wInnerBall"></div> </div> <div class="wBall" id="wBall_4"> <div class="wInnerBall"></div> </div> <div class="wBall" id="wBall_5"> <div class="wInnerBall"></div> </div> </div> </app> </body> It renders the divs with all its css(e.g ball radius and background-color etc.) but key-frame(i.e. transition/movement) of ball are not working upto some time (until all css/js is downloded and parsed) but after that it works fine. I thought may be while loading and parsing css/js the rendering engine will be busy so it can't execute transition but when I took a look on other web-pages they uses css loaders as I do and it is working fine. So how their animation is working when mine not.
Because browser tabs are single threaded. Some browsers are single threaded, entirely. If the JavaScript never stops running in some browsers you can’t even close the tab. If you want the DOM to repaint, or canvas to animate, or the page to be clickable, you can not lock JS up. Which means that you have to learn different programming paradigms to break up long-running processes.
How do I get rid of the white outline around my button?
How do I get the white outline out of this button? Here's the CSS, tell me if you think something caused it. .btn { background: linear-gradient(45deg, rgba(51, 197, 230, 0.5) 0%,rgba(51, 230, 131, 0.5) 50%,rgba(108,0,153,0.65) 100%); border-radius: 10px; width: 1315px; color: #fff; font-size: 18px; letter-spacing: 1px; padding: 16px 32px; text-decoration: none; text-transform: uppercase; -webkit-transition: box-shadow 1s ease; transition: box-shadow 1s ease; } #-webkit-keyframes hvr-bob { 0% { -webkit-transform: translateY(-8px); transform: translateY(-8px); } 50% { -webkit-transform: translateY(-4px); transform: translateY(-4px); } 100% { -webkit-transform: translateY(-8px); transform: translateY(-8px); } } #keyframes hvr-bob { 0% { -webkit-transform: translateY(-8px); transform: translateY(-8px); } 50% { -webkit-transform: translateY(-4px); transform: translateY(-4px); } 100% { -webkit-transform: translateY(-8px); transform: translateY(-8px); } } #-webkit-keyframes hvr-bob-float { 100% { -webkit-transform: translateY(-8px); transform: translateY(-8px); } } #keyframes hvr-bob-float { 100% { -webkit-transform: translateY(-8px); transform: translateY(-8px); } } .btn { display: inline-block; vertical-align: middle; -webkit-transform: translateZ(0); transform: translateZ(0); box-shadow: 0 0 1px rgba(0, 0, 0, 0); -webkit-backface-visibility: hidden; backface-visibility: hidden; -moz-osx-font-smoothing: grayscale; } .btn:hover, a.btn:focus, a.btn:active { -webkit-animation-name: hvr-bob-float, hvr-bob; animation-name: hvr-bob-float, hvr-bob; -webkit-animation-duration: .3s, 1.5s; animation-duration: .3s, 1.5s; -webkit-animation-delay: 0s, .3s; animation-delay: 0s, .3s; -webkit-animation-timing-function: ease-out, ease-in-out; animation-timing-function: ease-out, ease-in-out; -webkit-animation-iteration-count: 1, infinite; animation-iteration-count: 1, infinite; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; -webkit-animation-direction: normal, alternate; animation-direction: normal, alternate; }
The above commenters are correct-- border: none and outline: none would be good starts. Remember that the browser itself has some default styles-- if you want to override them before you start trying to style I'd recommend investigating a CSS Reset. Also, is your .btn classed element a div, or a true button? If the latter, remember native form elements are difficult to style appropriately cross browser, so if the visual treatment is important, you should consider using a div and an event handler.
Create a bounce effect on hover
I have to develop a similar website like http://www.unlocknrepair.com/ In this website when you hover your mouse over the Unlocking or Phone repair button a dropdown menu appears. Is there a way to make this dropdown appear in bouncy way.. like I want it to bounce a bit before it stabilizes. It is possible in jQuery, but can it be done using only css and javascript?
If experimental css3 is an option, you can do it even without javascript using css animations with the #keyframes rule. #parent { position:relative; height: 40px; } #onhover { display: none; position: absolute; top: 0; } #parent:hover #onhover { display: block; top: 30px; animation:mymove 0.8s linear; -moz-animation:mymove 0.8s linear; /* Firefox */ -webkit-animation:mymove 0.8s linear; /* Safari and Chrome */ -o-animation:mymove 0.8s linear; /* Opera */ -ms-animation:mymove 0.8s linear; /* IE */ } #keyframes mymove { 0% {top:0px;} 10% {top:3px;} 40% {top:40px;} 60% {top:25px;} 80% {top:35px;} 100% {top:30px;} } #-moz-keyframes mymove /* Firefox */ { 0% {top:0px;} 10% {top:3px;} 40% {top:40px;} 60% {top:25px;} 80% {top:35px;} 100% {top:30px;} } #-webkit-keyframes mymove /* Safari and Chrome */ { 0% {top:0px;} 10% {top:3px;} 40% {top:40px;} 60% {top:25px;} 80% {top:35px;} 100% {top:30px;} } #-o-keyframes mymove /* Opera */ { 0% {top:0px;} 10% {top:3px;} 40% {top:40px;} 60% {top:25px;} 80% {top:35px;} 100% {top:30px;} } #-ms-keyframes mymove /* IE */ { 0% {top:0px;} 10% {top:3px;} 40% {top:40px;} 60% {top:25px;} 80% {top:35px;} 100% {top:30px;} } <div id="parent">hover me<div id="onhover">hovering</div></div> Another "bounce" animation: $(function() { $(document.body).delegate( "img", "mouseenter", function() { var $this = $(this).addClass("right"); setTimeout(function() { $this.removeClass("right"); }, 2000); }); }); body { font-size: .7em; font-family: Arial, Helvetica, "Liberation Sans", sans-serif; padding: 0 !important; } img { -moz-transition: -moz-transform 1s ease-in; -webkit-transition: -webkit-transform 1s ease-in; -o-transition: -o-transform 1s ease-in; -ms-transition: -ms-transform 1s ease-in; } #anim.right { -moz-animation-name: bounce; -moz-animation-duration: 1s; -moz-animation-iteration-count: 1; -moz-transform: translate(400px); -moz-transition: none; -webkit-animation-name: bounce; -webkit-animation-duration: 1s; -webkit-animation-iteration-count: 1; -webkit-transform: translate(400px); -webkit-transition: none; } #-moz-keyframes bounce { from { -moz-transform: translate(0px); -moz-animation-timing-function: ease-in; } 60% { -moz-transform: translate(400px); -moz-animation-timing-function: ease-out; } 73% { -moz-transform: translate(360px); -moz-animation-timing-function: ease-in; } 86% { -moz-transform: translate(400px); -moz-animation-timing-function: ease-out; } 93% { -moz-transform: translate(380px); -moz-animation-timing-function: ease-in; } to { -moz-transform: translate(400px); -moz-animation-timing-function: ease-out; } } #-webkit-keyframes bounce { from { -webkit-transform: translate(0px); -webkit-animation-timing-function: ease-in; } 60% { -webkit-transform: translate(400px); -webkit-animation-timing-function: ease-out; } 73% { -webkit-transform: translate(360px); -webkit-animation-timing-function: ease-in; } 86% { -webkit-transform: translate(400px); -webkit-animation-timing-function: ease-out; } 93% { -webkit-transform: translate(380px); -webkit-animation-timing-function: ease-in; } to { -webkit-transform: translate(400px); -webkit-animation-timing-function: ease-out; } } <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script> <img id="anim" src="http://hacks.mozilla.org/wp-content/uploads/2011/04/75px-Aurora210.png" width="75" height="75" /> See Mozilla Developer Network for more details and browser compatibility.
Yes, it is possible using native javascript. Take a look at this document Note, I'm linking to the "easeOut" section, since I think that represents a ball's bouncing a little better than their "bounce". Here's a good example, further down the same page.