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.
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.
I am trying to create a "cube" effect where i can toggle between three objects and create the feeling of turning a cube.
Works fine with 2 sides, but i am stuck trying to add a third. Can someone please explain why the third site floats away?
I guess i am doing something wrong with item-3? But i just can't figure it out
.item-1{
-webkit-transform: translateZ(50px);
transform: translateZ(50px);
}
.item-2{
-webkit-transform: rotateX(-90deg) translateZ(-50px);
transform: rotateX(-90deg) translateZ(-50px);
}
.item-3{
-webkit-transform: rotateX(-180deg) translateZ(-50px);
transform: rotateX(-180deg) translateZ(-50px);
}
Live example:
http://jsfiddle.net/esbeka9t/
There you go:
Just change your .item-3 class like this:
-webkit-transform: translateZ(-50px) rotateX(-180deg) translateY(200px);
transform: translateZ(-50px) rotateX(-180deg) translateY(200px)
It seems your .items are positioned relative to each other. Giving .item a position: absolute, a fixed width and changing the translate values just a bit on your .item classes should solve the issue. Here is a modified version of your example to illustrate this.
I'm trying to build a cube with CSS3 3D Transform..
For this example I have only 2 faces :
<section id="header-cube-container">
<div id="header-cube">
<figure></figure>
<figure></figure>
</div>
</section>
With every other browser I get a good result, but it's weird with IE 11.
I have a good 3D translate and rotate on the green face (1), but the red face (2) perpendicular doesn't display in 3D. It's only the projection of the red face on the green face.
You can see the result on this fiddle.
PS : I make a rotation of 100deg and not 90 to see the projection of the red face on the green face (if the angle was 90, the projection isn't visible).
Thank you all!
IE doesn't support transform-style: preserve-3d yet.
You have to remove the transform from #header-cube and apply it to each of the figure children. Unfortunately IE already uses the non-prefixed properties, so you either can't use transform-3d at all or have to define the prefixed properties last.
From the IE transforms documentation:
At this time, Internet Explorer 10 does not support the preserve-3d
keyword. You can work around this by manually applying the parent
element's transform to each of the child elements in addition to the
child element's normal transform.
JSFiddle: http://jsfiddle.net/TTDH7/17/
#header-cube {
transform-style: preserve-3d;
transform: rotateX(43deg) rotateZ(130deg);
}
figure:nth-child(1) {
transform: translateZ(-16px);
}
figure:nth-child(2) {
transform: rotateY(-100deg) translateZ(-16px);
}
becomes:
#header-cube {
transform-style: preserve-3d;
-ms-transform-style: none;
transform: rotateX(43deg) rotateZ(130deg);
-ms-transform: none;
}
figure:nth-child(1) {
transform: translateZ(-16px);
-ms-transform: rotateX(43deg) rotateZ(130deg)
translateZ(-16px);
}
figure:nth-child(2) {
transform: rotateY(-100deg) translateZ(-16px);
-ms-transform: rotateX(43deg) rotateZ(130deg)
rotateY(-100deg) translateZ(-16px);
}
I have some CSS that on hover, a CSS transition effect will moves a div.
The problem, as you can see in the example, is that the translate transition has the horrible side effect of making the image in the div move by 1px down/right (and possibly resize ever so slightly?) so that it appears out of place and out of focus...
The glitch seems to apply the whole time the hover effect is applied, and from a process of trial and error I can safely say only seems to occur when the translate transition moves the div (box shadow and opacity are also applied but make no difference to the error when removed).
The problem only seems to happen when the page has scrollbars. So the example with just one instance of the div is fine, but once more identical divs are added and the page therefore requires a scrollbar the problem strikes again...
2020 update
If you have issues with blurry images, be sure to check answers from below as well, especially the image-rendering CSS property.
For best practice accessibility and SEO wise you could replace the background image with an <img> tag using object-fit CSS property.
Original answer
Try this in your CSS:
.your-class-name {
/* ... */
-webkit-backface-visibility: hidden;
-webkit-transform: translateZ(0) scale(1, 1);
}
What this does is it makes the division to behave "more 2D".
Backface is drawn as a default to allow flipping things with rotate
and such. There's no need to that if you only move left, right, up, down, scale or rotate (counter-)clockwise.
Translate Z-axis to always have a zero value.
Chrome now handles backface-visibility and transform without the -webkit- prefix. I currently don't know how this affects other browsers rendering (FF, IE), so use the non-prefixed versions with caution.
You need to apply 3d transform to the element, so it will get its own composite layer.
For instance:
.element{
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
or
.element{
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
More about layer creation criteria you can read right here: Accelerated Rendering in Chrome
An explanation:
Examples (hover green box):
Problem: Transition may cause blink effect on sibling elements (OSx Lion, Chrome 30)
Solution: An element on its own composite layer
When you use any transition on your element it cause browser to recalculate styles, then re-layout your content even if transition property is visual (in my examples it is an opacity) and finaly paint an element:
The issue here is re-layout of the content that can make an effect of "dancing" or "blinking" elements on the page while transition happens.
If you will go to settings, check "Show composite layers" checkbox and then apply 3d transform to an element, you will see that it gets it's own layer which outlined with orange border.
After element gets its own layer, browser just needs to composite layers on transition without re-layout or even paint operations so problem have to be solved:
Had the same problem with embeded youtube iframe (Translations were used for centering iframe element). None of the solutions above worked until tried reset css filters and magic happened.
Structure:
<div class="translate">
<iframe/>
</div>
Style [before]
.translate {
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
}
Style [after]
.translate {
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
filter: blur(0);
-webkit-filter: blur(0);
}
I recommended an experimental new attribute CSS I tested on latest browser and it's good:
image-rendering: optimizeSpeed; /* */
image-rendering: -moz-crisp-edges; /* Firefox */
image-rendering: -o-crisp-edges; /* Opera */
image-rendering: -webkit-optimize-contrast; /* Chrome (and Safari) */
image-rendering: optimize-contrast; /* CSS3 Proposed */
-ms-interpolation-mode: nearest-neighbor; /* IE8+ */
With this the browser will know the algorithm for rendering
Just found another reason why an element goes blurry when being transformed. I was using transform: translate3d(-5.5px, -18px, 0); to re-position an element once it had been loaded in, however that element became blurry.
I tried all the suggestions above but it turned out that it was due to me using a decimal value for one of the translate values. Whole numbers don't cause the blur, and the further away I went from the whole number the worse the blur became.
i.e. 5.5px blurs the element the most, 5.1px the least.
Just thought I'd chuck this here in case it helps anybody.
I cheated problem using transition by steps, not smoothly
transition-timing-function: steps(10, end);
It is not a solving, it is a cheating and can not be applied everywhere.
I can't explain it, but it works for me. None of another answers helps me (OSX, Chrome 63, Non-Retina display).
https://jsfiddle.net/tuzae6a9/6/
Scaling to double and bringing down to half with zoom worked for me.
transform: scale(2);
zoom: 0.5;
Try filter: blur(0);
It worked for me
I've tried around 10 possibly solutions. Mixed them up and they still didn't work correctly. There was always 1px shake at the end.
I find solution by reducing transition time on filter.
This didn't work:
.elem {
filter: blur(0);
transition: filter 1.2s ease;
}
.elem:hover {
filter: blur(7px);
}
Solution:
.elem {
filter: blur(0);
transition: filter .7s ease;
}
.elem:hover {
filter: blur(7px);
}
Try this in fiddle:
.blur {
border: none;
outline: none;
width: 100px; height: 100px;
background: #f0f;
margin: 30px;
-webkit-filter: blur(10px);
transition: all .7s ease-out;
/* transition: all .2s ease-out; */
}
.blur:hover {
-webkit-filter: blur(0);
}
.blur2 {
border: none;
outline: none;
width: 100px; height: 100px;
background: tomato;
margin: 30px;
-webkit-filter: blur(10px);
transition: all .2s ease-out;
}
.blur2:hover {
-webkit-filter: blur(0);
}
<div class="blur"></div>
<div class="blur2"></div>
I hope this helps someone.
For me, now in 2018. The only thing that fixed my problem (a white glitchy-flicker line running through an image on hover) was applying this to my link element holding the image element that has transform: scale(1.05)
a {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
transform: translateZ(0) scale(1.0, 1.0);
-webkit-filter: blur(0);
filter: blur(0);
}
a > .imageElement {
transition: transform 3s ease-in-out;
}
None of this worked, what worked for me is scaling image down.
So depending on what size you want the image or what resoultion your image is, you can do something like this:
.ok {
transform: perspective(100px) rotateY(0deg) scale(0.5);
transition: transform 1s;
object-fit:contain;
}
.ok:hover{
transform: perspective(100px) rotateY(-10deg) scale(0.5);
}
/* Demo Preview Stuff */
.bad {
max-width: 320px;
object-fit:contain;
transform: perspective(100px) rotateY(0deg);
transition: transform 1s;
}
.bad:hover{
transform: perspective(100px) rotateY(-10deg);
}
div {
text-align: center;
position: relative;
display: flex;
}
h3{
position: absolute;
bottom: 30px;
left: 0;
right: 0;
}
.b {
display: flex;
}
<center>
<h2>Hover on images</h2>
<div class="b">
<div>
<img class="ok" src='https://www.howtogeek.com/wp-content/uploads/2018/10/preview-11.png'>
<h3>Sharp</h3>
</div>
<div>
<img class="bad" src='https://www.howtogeek.com/wp-content/uploads/2018/10/preview-11.png'>
<h3>Blurry</h3>
</div>
</div>
</center>
The image should be scaled down, make sure you have a big image resoultion
I had a similar problem with blurry text but only the succeeding div was affected. For some reason the next div after the one that I was doing the transform in was blurry.
I tried everything that is recommended in this thread but nothing worked.
For me rearranging my divs worked. I moved the div that blurres the following div to the end of parents div.
If someone know why just let me know.
#before
<header class="container">
<div class="transformed div">
<span class="transform wrapper">
<span class="transformed"></span>
<span class="transformed"></span>
</span>
</div>
<div class="affected div">
</div>
</header>
#after
<header class="container">
<div class="affected div">
</div>
<div class="transformed div">
<span class="transform wrapper">
<span class="transformed"></span>
<span class="transformed"></span>
</span>
</div>
</header>
filter: blur(0)
transition: filter .3s ease-out
transition-timing-function: steps(3, end) // add this string with steps equal duration
I was helped by setting the value of transition duration .3s equal transition timing steps .3s
The blurring occurred for me in Chrome only (Windows and Mac) when animating 'transform' in a keyframe animation. For me, the -webkit-optimize-contrast setting only partially helped. For best results I also had to use a "magic value" for scaleX (slightly larger than 1 instead of 1).
Here's the code that worked:
img {
image-rendering: -webkit-optimize-contrast;
}
#keyframes scale-in-left {
0% {
transform: scaleX(0);
opacity: 0;
}
100% {
transform: scaleX(1.000001);
opacity: 1;
}
}
Here's the code that didn't work (caused blurry images in Chrome):
#keyframes scale-in-left {
0% {
transform: scaleX(0);
opacity: 0;
}
100% {
transform: scaleX(1);
opacity: 1;
}
}
In the end, the "working" code removed most of the blurring, but not all of it. Safari and Firefox were still clearer without any special settings.
Note also that just resizing the browser window cleared up the unwanted blurring, suggesting perhaps that something is causing Chrome to fail to execute a final render pass (?).