When an animation is triggered via the javascript API, it requires a list of keyframes. This example is from Vuetify.
const animation = animate(el, [{
transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
opacity: 0
}, {
transform: '',
}], {
duration: 225 * speed,
easing: deceleratedEasing
});
These keyframes are implicit, as they do not both include opacity, nor both transform.
On older browswers (i.e., Chrome 69.0), this is a problem, and one needs to be explicit about animation keyframes. Thus, it throws an exception for the above code. However, it works if changed to
const animation = animate(el, [{
transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
opacity: 0
}, {
transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
opacity: 1
}], {
duration: 225 * speed,
easing: deceleratedEasing
});
How does modern CSS decide the values for the implicit keyframes, and how can I find out that information for a generic keyframe with opacity, transform, and offset?
From this page, "Implicit to/from keyframes are supported from Chrome v84".
I tried entering values myself, but I have no idea what the implicit/default keyframes/opacities should be.
Related
I have a weird issue where if I play an animation on one of my 3 monitors, YouTube videos on any other monitor crashes. I did fix this by disabling hardware acceleration in chrome://flags, but a new update in Chrome recently made the issue come back, and I haven't found a way to fix it yet. Animations occur on places like Facebook ("Someone is typing a comment...") or basically any website with a animation-duration CSS property on something (spinners are probably the most used form of animations I guess).
I can verify this simply by placing this CSS on any page:
* {
animation-duration: 0s !important;
}
Boom instantly all my videos play perfectly. No issues what so ever. I could add this to an userscript (or make a tiny extension), and I don't think it would mess up too much, but I'm more interested in knowing if there's a Chrome flag that can disable animations completely? I don't know if animation-duration works for any animation.
From what I know Chrome has no such option.
But, I was able to make something similar using the Tampermonkey extension.
Simply add the following script to the extension:
// ==UserScript==
// #name Animation Stopper
// #description Stop all CSS animations on every website.
// #author Ba2siK - https://stackoverflow.com/users/7845797
// #match *://*/*
// #grant GM_addStyle
// #run-at document-end
// ==/UserScript==
GM_addStyle(`
*, *:before, *:after {
transition-property: none !important;
transform: none !important;
animation: none !important;
}`
);
console.log("Animation Stopper ran successfully");
Make sure it's enabled at the extensions bar
Note: it won't work on iframe elements.
Btw, You can disable the window animation in chrome by adding the --wm-window-animations-disabled command-line flag.
* {
animation: none !important;
}
/* turn off animation on all elements*/
Allow me to answer my own question. Setting animation-duration to 0s !important seems to be working. However, I added animation-play-state: paused for good measure as well.
I made an userscript, and found that it doesn't target the Shadow DOM, so I have to traverse through every element, check if it's a shadow root, and then add the CSS. Since elements can be added to a page dynamically, I decided to do this every second. So far I cannot see a performance difference, even on pages with a lot of elements.
Install TamperMonkey (Chrome) or GreaseMonkey (Firefox) to use this:
// ==UserScript==
// #name Disable all animations
// #version 1.0
// #author mortenmoulder
// #include *
// #grant GM_addStyle
// #grant GM_addElement
// ==/UserScript==
//remove animations globally
GM_addStyle("* { animation-duration: 0s !important; animation-play-state: paused; }");
var ignoreElements = [];
//remove animations inside shadow DOM elements
function findShadowRoots(elements) {
for (var i = 0; i < elements.length; i++) {
if(elements[i].shadowRoot) {
if(ignoreElements.includes(elements[i].shadowRoot) == false) {
GM_addElement(elements[i].shadowRoot, 'style', { textContent: '* { animation-duration: 0s !important; animation-play-state: paused;' });
ignoreElements.push(elements[i].shadowRoot);
}
findShadowRoots(elements[i].shadowRoot.querySelectorAll("*"));
}
}
}
//remove animations every 1 second
setInterval(() => {
var allNodes = document.querySelectorAll('*');
findShadowRoots(allNodes);
}, 1000);
I have two divs I want to transition across the screen to make it look like an infinite loop. I have worked with adjusting setTimeouts and setting an event listener (transitionend), but I keep getting a huge gap between the divs. Here is a link to the js fiddle using the event listener. Below is code I used without using the event listener.
Javascript
var boxWrap = $('#one');
var boxWrap2 = $('#two');
boxWrap.addClass('start')
boxWrap2.addClass('start')
setInterval(function () {
boxWrap.removeClass('start')
boxWrap[0].offsetTop
boxWrap.addClass('start')
}, 35000)
setInterval(function () {
boxWrap2.removeClass('start')
boxWrap2[0].offsetTop
boxWrap2.addClass('start')
}, 35000)
CSS
.boxWrapper.start {
transition: right linear 35s;
right: calc(-144vmin - 80vmin - 200vmin);
}
.boxWrapper.boxWrapper2.start {
transform: translateX(-224vmin);
transition: right linear 35s;
right: calc(-144vmin - 80vmin - 200vmin);
}
Tell me if there is anything you need.
I've used two keyframe animations in CSS. One moves from left to right and the other one uses exact the same values - but reversed.
#keyframes moveLeft
{
from {transform: translate3d(50px, 0, 0);}
to {transform: translate3d(0px, 0, 0);}
}
#keyframes moveRight
{
from {transform: translate3d(0px, 0, 0);}
to {transform: translate3d(50px, 0, 0);}
}
However, I wonder whether it's possible to use one keyframe animation only. but as soon as I add animation-direction: reverse, the animation does only play once. It probably saves the information that it has been used once before.
So: can I reset this information somehow? Or is there any possibility to use one animation twice in different directions? (without using JS)
http://jsfiddle.net/vrhfd66x/
No, there is no way to restart the animation using CSS alone. You'd have to use JavaScript to remove the animation from the element and then re-apply it to the element (after a delay) for it to restart.
The below is what the W3C's CSS3 Animation Spec says (in a different context, but the point should hold good for this case also):
Note also that changing the value of ‘animation-name’ does not necessarily restart an animation (e.g., if a list of animations are applied and one is removed from the list, only that animation will stop; The other animations will continue). In order to restart an animation, it must be removed then reapplied.
emphasis is mine
This CSS Tricks Article by Chris Coiyer also indicates the same and provides some JS solutions for restarting an animation. (Note: The article has a reference to Oli's dabblet which claims that altering properties like duration, iteration count makes it restart on Webkit but it seems to be outdated as they no longer work on Chrome).
Summary:
While you have already touched upon the following, I am going to re-iterate for completeness sake:
Once an animation is applied on the element, it remains on the element until it is removed.
UA does keep track of the animation being on the element and whether it has completed or not.
When you apply the same animation on :checked (albeit with a different direction), the UA does nothing because the animation already exists on the element.
The switch of positions (instantaneous) while clicking the checkbox is because of the transform that is applied within the :checked selector. The animation's presence makes no difference.
Solutions:
As you can see from the below snippet, achieving this with a single animation is pretty complex even when using JavaScript.
var input = document.getElementsByClassName("my-checkbox")[0];
input.addEventListener('click', function() {
if (this.checked) {
this.classList.remove('my-checkbox');
window.setTimeout(function() {
input.classList.add('anim');
input.classList.add('checked');
}, 10);
} else {
this.classList.remove('anim');
window.setTimeout(function() {
input.classList.remove('checked');
input.classList.add('my-checkbox');
}, 10);
}
});
input {
transform: translate3d(50px, 0, 0);
}
.my-checkbox {
animation: moveLeft 1s;
animation-direction: reverse;
}
.checked {
transform: translate3d(0px, 0, 0);
}
.anim{
animation: moveLeft 1s;
}
#keyframes moveLeft {
from {
transform: translate3d(50px, 0, 0);
}
to {
transform: translate3d(0px, 0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<input type="checkbox" class="my-checkbox">
So, the best option (if you want to stick to CSS animations) is to use two different animations.
Alternately, you could also have a look at Marcelo's comment. If the actual use-case is exactly what is provided in the fiddle then transition would suffice and animation isn't required. Transitions can work both in forward and reverse directions by nature and hence would be a safer bet.
I've used two keyframe animations in CSS. One moves from left to right and the other one uses exact the same values - but reversed.
#keyframes moveLeft
{
from {transform: translate3d(50px, 0, 0);}
to {transform: translate3d(0px, 0, 0);}
}
#keyframes moveRight
{
from {transform: translate3d(0px, 0, 0);}
to {transform: translate3d(50px, 0, 0);}
}
However, I wonder whether it's possible to use one keyframe animation only. but as soon as I add animation-direction: reverse, the animation does only play once. It probably saves the information that it has been used once before.
So: can I reset this information somehow? Or is there any possibility to use one animation twice in different directions? (without using JS)
http://jsfiddle.net/vrhfd66x/
No, there is no way to restart the animation using CSS alone. You'd have to use JavaScript to remove the animation from the element and then re-apply it to the element (after a delay) for it to restart.
The below is what the W3C's CSS3 Animation Spec says (in a different context, but the point should hold good for this case also):
Note also that changing the value of ‘animation-name’ does not necessarily restart an animation (e.g., if a list of animations are applied and one is removed from the list, only that animation will stop; The other animations will continue). In order to restart an animation, it must be removed then reapplied.
emphasis is mine
This CSS Tricks Article by Chris Coiyer also indicates the same and provides some JS solutions for restarting an animation. (Note: The article has a reference to Oli's dabblet which claims that altering properties like duration, iteration count makes it restart on Webkit but it seems to be outdated as they no longer work on Chrome).
Summary:
While you have already touched upon the following, I am going to re-iterate for completeness sake:
Once an animation is applied on the element, it remains on the element until it is removed.
UA does keep track of the animation being on the element and whether it has completed or not.
When you apply the same animation on :checked (albeit with a different direction), the UA does nothing because the animation already exists on the element.
The switch of positions (instantaneous) while clicking the checkbox is because of the transform that is applied within the :checked selector. The animation's presence makes no difference.
Solutions:
As you can see from the below snippet, achieving this with a single animation is pretty complex even when using JavaScript.
var input = document.getElementsByClassName("my-checkbox")[0];
input.addEventListener('click', function() {
if (this.checked) {
this.classList.remove('my-checkbox');
window.setTimeout(function() {
input.classList.add('anim');
input.classList.add('checked');
}, 10);
} else {
this.classList.remove('anim');
window.setTimeout(function() {
input.classList.remove('checked');
input.classList.add('my-checkbox');
}, 10);
}
});
input {
transform: translate3d(50px, 0, 0);
}
.my-checkbox {
animation: moveLeft 1s;
animation-direction: reverse;
}
.checked {
transform: translate3d(0px, 0, 0);
}
.anim{
animation: moveLeft 1s;
}
#keyframes moveLeft {
from {
transform: translate3d(50px, 0, 0);
}
to {
transform: translate3d(0px, 0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<input type="checkbox" class="my-checkbox">
So, the best option (if you want to stick to CSS animations) is to use two different animations.
Alternately, you could also have a look at Marcelo's comment. If the actual use-case is exactly what is provided in the fiddle then transition would suffice and animation isn't required. Transitions can work both in forward and reverse directions by nature and hence would be a safer bet.
I'm having trouble with Safari creating an effect that mimics bubbles floating into the air, except with feathers. I've omitted some code to get to the gist of things. The url to the work-in-progress is here.
Here are the webkit styles for my animated objects.
#-webkit-keyframes f1 {
100% {
-webkit-transform: translateX(-25px) translateY(-350px);
}
}
.feather {
/* other styling omitted */
-webkit-animation-duration: 7s;
-webkit-animation-timing-function: linear;
}
And the javascript to create a bunch of objects.
animateFeathers = function() {
var $feather = $('<img>'),
$feather.addClass('feather animated');
$feather.attr('src','img/feather.png');
$feather.css('-webkit-animation-name','f1');
$featherContainer.append($feather);
setTimeout(function() {
$feather.remove();
}, 9000);
// random time to create next feather
var rTimeout = Math.random() * maxTime + minTime;
setTimeout(animateFeathers, rTimeout);
}
If you visit the link in Chrome or Firefox you'll see the intended effect. However in Safari (again, mobile or desktop) the feathers stack and only animate in a group every 7 seconds. I'd like for them to begin their animation as soon as they are inserted into the DOM. Any ideas on this?
Had to resort to using a canvas as I really couldn't get performance working on Safari. Took quite a few hours, but its working:
http://poetreatapp.com/