css z-index lost after webkit transform translate3d - css

I have two absolutely positioned div elements that overlap. Both have set z-index values via css. I use the translate3d webkit transform to animate these elements off the screen, and then back onto the screen. After the transform, the elements no longer respect their set z-index values.
Can anyone explain what happens to the z-index / stack-order of the div elements once I do a webkit transform on them? And explain what I can do to keep the stack-order of the div elements?
Here is some more information on how I am doing the transform.
Before the transform, each element gets these two webkit transition values set via css (I am using jQuery to do the .css() function calls:
element.css({ '-webkit-transition-duration': duration + 's' });
element.css({ '-webkit-transition-property': '-webkit-transform' });
The element is then animated using the translate3d -webkit-transform:
element.css({ '-webkit-transform': 'translate3d(' + hwDelta + 'px, 0, -1px)' });
Btw, I have tried setting the 3rd parameter of translate3d to several different values to try to replicate the stack-order in the 3d space, but to no luck.
Also, iPhone/iPad and Android browsers are my target browser that this code needs to run on. Both support webkit transitions.

This might be related to: https://bugs.webkit.org/show_bug.cgi?id=61824
Basically when you apply a 3D transform on the z-axis, the z-index can't be accounted for anymore (you're now in a 3 dimensional rendering plane, use different z-values). If you want to switch back to 2D rendering for child elements, use transform-style: flat;.

This is most definitely related to the bug noted by samy-delux. This should only affect any elements which are positioned as absolute or relative. In order to remedy the issue, you can apply the following css statement to every element which is positioned this way and is causing issues:
-webkit-transform: translate3d(0,0,0);
This will apply the transform to the element without actually doing a transformation, but affecting its render order so it is above the element causing the issue.

Bit Late to this but try putting on the elements that have lost their Z-index placing the following, I had an issue when doing some parallax stuff recently and this helped massively.
transform-style: preserve-3d;
This saves putting
transform: translate3d(0,0,0);
On other elements which puts more strain on the GPU

Waiting to see the example
Have you tried to do a transform scale(1)? I remember to had a similar problem, and I had to re-arrange the html order of elements, and utilise a transform that I didn't need it just because the z-index of the use of transform changed.
If I am not in error, every time that you use a transform, it become the highest z-index available, and it is ordered by the nearest element of html is to the start of the tag. So from up to below.
I hope that this help

z-index will work against 3d transformed divs if you style the stackable element with -webkit-transform: translateZ(0px);
Snippet on codepen -> http://codepen.io/mrmoje/pen/yLIul
In the example, the buttons stack up and stack down raise and lower the footer's z-index (+/-1) against the rotated element (an img in this case).

I haven't been able to reproduce the problem you describe here. Regardless of what I do, the z-index value is retained throughout all transforms. I'm testing using Chromium (Google Chrome).
The third argument of the translate3d function manipulates the z-axis of the element. The concept is similar to, but not exactly the same as, the z-index... Elements with a lower z-axis are under elements with a higher value.
I know you tried values of the third argument to match your intended z-index, but the problem is that the z-axis doesn't seem to change during CSS3 animation. In the following example, the hovered element should be on top, but #element_a stays on top.
If I add a z-index to both the regular selector and the :hover selector, it seems to work and allow the hovered element to be top-most.
Although it's not exactly what you were looking for, this behavior provides a solution. You just need to use translate3d and z-index to set the order for the initial rendering.
<style>
div {
width: 300px;
height: 150px;
background-color: white;
border: 5px outset gray;
float: left;
margin: 20px;
-webkit-transition: 2s;
}
#element_a {
-webkit-transform: translate3d(0, 0, 50px);
}
#element_b {
-webkit-transform: translate3d(0, 0, 100px);
}
#element_a:hover {
-webkit-transform: translate3d(100px, 0, 60px);
}
#element_b:hover {
-webkit-transform: translate3d(-100px, 0, -60px);
}
</style>
<body>
<div id="element_a">
<img src="http://www.google.com/intl/en_com/images/srpr/logo3w.png">
</div>
<div id="element_b">
<img src="http://www.google.com/intl/en_com/images/srpr/logo3w.png">
</div>
</body>

I had this problem on iphone/ios where I had a dropdown menu that overlapped a leafletjs map but was being covered by the map. Noticed that the map had translate3d applied.
Added this to the dropdown element:
transform: translate3d(0,0,0);
...and it is fixed. Thank you stackoverflow people.

Another way around this is that you can create a parent element and apply all other transitions related to it:
# Apply transitions to a parent div
<div>
# This image z-index -1
<img src="foo"/>
# This image z-index -3
<img src="bar"/>
#This image z-index -2
<img src="gg"/>
</div>
JsFiddle

Related

position: fixed not working

Working on a website today I found myself in the position (haha...) that a logo that I wanted to fix to the viewport didn't stick anymore. In my research to resolve this problem I learned that position: fixed won't fix to viewport if the ancestor element has a transform on it (see positions-fixed-doesnt-work-when-using-webkit-transform).
I made sure not to have any transforms on my element (or it's ancestors), I even tried to remove all child elements (which happen to have transforms and animations on them) – but I still didn't manage to get things going.
I am sort of clueless right now, so I made a jsfiddle for others to look at. The element that needs fixing is the bright red .titles element: http://jsfiddle.net/ZWcD9/90/
remove transfrom from body
body {
width: 100%;
/* -webkit-transform: translateZ(0); */
/* transform: translateZ(0); */
}

How to get Microsoft Edge handling my css for 3D in perspective correctly for mouse hovering?

I am using the css properties perspective and transform to create a 3D world in html. In Google Chrome everything works without problems, but in Microsoft Edge there is something buggy in it... I narrowed it down using this jsfiddle: https://jsfiddle.net/uke8bsvk/12/
The third variant in the fiddle is where it goes wrong. It is working fine in Google Chrome, but in Microsoft Edge somehow the red div does not respond well to hovering it with the mouse by changing its color to green. It only responds to hovering it with the mouse close to the bottom of the red div.
In the fourth variant I removed transform-style: preserve-3d for the red div and everything works fine again.
Does anyone have an idea what's going on here and how to solve it?
PS. In my real case, I sometimes have a child div for which preserving 3d is necessary and sometimes I do not have a child div. It is not really an option to use the obvious dirty work around of setting and removing transform-style: preserve-3d dependent on the presence of a child div.
I found a relatively clean trick/work around to 'solve' the problem: just add an extra child div, make it invisible and rotate it out of plane with transform: rotateX( 1deg ). See jsfiddle: https://jsfiddle.net/uke8bsvk/13/
You need to prefix the 3d properties in your css, using Autoprefixer. You can do it on the site itself or add it as an extension to your code editor of choice.
It will add some of these prefixes to your code as so:
-webkit-transform-origin: bottom left;
transform-origin: bottom left;
-webkit-transform: rotateX( 30deg );
transform: rotateX( 30deg );
background: red;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
Here is an updated Fiddle.
You should prefix each and every one of your projects for the web.

Why is CSS Hover behaviour flaky?

I want to create a button (using only css and html) that reveals another button beneath it on hover by rotating on it's lowermost axis.
I've been mostly successful: http://codepen.io/machinarius/pen/BdtCb
But as you can see on my pen the hover behaviour is flaky at best, it resets the animation on any movement of the cursor. Why id that happening? Isn't -webkit-animation-fill-mode: both; supposed to reverse the animation once the selector goes off?
There seem to be two parts to this question:
Why is the hovering flaky?
Like Palpatim said, as soon as the unfold-button is hovered over, it jumps away, so you'll need to have an unmoving element that will catch your hovers without un-hovering itself. So let's add a div that will do this:
<div class="container">
<div class="unfold-button orange">
Hello World
</div>
</div>
Likewise, let's update the CSS selector accordingly:
.container:hover .unfold-button {
Now if you put that in your HTML, you'll see that the hovering is no longer flaky. However, as you described, it still isn't animating back into place. This brings us to our second question:
Why is the animation not reversing?
Actually, animation-fill-mode does not mean that the animation will reverse back when the animation is no longer assigned; it only determines what attributes "fill out" before and after the animation occurs. If you remove the line defining animation-fill-mode, you'll see that the only difference is that, without it, the animation reverts after completing.
Also, elements have no memory of the animation values that they used to have, so as soon as an element's animation attribute changes, the element immediately "pops" into what it is assigned to be with no influence from any previous values of animation.
As a result, what's actually happening with your CSS is that, when the unfold-button is hovered over, it is handed the unfold animation and plays it (like it should), but when it is un-hovered, it suddenly has no animation assigned, so having "forgotten" about the animation, it just snaps back to what it was originally assigned to be.
Considering that the unfold animation is one simple motion, I would recommend expressing it instead as a transition:
.unfold-button {
/* ... */
border-style: none;
box-sizing: border-box;
transform-origin: 50% 100%;
-webkit-transform-origin: 50% 100%;
-webkit-transition: 0.5s;
transform: rotateX(0deg);
-webkit-transform: rotateX(0deg);
}
.container:hover .unfold-button {
-transform: rotateX(180deg);
-webkit-transform: rotateX(180deg);
}
Note how the transition attribute is maintained throughout both the hovered and non-hovered states. Like with animation, no animation results from it without its immediate presence.
And there you have it!
If the HTML and CSS look like what I have sitting in front of me right now, all should be good.
There's a little bit more information about reversing a CSS animation on hover-out here:
How to make CSS Animation reverse on hover-out?
The problem is that you're applying your animation on the :hover pseudo-class. Once the animation happens, you're no longer hovering, and so the animation resets. Try wrapping a container class around your animation element, and applying your animation trigger to the container's :hover, as in the example on https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode.

css flipped block interaction with non flipped, only webkit specific

okey, simple css flip
.container
.flipper.A
.front
.back
.flipper.B
.front
.back
it's important for me, that .front and .back both have negative top and left absolute position
and .flipper dimensions is 0x0
when flipper A is rotatedY 180deg, so .back is visible, it incorrectly interacts with other .flippers if their positions intersect. For example, i click on links in flipper B, but can't click on links in flipper A, if A is over B
working example is here http://jsfiddle.net/attenzione/g2at2/ - you almost can click on test 1, instead click on test 3
such situation only appear on webkit browser
any help with it? is this webkit bug?
Just bring the div that you want to be in front towards the front (in 3d space)
CSS
div.flipped {
-webkit-transform: rotateY(180deg) translateZ(-1px);
z-index: 2;
}
the translateZ moves it towards you
corrected fiddle
Is there a reason why your inner .block has absolute positioning? This is what is causing the issue. If you must use absolute positioning on the inner block then there are two ways round this.
You could overflow hidden the outer element (.flipper)
Or you could add pointer-events:none on the unflipped element, bear in mind this only works back to IE9
You should really try not to use absolute positioning though as it isn't needed.

Why does transform-origin-z distort on Safari, iOS?

I've been building a prism rotation effect using 3D transforms. The transform-origin-z property seemed best for transforming the faces of the prism, but Safari 5 and Mobile Safari inexplicably stretch my element, even when no transform is applied. Firefox 12 and Chrome 18 work correctly.
Live Demo
Full Prism Demo
I'm interested in understanding why this happens. Should I avoid transform-origin-z entirely, or is there some workaround for Safari and Mobile Safari?
<style>
/* other browser prefixes omitted for brevity */
.container {
margin: 50px;
border: 2px solid #00f;
height: 50px;
-webkit-perspective: 500px;
}
.face {
height: 50px;
background-color: rgba(255,0,0,0.5);
-webkit-transform-origin: center center -25px;
-webkit-transform: translate3d(0,0,0);
}
</style>
<div class="container">
<div class="face"></div>
</div>​
it seems like this is a bug in Safari.
Chrome moves the transformation-center over the Z-axis, Safari leaves this center were it was, but moves the object itself over the Z-axis.
The object therefore is zoomed in Safari, and seems bigger.
I would avoid the transform-origin (on Z-axis) for now and work with translate-Z to produce the same effect.
Example:
http://jsfiddle.net/willemvb/GuhcC/3/
I believe the following explanation answers the "why" Safari is doing what it is
I do not have access to Safari for testing, but as I read the specifications for the perspective property (the same spec page you point to), it states:
The ‘perspective’ property applies the same transform as the
perspective() transform function, except that it applies only
to the positioned or transformed children of the element, not to the
transform on the element itself.
Update on how I read the above spec
The ‘perspective’ property applies the same transform as the perspective() transform function
This tells me a perspective transform is going to be done just as if transform: perspective(500px) were applied in this case.
except that it applies only to the positioned or transformed children of the element
This tells me the perspective transform is going to be applied to child elements, in this case .face. Here, there seems to be some ambiguity. Is this saying the perspective should only be applied if another transform is done on the child element? And, does the tranform-origin property count as a transform being done to the child (especially since it is this value that relates directly to the perspective transform)? It is at this point of ambiguity that the browsers seem to differ. Safari is doing the perspective transform because the child element has tranform-origin set to -25px, whereas the others apparently are not (at least, not until the actual other transform does something else to the .face during the animation).
not to the transform on the element itself
This tells me the z=0 of .container is irrelevant, because the transform from this property is not affecting .container, but rather .container's children (i.e. .face).
So Safari appears to be taking the position that your .face always has a transform applied because you have set .container to have -webkit-perspective: 500px;, so there is always a perspective transform being applied to the child elements (.face in your case).
Note that if you take away the animation, and apply an actual transform: perspective(500px) to the .face you will see the same result in Firefox or Chrome as what you experience in Safari with your code.
So I think actually, Safari may be doing it correctly, and Firefox and Chrome perhaps are not. The spec has some ambiguity. The other two browsers perhaps should be still applying the perspective transform based off .container like Safari does, but certainly appear to not be, whereas Safari obviously appears to be.
To eliminate the issue (not have it "stick out" when "at rest"), you probably need to
Animate the transform-origin itself at the beginning of your animation (and reset to 0 afterwards), OR...
Animate the perspective value itself to be 0 when "at rest" and 500px when animating.
My guess is #1 will be easier to implement, but I don't know for sure.
I don't know why this worked for me. Seem to work on all browsers. Basically I think I am canceling the css declarations effect.
.container {
perspective: 500px;
transform-origin: 50% 50% 25px;
}

Resources