z-index is canceled by setting transform(rotate) - css

Using transform property, z-index is canceled and appeared in the front.
(When commenting out -webkit-transform, z-index is properly working in below code)
.test {
width: 150px;
height: 40px;
margin: 30px;
line-height: 40px;
position: relative;
background: white;
-webkit-transform: rotate(10deg);
}
.test:after {
width: 100px;
height: 35px;
content: "";
position: absolute;
top: 0;
right: 2px;
-webkit-box-shadow: 0 5px 5px #999;
/* Safari and Chrome */
-webkit-transform: rotate(3deg);
/* Safari and Chrome */
transform: rotate(3deg);
z-index: -1;
}
<html>
<head>
<title>transform</title>
<link rel="stylesheet" type="text/css" href="transformtest.css">
</head>
<body>
<div class="test">z-index is canceled.</div>
</body>
</html>
How do transform and z-index work together?

Let's walk through what is occurring. To start, note that z-index on positioned elements and transform by itself create new "stacking contexts" on elements. Here's what's going on:
Your .test element has transform set to something other than none, which gives it its own stacking context.
You then add a .test:after pseudo-element, which is a child of .test. This child has z-index: -1, setting the stack level of .test:after within the stacking context of .test Setting z-index: -1 on .test:after does not place it behind .test because z-index only has meaning within a given stacking context.
When you remove -webkit-transform from .test it removes its stacking context, causing .test and .test:after to share a stacking context (that of <html>) and making .test:after go behind .test. Note that after removing .test's -webkit-transform rule you can, once again, give it its own stacking context by setting a new z-index rule (any value) on .test (again, because it is positioned)!
So how do we solve your problem?
To get z-index working the way you expect, make sure that .test and .test:after share the same stacking context. The problem is that you want .test rotated with transform, but to do so means creating its own stacking context. Fortunately, placing .test in a wrapping container and rotating that will still allow its children to share a stacking context while also rotating both.
Here's what you started with: http://jsfiddle.net/fH64Q/
And here's a way you can get around the stacking-contexts and keep
the rotation (note that the shadow gets a bit cut off because of .test's white background):
.wrapper {
-webkit-transform: rotate(10deg);
}
.test {
width: 150px;
height: 40px;
margin: 30px;
line-height: 40px;
position: relative;
background: white;
}
.test:after {
width: 100px;
height: 35px;
content: "";
position: absolute;
top: 0;
right: 2px;
-webkit-box-shadow: 0 5px 5px #999; /* Safari and Chrome */
-webkit-transform: rotate(3deg); /* Safari and Chrome */
transform: rotate(3deg);
z-index: -1;
}
<div class="wrapper">
<div class="test">z-index is canceled.</div>
</div>
There are other ways to do this, better ways even. I would probably make the "post-it" background the containing element and then put the text inside, that would probably be the easiest method and would reduce the complexity of what you have.
Check out this article for more details about z-index and stacking order, or the working W3C CSS3 spec on stacking context

Set the div you want to stay on top to position:relative

Had a similar problem where siblings were being transform: translate()'d and z-index wouldn't work.
Most straightforward solution is to set position: relative on all siblings, then z-index would work again.

Quick fix: You could just rotate the other element by 0 degrees as well.

For those who still looking for the solution, I found this article how to solve issue with transform and z-index here
Simple usage of it is by doing this:
.parent { transform-style: preserve-3d; }
.parent:before { transform: translateZ(-1em); }

I was facing the similar problem.
What i did was, I added a wrapper div around the test and gave the transform property to the wrapper div.
.wrapper{
transform: rotate(10deg);
}
here is the fiddle http://jsfiddle.net/KmnF2/16/

Set the div you want to stay on top to position:absolute

Related

Z-index not working with position:fixed pseudo-elements

I've researched a lot on the topic and generally most problems of this matter are solved by specifying of changing the position attribute. However, the situation is different when dealing with pseudo-elements. The following CSS is the reduced test case.
#div {
background: #f5f;
height: 80vw;
width: 80vw;
max-height: 50px;
max-width: 50px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#div:before {
content: '';
background: #000;
height: 100vw;
width: 100vw;
max-height: 100px;
max-width: 100px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: -1;
}
HTML
<div id="div">hi!</div>
Fiddle
Pseudo elements belongs to the element itself. So the z-index will work in all pseudo "childrens", but not in the parent because is not in the same stack.
It's like when you want to change the z-index to put a div over another div but first is the parent of the second:
div {position:relative;}
.parent {z-index:10; background:red; padding: 5px;}
.children {z-index:5; background:blue;}
<div class="parent">
I need this more z-index than his children
<div class="children">
I need this less z-index than his parent
</div>
</div>
It doesn't work obviously. That's the same case.
To avoid this, you need to change your HTML and convert the pseudo element in a normal element with the propper stack.
EDIT
In your case, you can solve if you change the fixed positioning to the relative positioning:
http://jsfiddle.net/Kq2PY/166/
But this is a particular case because the parent is fixed positioning, and it works going out of the normal flow (fixed elements are attached to the document, not the parent element). So avoid to make this kind of things when you can make with another ways.

CSS3 blur filter on image expands beyond original width

I am applying CSS3 blur filter on an image, but unexpectedly the blur effect goes out of the image original size (at least on Webkit browsers ).
I used overflow: hidden; but it's not working.
Here is my code:
HTML:
<div class='container'>
<img src='img.jpg' class='blur' />
</div>
CSS:
body{
padding:0px;
margin: 0px;
background: #1f1f1f;
}
.blur{
-webkit-filter: blur(15px);
-moz-filter: blur(15px);
-o-filter: blur(15px);
-ms-filter: blur(15px);
filter: blur(15px);
}
.container {
border:1px solid #fff;
margin:40px;
float:left;
overflow: hidden;
}
And here is a fiddle
Any ideas?
By giving the img a negative margin such as
img {
margin: -5px;
}
... will hide the spillage. You can play around with the margin.
FIDDLE
EDIT: Why This Occurs
Applying blur... you are blending your element by whatever amount of px, em etc. you declare e.g. 5px. To create this blur, the element will be expanded/feathured by that amount outside of its current size.
So applying a negative margin essentially "clips" the size and prevents anything outside of it to work. "Clipping" it is one approach, another would be by wrapping the element with a div and declaring a height and width and applying overflow: hidden. This will mask the overflow.
As I was experiencing the exact same bug on Safari 8 I thought I'd post my solution.
In the above example, you'd just need to add
-webkit-filter:blur(0px);
to the container.
The blur effect always go beyond the width.
In your case you can fix the issue using one of the following techniques -
Try setting a width of your .container and reduce 15px + 15px from both height and width of the img using CSS calc() function.
Or you can just add a padding of 15px to the img
DEMO of 2nd solution
I don't know much about "blur" yet, but I'm guessing it spreads / blurs out the edges 15px (in this case) in every direction. When you add padding: 15px; to your .container class it looks fine:
.container {
border:1px solid #fff;
margin:40px;
float:left;
overflow: hidden;
padding: 15px;
}
here is the fiddle
Put height and width attributes that are smaller than the image on the container. A size of 1px less than the image seems to work well.
CSS:
.container {
/* ... */
width:399px;
height: 223px;
}
JSFiddle
If your background around the clipping box .outer can be solid, you can cheat with a drop shadow. http://jsfiddle.net/ffghjkbj/
.overflow{
width: 200px;
height: 200px;
overflow: visible;
background-color: transparent;
position: relative;
z-index: 4;
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
margin: 30px;
}
.overflow:after {
content: "";
position: absolute;
display: block;
box-shadow: 0 0 0 40px #fff;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 10;
}
.inner{
width: 100%;
height: 100%;
background: green;
filter: blur(10px);
-webkit-filter: blur(0px);
transition: all 0.5s ease-in-out;
-webkit-transform: scale(1.2 , 1.2);
-webkit-transform-origin: 50% 50%;
z-index: -1;
position: absolute;
-webkit-backface-visibility: hidden;
margin: 0px;
padding: 10%;
box-sizing: border-box;
}
.overflow:hover .inner{
filter: blur(10px);
-webkit-filter: blur(10px);
}
If you background is not solid, you could maybe use a border-image, with the same image than the background, to fake the effect, which would be almost the same than using a png mask with a hole in the middle, instead of a background, and moving the pseudo-object with the mask to the front with z-index.
The blurry border you see is generated by the .inner element being CLIPPED (by its parent) BEFORE the blur is applied. Definitely a way for the acceleration not to waste power in rendering hidden areas.
So the .inner element is ALREADY clipped at the parent's edges when the blur is applied to it, and the blurry frame is actualy the outside empty area bleeding inside the image when blurred. The blur is NOT applied to the whole inner element as we would imagine if the element was "inside" or "behind". Just to the visible part. (This is why an oversized .inner element as suggested above won't work).
It's not obvious because the idea of a children element "inside" or "behind" its parent is in our mind. Objects just happen to be clipped at the paren't coordinates, but are actually IN FRONT of the parent.

Controlling Intersection of CSS 3D Transformed Elements

Have been experimenting with CSS 3D transforms and am confused why I'm not getting the expected results in browsers other than Safari.
Basically I have 2 sibling elements that are on top of one another (on the same z-index). If I put a transform: rotateX(xdeg) on one and leave the other untouched I would expect to see one half of the transformed element hidden behind the untouched element and the other side to be sticking out.
HTML:
<div class="container">
<div class="outer"></div>
<div class="inner"></div>
</div>
CSS:
.container{
position: relative;
margin: 100px;
-webkit-perspective: 30em;
perspective: 30em;
}
.outer{
-webkit-transform: rotateX(45deg);
transform: rotateX(45deg);
position: absolute;
top: 0;
left:0;
width: 100px;
height: 100px;
box-sizing: border-box;
-moz-box-sizing: border-box;
border:5px black solid;
}
.inner{
position: absolute;
top: 5px;
left: 5px;
background: orange;
width: 90px;
height: 90px;
transform: rotate
}
http://jsfiddle.net/jaredkhan/4VRTb/3/
The fiddle uses the same code.
The bottom of the transformed element is not displayed in front of the element that is untouched despite theoretically being closer in 3D space. This does however, work as I would expect in Safari. Am I missing something? I've tried explicitly putting them both on the same z-index and even nesting the inner one, nothing seems to be working. It's likely I'm just being dumb but please help.
Thanks
Children are rendered one by one onto the plane of the parent element. You need to set transform-style: preserve-3d on the parent to prevent this (fiddle):
.container{
...
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
More info on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style
(I'm not sure whether this even existed back in 2014 when you asked the question, but it works now in 2019.)

Off by one pixel issue in IE CSS transform

I am using transform: skew to create the effect of a down arrow on my banner image using both the :before and :after tags. The result should look like the following:
However, in IE 9-11 there seems to be a rounding issue. At some heights there is one pixel from the background image that shows below the skewed blocks resulting in the following:
In my case, the banner is a percentage of the total height of the window. Here is the some sample code which should be able to reproduce the problem:
HTML
<div id="main">
<div id="banner"></div>
<section>
<h1>...</h1>
<p>...</p>
</section>
</div>
CSS
#banner {
position: relative;
background-color: green;
width: 100%;
height: 75%;
overflow: hidden;
}
#banner:before,
#banner:after {
content: '';
display: block;
position: absolute;
bottom: 0;
width: 50%;
height: 1.5em;
background-color: #FFFFF9;
transform: skew(45deg);
transform-origin: right bottom;
}
#banner:after {
right: 0;
transform: skew(-45deg);
transform-origin: left bottom;
}
body {
background-color: #333;
position: absolute;
width: 100%;
height: 100%;
}
#main {
max-width: 40em;
margin: 0 auto;
background-color: #FFFFF9;
position: relative;
height: 100%;
}
section {
padding: 0 1em 5em;
background-color: #FFFFF9;
}
And here a working example.
Yes, seems to be a rounding issue – and I don’t know of anything that one could do to fix this. It’s in the nature of percentage values that they don’t always result in full pixel values – and how rounding is done in those cases is up to the browser vendor, I’m afraid.
I can only offer you a possible workaround (resp. “cover up”) that seems to work – if the layout really is as simple as this, and the main content area has a white background, and no transparency or background-image gets involved there.
Pull the section “up” over the banner by a negative margin of -1px (eliminated top margin of h1 here as well, otherwise it adjoins with the top margin of the section – countered by a padding-top), so that its background simply covers up that little glitch:
section {
padding: 1em 1em 5em;
background-color: #FFFFF9;
position:relative;
margin-top:-1px;
}
section h1:first-child { margin-top:0; }
Well, if you look closely, that makes the corner of triangle look slightly “cut off” (by one pixel) in those situations where the rounding glitch occurs – if you can live with that (and your desired layout allows for it), then take it :-) (And maybe serve it to IE only by some means). If not – then sorry, can’t help you there.

Webkit border-radius and overflow bug when using any animation/transition

I am having getting a weird bug when I use a combination of overflow, border-radius, and transition. I have a div with an img inside of it:
<a href="#" class="block size1 annualreport nonprofit">
<div class="inner_block">
<img src="http://i.imgur.com/8uuZB.jpg" />
</div>
</a>
The div has a border-radius, and overflow is set to hidden:
body {background-color:#78735e;}
.block {
position: absolute;
left: 0px;
top: 0px;
border-radius: 10px;
margin: 6px;
box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.2);
overflow:hidden;
}
.size1 {
width: 226px;
height: 464px;
min-width: 160px;
max-width: 226px;
}
.inner_block {
overflow: hidden;
border-radius: 10px;
}
.block img {
width: 100%;
height: 100%;
transition: all 0.1s;
}
.block img:hover { width:115%; height:115%; }
When I hover over the img I have a transition that takes place which makes the image larger to create a zooming effect. The problem is that the overflow seems to break on the bottom left and bottom right of the image.
I have created a JSFiddle for you to see what I'm talking about. http://jsfiddle.net/dmcgrew/HuMrC/1/
It works fine in Firefox, but breaks in Chrome and Safari.
Anyone know what might be causing this or how to fix it?
I had the same exact issue. Adding this to the parent container solved it for me (this is a LESS mixin).
.transitionfix() {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0)
}
I added minus z-index value for image and higher value for parent
li {z-index:10; overflow: hidden;}
li img {z-index: -10;}
I have faced this issue on Safari(It's a known bug in safari); fixed it by applying -webkit-mask-image and it works for me perfectly. cheers
.block {
-webkit-mask-image: -webkit-radial-gradient(white, black);
}
-- Simple Solution --
On the same element that has the animation transition, simply add:
.animated-item {
will-change: transform; /* New line to add to your existing CSS */
}
The will-change CSS property hints to browsers how an element is expected to change. Browsers may set up optimizations before an element is actually changed. These kinds of optimizations can increase the responsiveness of a page by doing potentially expensive work before they are actually required.
~ https://developer.mozilla.org/en-US/docs/Web/CSS/will-change
I don't know if I'm understanding the problem correctly as the image isn't loading. If you add height: 100%; to .inner_block does it help your issue?
http://jsfiddle.net/HuMrC/2/
There's already an answer about a CSS property for creating a new stacking context:
isolation: isolate;
I've had an issue in the past like this while trying to zoom into a photo inside a div. I fixed it by adding rotation scale(1.05) rotate(0.02deg) to the scale transform
(It actually removed the glitchy lines)
My issue today is getting the glitch lines off a translateY div hover effect. Surprisingly enough, I got rid of them by removing overflow: hidden;
Hopefully this helps future debuggers.
It is a problem about stacking context.
We can use methods listed in MDN - stacking context to form a stacking context:
position: relative; z-index: 1;
-webkit-mask-image: -webkit-radial-gradient(white, black);
opacity: 0.999;
will-change: transform;
For me personally, the first method is the best.

Resources