Is it possible to turn off all CSS animations in Chrome? - css

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);

Related

transitioning between images in vuejs

I want to create a smooth transition between 2 images with a legend.
The images come from an object-array of images.
Because works only on single tags and components, I've created a component to define the image+legend.
<transition>
<home-image :slide="slide" :key="slide"></home-image>
</transition>
The classes I define are like this
.v-enter-active,
.v-leave-active {
transition: opacity 2s ease-in-out;
}
.v-leave,
.v-enter-to {
opacity: 1;
}
.v-enter,
.v-leave-to {
opacity: 0;
}
The new image is returned by a method
updateSlide() {
this.slide = this.entries[ Math.floor( Math.random() * this.entries.length ) ];
}
where entries is my array defined in data
this.slide is updated in regular intervals, every 10seconds like this, which is defined in the created() section
this.updateSlide();
this.uSlide = setInterval( this.updateSlide, 10000);
The code works, in the sense that a new image is loaded in this.slide every 10 seconds.
However, the transitions work only "half-way".
There is no transition fading out: the "old image" disappears and makes way for the new image fading in.
However, what I'd like is a smooth transition from one to the other.
I've tried more than a couple of ideas including using mode="out-in" and "in-out" but nothing works as I want.
What am I overlooking?

CSS Animation Not Working As Expected With Image element In Safari

Below is a minimum mockup of a bug that I'm experiencing in Safari.
Expected behaviour: The code is supposed to display a placeholder while another image loads and then fade-in that image while removing the placeholder.
placeholder -> fading in loaded image
Actual behaviour:
Works as expected in Chrome and Mozilla but fails in Safari, resulting in the following effect:
placeholder -> white screen -> loaded image
Can somebody help me figure out why this is happening in Safari please? (try running below example in chrome or mozilla vs safari to see for your self.)
const image = new Image();
image.onload = () => {
document.getElementById('placeholder').remove();
const el = document.createElement('img');
el.setAttribute('src', 'http://deelay.me/1000/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg');
el.setAttribute('width', '150');
el.setAttribute('height', '150');
el.style = `
animation-name: testAnimation;
animation-duration: 0.3s;
animation-iteration-count: 1;
animation-timing-function: ease-in;
background: red;
`;
document.body.appendChild(el);
}
image.src = 'http://deelay.me/1000/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg';
#placeholder {
background: #eee;
}
#-webkit-keyframes testAnimation {
0% {
opacity: 0.25;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
<img id="placeholder" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' width%3D'200' height%3D'300' viewBox%3D'0 0 200 300'%2F%3E" width="150" height="150">
(
Another weird behaviour is that if animation-duration gets increased to around 3-4 seconds then the image does fade-in but the white screen is still there, i.e.
placeholder -> white screen -> fading in loaded image
)
update:
After playing around with img’s background color it seems like in Safari the animation begins taking effect around 1s before the image even begins getting rendered to the screen.
hence the white flick if the real image doesn't have a background color like the placeholder image does and hence why after adding a background color to the real image that background color becomes visible around 1 sec earlier before the image even starts displaying
and hence the fade effect starting to take place around 1 sec earlier before the image even starts displaying
Whereas in Chrome and Mozilla the animation appears to be perfectly in sync with the image.
Run updated code to see for yourself
(it also only seems to happen with <img>, I've tested it with some other elements (still inside of image.onload) and they work as expected.)
update 2: See the fix in the answer below together with an explanation
This was fixed by adding another onload event this time on the image element rather than on the explicit Image object and putting the image.onload listener inside of it.
Which seems to suggest that in Safari, animation and styles are applied as soon as the <img> is added to the DOM - before it is fully loaded (its onload event called.)
This can be tested by giving the <img> a background color and seeing it show up together with the animation as soon as the element is added to the DOM and seeing that it takes an extra second until the image itself becomes visible
You can also see the same effect happen without using any animation at all just by giving the <img> a background color
(a bug in Safari? My Safari version: Version 11.0.2 (13604.4.7.1.3))
Edit: Actually the problem seems to be caused by caching, Safari doesn't seem to cache the pre-loaded proxied image while other browsers do cache it. Safari seems to fire another request for that image when it gets rendered to the screen - hence the styles being visible prior to seeing the actual image since the image is still being downloaded.
Edit 2: Upon further investigation it seems like Safari is actually the only one out of those 3 browsers that is behaving as expected - this is because the image's HTTP response contains a Cache-Control: no-cache, must-revalidate header explicitly instructing the browser to not cache the image.
const image = new Image();
const el = document.createElement('img');
el.setAttribute('src', 'http://deelay.me/500/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg');
el.setAttribute('width', '150');
el.setAttribute('height', '150');
el.style = `
animation-name: testAnimation;
animation-duration: 1s;
animation-iteration-count: 1;
animation-timing-function: ease-in;
background-color: red;
`;
el.onload = () => {
image.onload = () => {
document.getElementById('placeholder').remove();
document.body.appendChild(el);
}
}
image.src = 'http://deelay.me/500/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg';
#placeholder {
background: #eee;
}
#-webkit-keyframes testAnimation {
0% {
opacity: 0.25;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
<img id="placeholder" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' width%3D'200' height%3D'300' viewBox%3D'0 0 200 300'%2F%3E" width="150" height="150">
This appears to be related to the specific server/image you are using. I tried changing just the image URL (to something on wikimedia.org, just for testing purposes), and the animation began working as expected in Safari 11.0.2 (13604.4.7.1.6).
Pre-loading the image may help... or even better (all of this assuming you have proper usage rights, of course), you can try copying the image to your web server so it can be loaded locally. Essentially, you're just remedying the fact that Safari has finished running the animation by the time it can load the image from the remote server. You could also try using window.onload instead of image.onload, to force all external resources to be loaded before it runs.

Pause/play ALL the CSS animations of every child element

I'm creating a dashboard page which is full of CSS animations. From Bootstrap stuff (animated progress bars) to custom animations.
When you click some of the elements, a near full-screen modal is triggered, which overlaps all the animations, so I want to temporarily pause them all (because of possible performance issues) by adding/removing a class to one of the top elements, and using CSS to pause all animations when that class is set.
This solution would use only a single line of js, just to toggle the class on opening the modal.
My template looks somewhat like this:
<body>
<div class="modal">
<!-- Modal code -->
</div>
<div class="app">
<!-- Template -->
</div>
</div>
Is it possible to add a class to .app which pauses every CSS animation in every child element?
Note 1:
I know you can use the exact opposite of what I request: namely, have a default .animation-play class to one of the top elements, and prefix every child element with an animation with this class, and then remove this class to pause every animation. Just like:
app.animation-play .somediv .somediv .element {
// animation code
}
app.animation-play .somediv .element {
// animation code
}
app.animation-play .somediv .somediv .somediv .somediv .element {
// animation code
}
But then I have to edit a lot of CSS code, and it doesn't look very nice either.
Note 2:
I'm also open for a JS solution, but I would heavily prefer a pure CSS way of achieving this.
You can use a universal selector to target everything when a class of 'paused' is added to your app wrapper, however many CSS linters still warn against using these due to performance impacts.
To be honest the impact is probably minimal these days and many CSS resets for example use them.
You could use something like:
.app.paused * {
animation: none;
}
EDIT:
Looking through the comments above it seems as though the above selector doesn't have enough precedence to overwrite the animations so '!important' has been added.
.app.paused * {
animation: none !important;
transition: none !important;
}
However this is generally not a great idea, I always try to avoid using '!important' at all costs due to the difficulty in maintaining the stylesheet with these selectors in place. If you can overwrite the animations with a greater precedence then it would be better to do so rather than using '!important'.
EDIT 2:
As you mentioned you were open to JS solutions, here is some JS that should clear all the animations within a given selector. I'm not sure what the performance impact of doing it this way is but I added it here just in case someone else prefers to do it only using JS:
let stopAnimationsWrap = document.querySelector('.app');
let stoppedAnims = [];
// Stop animations
document.querySelector('.stop').addEventListener('click', () => {
let appAllEls = stopAnimationsWrap.querySelectorAll('*');
let allElsAr = Array.prototype.slice.call(appAllEls);
allElsAr.forEach((thisEl) => {
let elClass = thisEl.classList[0];
let cs = getComputedStyle(thisEl, null);
let thisAnimation = cs.getPropertyValue('animation-name');
if (thisAnimation !== 'none') {
stoppedAnims.push([elClass, {
'animationName': thisAnimation
}]);
thisEl.style.animationName = 'none';
}
});
});
// Start animations
document.querySelector('.start').addEventListener('click', () => {
stoppedAnims.forEach((thisEl) => {
let domEl = '.' + thisEl[0];
stopAnimationsWrap.querySelector(domEl).style.animationName = thisEl[1].animationName;
});
});
Fiddle:
https://jsfiddle.net/vu6javb2/14/
.app {
-webkit-animation-play-state: paused; /* Safari 4.0 - 8.0 */
animation-play-state: paused;
}
on hover:
.app:hover {
-webkit-animation-play-state: paused; /* Safari 4.0 - 8.0 */
animation-play-state: paused;
}

CSS background color is not applied consistently to visited links. CSS added by GM_addStyle

I'm noticing some odd behavior with CSS added by GM_addStyle(). I have the following userscript:
// ==UserScript==
// #name Reddit
// #namespace http://example.com
// #include http://www.reddit.com/
// #grant GM_addStyle
// #version 1
// ==/UserScript==
GM_addStyle("a:visited { background-color: yellow !important; }");
Now, I'd expect the behavior to either work for all links or work for no links (due to the security patch), but what I get is an inconsistent behavior in that it works for some link, but not other.
Could anyone explain the above behavior for me?
From Privacy and the :visited selector at MDN:
Only the following properties can be applied to visited links:
color
background-color
border-color (and its sub-properties)
outline-color
The color parts of the fill and stroke properties
In addition, even for the properties you can set for visited links, you won't be able to change the transparency between unvisited and visited links, as you otherwise would be able to using rgba() or hsla() color values or the transparent keyword.
Apparently, this means, in Firefox, that in order for you to change the background color, the link must first have a background (which you can't add using the :visited selector). So set the background before trying to style visited links' background color.
This works for me:
// ==UserScript==
// #name _Reddit, style visited links
// #include http://www.reddit.com/*
// #grant GM_addStyle
// #version 1
// ==/UserScript==
GM_addStyle (
/* For precision, only prime the desired links, that don't
otherwise have a BG.
*/
"a.title { background: white; }"
+ "a:visited { background-color: yellow !important; }"
);
Note that I just "primed" the links that I was explicitly interested in, that didn't already have a background. Hence the a.title {... instead of a {....
Also note that for just changing styles, Stylish is usually a better bet (performance and ease of setup).

Safari (mobile + desktop) grouping CSS Keyframe Animations

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/

Resources