How to run a CSS3 keyframe animation once, and only when triggered? - performance

I would like to implement an HTML5 animation that involves a bit more than just moving an item from point A to point B. That's why I am considering using keyframes rather than transitions. However, I just want the animation to run once, and only when triggered.
The problem is twofold:
1) When the animation is finished, the item returns to its start position. Is there a way to make it stay at the end position until further notice?
2) Is there a way to restart the animation later from Javascript?
The other possible solution I see would be to chain a few transitions using the onTransitionEnd event.
What is the best solution here considering performance? I am only targeting Webkit browsers, including mobile.
EDIT: based on the comment by #Christofer-Vilander I made a JSfiddle, which basically does what I wanted. Thanks!
HTML:
<button id="start">Start</button> <button id="reset">Reset</button>
<br/>
<div id="ball" class="ball"></div>
Javascript:
document.getElementById('start').addEventListener('click', function(e) {
document.getElementById('ball').classList.add('remove');
});
document.getElementById('reset').addEventListener('click', function(e) {
document.getElementById('ball').classList.remove('remove');
});
CSS:
.ball {
width:100px;
height:100px;
border-radius:100px;
background-color:darkred;
position:absolute;
top:100px;
left:200px;
}
#-webkit-keyframes slide {
from { top:100px; left:200px; }
to { top:100px; left:-100px; }
}
.remove {
animation: slide 1s linear;
-webkit-animation: slide 1s linear;
-webkit-animation-iteration-count: 1;
-webkit-animation-fill-mode: forwards;
}

Add a class in the html element with Javascript, and the desired css animation ruleset for this class. Use animation-fill-mode: forwards; for the animation to run once.
Then, remove the class from the element to re-run animation onClick.

Related

Vuejs 2 removing from array (splice) not animating with transition

I have a vue component:
<transition-group name="list">
<task v-for="task in tasks" v-bind:key="task.id" v-bind:task="task" class="list-task"></task>
</transition-group>
With a simple transition:
.list-task {
transition: all 0.5s;
}
When I add an element to the tasks array with unshift I get a nice animation, where the existing elements are sliding down to make room for the new element.
However, when I remove an element from the array with splice, that element just just suddenly disappears.
How can I make it animate out like with adding an element?
You probably forgot to specify the transition classes. This will give you a basic fade-out:
.list-leave-active {
transition: all 0.5s;
opacity: 0;
}
Please refer to the (excellent) docs on Transition Classes.

What is best practice for handling resize events in a polymer element?

I'm trying to create a "Viewport" type element extended from a Canvas element. I intended for it to fill the parent container, but that seems not very trivial.
The canvas element does not work with style="width:100%; height:100%" (it will revert to a default value of 300x150 pixels if the special Canvas width and the height attributes are not set, or it will go to 100x100 pixels if I try to set those attributes to "100%". This leaves me with the task of manually setting the width of the canvas element according to the size of the parent element. However I am at a loss when trying to figure out a way to access a resize event I could add a handler to from the perspective of the custom element. I don't seem to get access to window.on.resize from anywhere within the custom element. Do I have to do this from the outside?
Here is an example polymer element definition:
<polymer-element name="canvas-viewport">
<template>
<style>
#host{
:scope {
margin:0px;
padding:0px;
display:block;
position:relative;
width:100%;
height:100%;
background:limegreen;
overflow:visible;
border:0;
}
}
div {
border:0;
margin:0px;
padding:0px;
width:100%;
height:100%;
}
</style>
<div id="container">
<canvas width="{{wpWidth}}" height="{{wpHeight}}" id="theCanvas"></canvas>
</div>
</template>
<script type="application/dart" src="canvas_viewport.dart"></script>
</polymer-element>
Here is some dart code in the accompanying polymer class definition for trying to handle the resize that I made based on a suggested solution to this question.
#override
void attached() {
super.attached();
viewPortContainer = shadowRoot.querySelector("#container");
window.onResize.listen(resizecontainer);
}
void resizecontainer(Event e){
wpWidth = viewPortContainer.clientWidth;
wpHeight = viewPortContainer.clientHeight;
print("resizing Width:$wpWidth , Height:$wpHeight ");
}
However this results in a bug where the height grows by three pixels on each resize event, even though margins and paddings are set to zero.
OnResize works for me inside a custom element.
#override
void attached() {
super.attached();
window.onResize.listen((e) {
print(e.currentTarget.innerWidth);
});
}
This is how I will achieve this in Polymer.
connectedCallback() {
super.connectedCallback();
this._onResize = this.onResize.bind(this);
window.addEventListener("resize", this._onResize);
}
onResize(e) {
console.log('width', e.currentTarget.innerWidth);
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener("resize", this._onResize);
}

Using a CSS image sprite for hover effect without the scrolling animation

I'm using a sprite image to change the background on hover and click (the .keepImage class is for the click). It all works, but when the background picture changes it scrolls over to the correct position. Is there a way to do it without the scrolling motion?
JS:
<script>
$(document).ready(function(){
$("a.doing").click(function() {
$(this).siblings(".keepImage").removeClass("keepImage");
$(this).addClass("keepImage");
});
});
</script>
CSS:
a.doing {
width: 229px;
height: 202px;
margin-right: 8px;
background: url(http://localhost:8000/img/manifesto/spr_doing.png) 0 0;
}
a.doing:hover, a.doing.keepImage {
background: url(http://localhost:8000/img/manifesto/spr_doing.png) -229px 0;
}
I think, somewhere in your css you have the transition property specified. Usually when you have a transition property specified like this: "transition: all 500ms ease;", the background position will change with a scrolling effect. If you want to prevent this scrolling from happening, then you can either remove the transition property completely, or you can use transition only for the properties you want to animate like - border, color etc.. but not background. If you can somehow provide a link to your page, or give the html mark up and css, it will help. Thanks.

firefox transitions breaking when parent overflow is changed

i came across an issue today and it took me so long to debug, I couldn't find a solution anywhere online so I thought it would be useful to document
It seems that transitions do not work on Firefox if the parent's "overflow" property is changed together with the transition - ie:
.parent { overflow: hidden; }
.parent:hover { overflow: visible; }
.child { opacity: 1; transition: opacity 1s linear; }
.parent:hover .child { opacity: 0; }
The transitions will not work on the child. Remove the "overflow:visible" property from the hovered parent, and everything is ok. It seems that changing the overflow on the child itself does not cause any issues, which is weird.
Here's a js fiddle for this http://jsfiddle.net/qzMj9/13/
does anyone know why this happens? is it a ff bug or the correct functionality? it works on webkit!
This looks like https://bugzilla.mozilla.org/show_bug.cgi?id=625289 to me: the parent is having its CSS boxes reconstructed, which loses the old computed style on the child, which means no transition start, since that's triggered by computed style changes.

changing css3 animation iteration count from infinite does nothing

I have a css3 animation running with the iteration count set to infinite.
based on a click event I want to stop the animation but changing the iteration count does nothing. can anyone suggest a better solution?
Thanks
Ian
Put your animation in a class sepeared from the styling, i.e.
.box {
height: 100px;
width: 100px;
background-color: #000;
}
.box.animated {
-webkit-animation...
}
and then remove class animated on click.

Resources