Question: Why does my CPU register ~30% when blur is applied versus ~6% when no blur is applied to an animated object?
Details:
I have a set of randomly generated items on a page that have a CSS animation assigned (in a CSS file) and randomly generated values for width, height, and importantly, blur, applied inline.
CSS file styles looks like:
animation-name: rise;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-iteration-count: 1;
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
-webkit-transform: translate3d(0,0,0);
transform: translateZ(0);
width, height and blur are applied inline via style attribute.
<div class="foo" style="width:99px;height:99px;
filter:blur(2px);
-webkit-filter:blur(2px) opacity(0.918866247870028);
-moz-filter:blur(2px) opacity(0.918866247870028);
-o-filter:blur(2px) opacity(0.918866247870028);
-ms-filter:blur(2px) opacity(0.918866247870028);"></div>
With the blur enabled my CPU usage is ~30%. When I disable the blur, CPU usage goes down to ~6%.
What's happening here? Is chrome only able to GPU accelerate when no blur is applied? If so, why?
Update 1:
The animation rise looks as follows:
#keyframes rise {
0% {
transform: translateY(0px);
}
100% {
transform: translateY(-1000px);
}
}
I don’t think the blur is actually causing your issues, it just seems to make it more noticeable than before. The problem is that the transform: translateY in your animation is overwriting the transform: translateZ(0) you’re using to force GPU acceleration.
This is a timeline recording for the the code you’re running right now, notice how there’s all this activity on the main and raster threads:
Now compare this to a recording where I applied will-change: transform to the .foo:
No activity on the main and raster whatsoever.
There’s two steps to applying this fix:
Apply will-change: transform to .foo. This will let the browser know you intend to change that property and have it render that element on the GPU to account for this.
No versions of Edge and IE support will-change at the moment. Therefore we’ll use transform: translate3d(0, -1000px, 0); in the animation to force GPU acceleration. Note this is a hack, so we’ll detect support for will-change and use transform: translateY in browsers that support it.
Final code:
#keyframes rise {
0% {
transform: translate3d(0, 0, 0);
}
100% {
transform: translate3d(0, 1000px, 0);
}
}
#supports (will-change: transform) {
#keyframes rise {
0% {
transform: translateY(0px);
}
100% {
transform: translateY(1000px);
}
}
}
div {
width: 100px;
height: 100px;
background: #f00;
animation: rise forwards 2s linear infinite;
will-change: transform;
}
See here for a working version: http://jsbin.com/mosuvikoto/edit?html,css,output
Don't blur it in inline styles. Put your blur in the style file.
Related
I'm working on CSS and web development,but just face a something which i really don't understand it:
.header{
position: absolute;
width:60%;
top: 20%;
left: 50%;
transform: translateX(-50%);<------ executed after animation
text-align: center;
animation: moveUp 2s;
animation-fill-mode: backwards;
}
#keyframes moveUp{
0%{
opacity: 0;
transform:translateY(2rem);
}
100%{
opacity: 1;
transform: translateY(0rem);
}
}
so my problem here is the indicated line doesn't apply on ".header" until the animation gets applied in other word it applies animation first then translate -50% ,is there a priority of execution here or it is different thing?
Usually the styles are parsed from top to bottom, however this isn't the issue here.
What is happening in your case is the transform is being applied initially, but then it is being overridden by the animation. Once the animation is over, the element is reverting back to its default style which has the transform.
Essentially, even though the transform is applied at first, you don't see it until the element reverts to it after the end of the animation.
The only solution if you want to have the transform during the animation, is to include it in the animation itself.
#keyframes moveUp {
0 % {
opacity: 0;
transform: translate(-50%, 2rem);
}
100 % {
opacity: 1;
transform: translate(-50%, 0);
}
}
EDIT: To clarify, the order at which the styles are applied does not matter. Whether the animation or the transform is applied first, the result will be the same.
I think a source of your confusion is that the first transform is a translateX while the animation only does translateY. In both cases what is changing is the value of the transform property of the element. Therefore which axis the translation is on doesn't matter. First you set transform: translateX(-50%), but then once the animation kicks in, transform becomes translateY(2rem). The translateX part is removed from the transform, unless you include it in the animation like I have shown.
I am using css to do svg animations. The goal is the make a character move on a 2d isometric grid using js.
The svg in then drawn on canvas.
My issue is, while everything works fine on Chrome :
https://raw.githubusercontent.com/Lunacie/SquishySlug/master/screenshots/walk-chrome.gif
It doesn't work at all on Edge, which was to be expected, as Edge doesn't support svg css animations :
https://raw.githubusercontent.com/Lunacie/SquishySlug/master/screenshots/walk-edge.gif
However, interestingly enough, while css svg animations seem to work on Firefox, once I draw the svg on a canvas, it stops working and gets stuck on the first frame :
https://raw.githubusercontent.com/Lunacie/SquishySlug/master/screenshots/walk-firefox.gif
Here is a code excerpt of how I have been doing the animations :
#leg_x5F_back_x5F_top {
transform-box: fill-box;
-webkit-animation : leg_back_top 1.5s linear infinite;
animation : leg_back_top 1.5s linear infinite;
}
#keyframes leg_back_top {
0% {
-webkit-transform-origin: 100% 40%;
transform-origin: 100% 40%;
-webkit-transform: translate(10%, -10%) rotateZ(-10deg);
transform: translate(10%, -10%) rotateZ(-10deg);
}
[...]
80% {
-webkit-transform-origin: 20% 40%;
transform-origin: 20% 40%;
-webkit-transform: translate(-20%, 0%) rotateZ(30deg);
transform: translate(-20%, 0%) rotateZ(30deg);
}
}
So my question is : Is this behaviour normal and to be expected from Firefox? Maybe css animations drawn on canvas are not supported ? Or am I doing something wrong ?
Thank you in advance for your help.
Why does the following clipPath animate in Chrome but not Firefox?
http://jsfiddle.net/H8S3k/67/
.graph {
transform: translateY(150px);
animation: 2s ease-out 0s normal none infinite popup;
}
#keyframes popup {
0% {
transform: translateY(50px);
}
50% {
transform: translateY(0px);
}
100% {
transform: translateY(50px);
}
}
In SVG 1.1, only certain attributes were deemed to be stylable with CSS. These particular set of attributes were called "properties". You can see the list of designated properties here:
https://www.w3.org/TR/SVG/propidx.html
transform is not one of those, so it cannot be styled with CSS.
However in SVG 2, which is not yet finalised, all SVG attributes will probably be made stylable. Chrome has begun implementing this, however Firefox has not yet. That is why your example works in Chrome but not Firefox.
The rotate animation won't work with translate. I get, that I have to put translate in the same property with the rotate, but how is this possible when using keyframes? Code is like so:
#-webkit-keyframes rotating {
from{
-webkit-transform: rotate(0deg);
}
to{
-webkit-transform: rotate(360deg);
}
}
#keyframes rotating {
from{
transform: rotate(0deg);
}
to{
transform: rotate(360deg);
}
}
img{
-webkit-transform:translate(-50%,-50%);
transform:translate(-50%,-50%);
-webkit-animation: rotating 2s linear infinite;
animation: rotating 2s linear infinite;
position:absolute;
top:50%;
left:50%;
}
This will make the rotation, but it disables the translate. If I put the translate into the rotating animation, the translate is being animated as well(ofcourse).
The 2022+ answer
You can work around this by using individual property transforms which have pretty good browser support.
In short, use the properties like scale, translate, etc. instead of transform.
Side note: You don't need browser-specific properties for anything related to transforms or animations these days.
The original 2014 answer
The issue is that the transform in the animation is overriding the default transform:translate. In this case, you can combine them in the animation itself but it has to be hard coded.
#keyframes rotating {
from {
transform: translate(-50%,-50%) rotate(0deg);
}
to {
transform: translate(-50%,-50%) rotate(360deg);
}
}
If you need it to be dynamic, you can nest it in an element and animate one while not affecting the other - most likely translate the parent and rotate the child.
If you absolutely cannot have more than one element, you can affect the transform matrix for the element using JavaScript, in which case using an animation library like GSAP would be advantageous.
I am attempting to make a type of CSS only slide transition from one content section to another. In order to do so in an interesting way, I use CSS's perspective and rotateX to in essence lay down the page content. I then am trying to slide the content out towards the bottom of the screen using translateY
Separately, both the translateY and the rotateX work perfectly, no matter what the perspective is. However, when combined, it only works with certain perspectives based on the window size and rotateY value
In this jsFiddle it works as I would like it to in the window sizes I have tried. The problem is that I would like the perspective value to be lower, around 250px, but I cannot do so without breaking the animation.
I tried using a higher rotateY degree instead of making the perspective lower but the same issue occurs
#keyframes slide {
0% { transform: perspective(450px); }
25% { transform: perspective(450px) rotateX(30deg); }
50%,100% { transform: perspective(450px) rotateX(30deg) translateY(100%); }
}
I have tested this on CSS Deck and jsFiddle both in FireFox and Chrome and it seems to be a consistent issue
Can anyone provide me with a reason why this is happening and offer a work around?
Try setting the perspective as a separate rule on a parent element (as opposed to being part of the transform in the animation).
.parent {
perspective: 250px;
}
#keyframes slide {
25% { transform: rotateX(30deg); }
50%, 100% { transform: rotateX(30deg) translateY(100%); }
}
Updated fiddle: http://jsfiddle.net/myajouri/DYpnU/
My reasoning:
The perspective does not change during the animation so there's no point in having it as part of the animation.
Since your elements occupy 100% of the parent's area, setting the perspective on the parent should produce the same result as setting it on the elements themselves (inside transform).
It seems to solve your problem (see fiddle above).
UPDATE: after more experimentation, I found that explicitly setting the translateY(0) initial value in the animation would solve the issue as well.
#keyframes slide {
0% { transform: perspective(150px); }
25% { transform: perspective(150px) rotateX(30deg) translateY(0); }
50%, 100% { transform: perspective(150px) rotateX(30deg) translateY(100%); }
}
Updated fiddle: http://jsfiddle.net/myajouri/YJS3v/
Only a slight improvement over myajouri answer.
At leats in Chrome, you can write
#-webkit-keyframes slide {
0% { -webkit-transform: perspective(50vh); }
10%,15% { -webkit-transform: perspective(50vh) rotateX(30deg) translateY(0%); }
50%,100% { -webkit-transform: perspective(50vh) rotateX(30deg) translateY(100%); }
}
Setting the perspective to the viewport height should make it more responsive that your current setting
demo
(Untested in other browsers)