I'm writing a custom animation for a project I'm working on. The idea is that the animation is meant to resemble an exclamation mark becoming unhinged from the baseline, swinging for a moment, and then falling off the baseline entirely.
For some reason, only Safari (OSX and iOS) refuses to render the first animation keyframe as a clockwise rotation in a CSS animation I've made. Instead, it renders the keyframe as a counter-clockwise animation, but then works just fine for the following animation keyframes.
Working CodePen example: http://codepen.io/michaelmarcialis/pen/obPYPO
#keyframes unhinged {
0% {
transform: rotate(0deg);
}
15% {
transform: rotate(240deg);
}
30% {
transform: rotate(125deg);
}
45% {
transform: rotate(220deg);
}
60% {
transform: rotate(145deg);
}
75% {
opacity: 1;
transform: rotate(200deg);
}
90% {
opacity: 0;
transform: translate(-0.5rem, 8.57142857142857rem) rotate(215deg);
}
95% {
opacity: 0;
transform: translate(0) rotate(0deg);
}
100% {
opacity: 1;
transform: rotate(0deg);
}
}
All other browsers render the animation as intended, with the first animation keyframe rotating clockwise. Safari is the only one that applies a counter-clockwise rotation in the initial keyframe. I'm assuming Safari is doing this because the distance to travel the rotation is shorter when going counter-clockwise, but it's not honoring the CSS spec properly if that's the case.
Does anyone know a remedy for this?
The problem is that if you try to animate a rotate in safari greater than 180 degrees, it will instead rotate the other way. So if you try to rotate +270 degrees, Safari will animate a rotation of -90 degrees.
The workaround for Safari is to never rotate more than 179 in either direction, then complete the rest of the rotation in another segment.
Related
I made a little CSS animation with a simple svg to transition my hamburger menu to a cross. It works as expected on Chrome and Firefox, but the translation is off in Safari. The animation plays, and even resets correctly so it has nothing to do with prefixes (I tried). The translate of the two lines making the cross is just wrong.
I'm guessing it has something to do with how safari handles the transform when scaling is also applied. Does anyone know if there is a work around / or what I'm doing wrong?
JSFiddle
Safari / Firefox / Chrome
#keyframes showCross {
0% {
transform: scale(1) rotate(0);
}
40% {
transform: scale(0.3) rotate(280deg);
}
100% {
transform: scale(1) rotate(360deg);
}
}
#keyframes showCross_P1 {
0% {
transform: rotate(0);
}
100% {
transform: rotate(-45deg) translate(-42%, -10%);
}
}
I fixed it by doing the following:
First I removed the groups surrounding the paths.
Then I gave all the paths the following values:
transform-origin:center center;
transform-box: fill-box;
Next I edited the animation keyframes to look as follows:
0% {
transform: translate(0rem,0rem) rotate(0);
}
100% {
transform: translate(-10rem,-38rem) rotate(-45deg) ;
}
Safari has problems with percents and also if you put the rotation before the translate it has inconsistency with other browsers, use rem instead!
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'm trying to understand CSS animations and I'm running into the following issue:
I've got a simple div with animation attached to it in CSS, like below:
<div id="learn">LEARN</div>
#learn {
width: 100px;
height: 100px;
background: blue;
position: relative;
animation: test1 5s ease-in 2s infinite;
}
Case 1:
#keyframes test1 {
0% {
transform: rotate(179deg);
}
100% {
transform: rotate(357deg);
}
}
Case 2 (the 0% transform is split into 90+89 deg instead of 179):
#keyframes test1 {
0% {
transform: rotate(90deg) rotate(89deg);
}
100% {
transform: rotate(357deg);
}
}
Why is the first case rotating clockwise and the second case rotating counter clockwise?
This might just be a bug with rotation transforms, which I'll address after some background.
Background
First off, the way rotations are supposed to work is with relation to a circle. If you specify a number of degrees, that will place the element in the position dictated by a how much rotation the degrees specify. When not animating a rotation, there are many ways to represent the element's placement. Code Uniquely is half-right in their comment in that the placement of 357 degrees and -3 degrees is the same, but when animating, they're very different. Going from 0 degrees to -3 degrees is a small counter-clockwise rotation, whereas going from 0 degrees to 357 degrees is a large clockwise rotation.
Findings
What you've found seems to ignore this calculation (in both Firefox and Chrome from what I've tested out). From what I'm seeing, combining rotate transforms effectively reverses the direction that the rotation should be going in, even if you're combining with a 0deg rotation:
transform: rotate(90deg); //rotates clockwise
transform: rotate(0deg) rotate(90deg); //rotates counter-clockwise
It seems that you can fix this by "combining" the rotation transforms in both animation steps:
// this performs a clockwise rotation
#keyframes test3 {
0% {
transform: rotate(0deg) rotate(90deg);
}
100% {
transform: rotate(0deg) rotate(357deg);
}
}
Finally, it seems that the number of "combinations" matters. If you combine 2 rotations in one step, but 3 in another, the unexpected behavior occurs:
// rotates counter-clockwise since there are unequal rotation transforms
#keyframes test4 {
0% {
transform: rotate(0deg) rotate(0deg) rotate(90deg);
}
100% {
transform: rotate(0deg) rotate(357deg);
}
}
Conclusion
This likely isn't the greatest answer, but combining rotations like this just doesn't appear to be documented anywhere. I would suggest not combining the same rotate transforms (you can still combine rotateX and rotateY without this weirdness) and stick with the sum of the degree values.
In case anyone finding this explanation wants to perhaps find out more about this behavior than I have, here's a fiddle with the examples above as a starting point.
I'm trying to animate an element back and forth, with a flip at each end. I'm using a CSS animation with scaleX(-1) at the end. It works fine in everything but IE, where it's shooting the element all the way off the page, then sliding it back into position.
#keyframes moveAndFlip {
48% {
transform: translateX(12vh) scaleX(1);
}
50% {
transform: translateX(12vh) scaleX(-1);
}
98% {
transform: translateX(0) scaleX(-1);
}
}
http://jsfiddle.net/pq9yqscy/2/
Is this a known issue in IE? Another way to tackle it?
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)