CSS perspective with rotate & translate issue - css

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)

Related

Safari transforms SVG wrong

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!

GPU Acceleration of animated and blurred content

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.

Safari CSS Bug: Animation Rotation Direction Incorrect?

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.

animate flipping an element horizontally in IE11

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?

-webkit-transform with two background layers?

I have an animation for a div with two semi-transparent backgrounds:
/* The animated background DIV. */
#-webkit-keyframes wind /*Keyframes*/
{
0%
{
background-position: 0px 0px, 0px 0px;
}
100%
{
background-position: 370px 370px, 424px 242px;
}
}
Have you noticed the comma? It's because I use
#animatedBkg
{
background-image: url('1.png'), url('2.png');
}
Both files contain alpha channel.
Now, I want to accelerate this code on iPhone. So, I've replaced CPU loader background-position with -webkit-transform: translate():
/* The animated background DIV. */
#-webkit-keyframes wind /*Keyframes*/
{
0%
{
-webkit-transform: translate(0px, 0px), translate(0px, 0px);
}
100%
{
-webkit-transform: translate(370px, 370px), translate(424px, 242px);
}
}
It doesn't work at all. But if I remove the comma, both bkg layers are moving synchronously (it seems only the first translate() works), but MUCH smoother. Actually, speed difference is so huge I just can't return to background-image.
Are there other options except making two divs: #animatedBkg1 and #animatedBkg2?
Regards,
Well, since translating is moving an object, and background-position is an object property, it looks like 2 divs are required. This means #animatedBkg1 and #animatedBkg2.

Resources