Prevent elements clipping when using 3D CSS transforms - css

I am having trouble preventing two elements clipping when using 3D CSS transforms. Has anyone come across this before and found a solution?
I have attached a screenshot from the latest version of iOS to illustrate the issue - It also occurs on the desktop version of Safari, but not Chrome on OS X.
I understand why this happens, and even that this is the correct behaviour in some circumstances, but it is inconsistent across different browsers.
Thanks for any help :)

This is caused by rendering both elements within the same 3d layer. The solution is to render them each in their own layer.
This is a simplified version of the code which caused the issue:
CSS:
.wrapper {
transform-style: preserve-3d;
perspective: 1000;
}
.rotate {
width: 100px;
height: 100px;
background: grey;
transform: rotateX(45deg);
}
.clipped-element {
width: 30px;
height: 30px;
background: blue;
}
HTML:
<div class="wrapper">
<div class="rotate">
<div class="clipped-element"></div>
</div>
</div>
By using transform-style and perspective I've created a rendering layer. As the .clipped-element is part of this layer it exists in the same 3d space.
By moving the clipped element into it's own layer it exists in it's own 3d space and the clipping issue is avoided.
CSS:
.wrapper {
width: 200px;
height: 200px;
}
.rotate__wrapper {
width: 100%;
height: 100%;
transform-style: preserve-3d;
perspective: 1000;
}
.rotate {
width: 100px;
height: 100px;
background: grey;
transform: rotateX(45deg);
}
.clipped-element {
width: 30px;
height: 30px;
background: blue;
}
HTML:
<div class="wrapper">
<div class="rotate__wrapper">
<div class="rotate"></div>
</div>
<div class="clipped-element"></div>
</div>
I've created an example on CodePen.

Related

Adding transform to parent breaks mix-blend-mode

I'm working on site where I need to animate divs that move over a sibling and apply a mix-blend-mode. I'm working with a library that create 2 divs the wrap around the blending element. The library also adds a transform to the direct parent, which is now breaking the blending. I figured this might relate to a stacking issue, but no matter how many/where I add a transform3d(0,0,0 ) the blend is still broken.
Due to the constraints of the library, I can't do much about of the wrappers or that the background is a sibling of the outermost wrapper.
If you toggle the requiredParent2 transform, everything works (as stated, this transform is added by a required library).
Additionally there are siblings to the blending element (mixBorder, which prevents me from moving the blending to the requiredParents)
Fiddle also here: https://jsfiddle.net/hb7qaod6/5/
.bg,
.root,
.requiredParent1,
.requiredParent2 {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.requiredParent2 {
transform: translate3d(0px, 2px, 0px);
}
.bg {
background-color: red;
}
.mix,
.mixBorder {
position: absolute;
top: 50%;
left: 50%;
width: 25%;
height: 25%;
}
.mix {
background-color: white;
mix-blend-mode: difference;
}
.mixBorder {
outline: white solid thick;
}
<div class="root">
<div class="bg"></div>
<div class="requiredParent1">
<div class="requiredParent2">
<div class="mix">
</div>
<div class="mixBorder">
</div>
</div>
</div>

Hover not reliable in a relative hierarchy using CSS rotation

I'm trying to create a online card game, using pure HTML/CSS.
I created a relative hierarchy of objects and I want the user to interact with them.
Probleme is, with CSS rotations (transform: rotateX, transform-style: preserve-3d), hover is not reliable.
Here's a simplified version of what it looks like :
http://jsfiddle.net/qLg9u51e/1/
Here are the main elements :
.container {
transform: rotateX(50deg);
transform-style: preserve-3d;
}
.tile {
position: relative;
}
.object {
position: absolute;
background: orange;
}
.object:hover {
background: red
}
I am expecting the orange object to be red while the mouse is hovering it, but as you can see, that's not always the case. It's a weird behaviour and I do not fully understand it.
By removing either rotateX, preserve-3d or the relative property, the hover property works correctly, but I need these elements.
Why am I doing wrong here ? And if you don't know how to solve my problem, do you know why CSS is acting like this ?
It looks like the row was overlapping the object at some points (not all, which is a bit confusing!).
Adding .row { pointer-events: none; }and .object { pointer-events: all; } fixes the problem:
.master {
perspective: 500px;
width: 200px;
height: 100px;
}
.container {
transform: rotateX(50deg);
transform-style: preserve-3d;
}
.row {
width: 200px;
background: darkgray;
padding: 20px;
pointer-events: none;
}
.tile {
height: 150px;
width: 80px;
margin-left: 60px;
margin-right: 60px;
background: #505050;
position: relative;
}
.object {
position: absolute;
height: 140px;
width: 70px;
margin: 5px;
background: orange;
pointer-events: all;
}
.object:hover {
background: red;
}
<div class="master">
<div class="container">
<div class="row">
<div class="tile">
<div class="object"/>
</div>
</div>
</div>
</div>
It's not ideal since I can't quite pinpoint the root cause, but it works in the meantime!

Skewing elements breaking in column-count configuration on chrome

Given a container with 3 columns using the css property column-count, and each column is skewed with transform: skewX(-15deg), if I apply another skew operation inside of the columns, starting from the 2nd column the affected elements become invisible.
I made a little example illustrating the problem:
https://jsfiddle.net/yvkeax2s/4/
.outer {
background-color: #aaffaa;
margin: 50px;
height: 200px;
width: 510px;
column-count: 3;
-moz-column-count: 3;
-webkit-column-count: 3;
column-count-gap: 20px;
-mozcolumn-count-gap: 20px;
-webkitcolumn-count-gap: 20px;
}
.inner {
display: inline-block;
width: 150px;
transform: skewX(-15deg);
background-color: #ff9999;
height: 100%;
}
.unskewed {
transform: skewX(15deg);
}
<div class="outer">
<div class="inner">
<div class="unskewed">skewed 1 <img src="http://placehold.it/40x20"></div>
raw text 1 <img src="http://placehold.it/40x20">
</div>
<div class="inner">
<div class="unskewed">skewed 2 <img src="http://placehold.it/40x20"></div>
raw text 2 <img src="http://placehold.it/40x20">
</div>
<div class="inner">
<div class="unskewed">skewed 3 <img src="http://placehold.it/40x20"></div>
raw text 3 <img src="http://placehold.it/40x20">
</div>
</div>
On Google chrome (Version 51.0.2704.103 m), I get the following:
On Firefox (47.0) I get the correct, expected result:
(The skewed blocks getting truncated seems to be another problem, which I currently don't care about, but might still be noteworthy)
This seems to be a bug in chrome with column-count, but is there a workaround to get this to work?
EDIT: I tested this on Version 53.0.2780.0 canary, and it worked, so the bug seems already fixed for the future.
You can force it to display by changing the .text class to the following:
.text {
transform: skewX(15deg) translateZ(0);
}
But do you need to use the column property? It's currently highly experimental, is full of bugs and requires a lot of browser prefixes, see Can I use.
What you are doing could be achieved in a number of different ways without using the column property. I have modified your fiddle to work without it: https://jsfiddle.net/yvkeax2s/6/
.outer {
background-color: #aaffaa;
margin: 50px;
height: 200px;
width: 510px;
}
.inner {
float: left;
width: 150px;
transform: skewX(-15deg);
background-color: #ff9999;
height: 100%;
margin: 0 10px;
}
.text {
transform: skewX(15deg);
}

CSS backface-visibility not showing on cardflip in a parent div

I am trying to make an opening book animation with CSS transitions similar to a card flip animation except with another card behind it.
When I create a single card flip it works fine in chrome. But if I put it inside a parent div in order to place another card behind it the back of the card no longer shows.
HTML
<div class="scene">
<div class="turncard">
<div class="turncard-front">
<div class="turncard-outside turncard-side">
Front!!!<br/>I don't work
</div>
<div class="turncard-inside turncard-side">
Back!!!<br/>Can you see me?
</div>
</div>
</div>
</div>
CSS
.scene {
margin-left: 200px;
perspective: 6000px;
}
.turncard {
width: 200px;
height: 200px;
margin-top: 50px;
transform-style: preserve-3d;
}
.turncard-front {
height: inherit;
width: inherit;
transition: transform 0.6s;
transform-origin: top left;
}
.turncard-side {
height: inherit;
width: inherit;
position: absolute;
backface-visibility: hidden;
background-color: green;
text-align: center;
}
.turncard-outside{
z-index: 1;
}
.turncard-inside {
transform: rotateY(180deg);
z-index: -1;
}
.turncard-front:hover {
transform: rotateY(180deg);
}
Both the working version (without a parent div) and non-working example (with the div) are shown in this fiddle: http://jsfiddle.net/bxLa4kwu/1/
Stick this property on .turncard2-front:
transform-style: preserve-3d;
http://jsfiddle.net/bxLa4kwu/3/
This property tells it to preserve the 3D position of children of the turncard2-front element (e.g. inside and outside of the page) when turncard2-front is css transformed.
Be aware this doesn't work in IE11 as the property isn't supported (but you probably knew that as the first example doesn't work either in IE).

Triangular css button image

I'm trying to make a splash page on my website with 2 large buttons, each a right angled triangle, and both join by the longest side to create a square. Basically I'm looking to find out how to make non-rectangular buttons in css.
I have no idea if this is even possible though, and cannot find anything online explaining similar techniques for buttons which are not rectangular, and i'm not particularly skilled in css. A push in the right direction would be very helpful!
A very old (unanswered question) deserves an answer.
You could use a nested div element in which the parent has an overflow set to hidden, with the child element rotated.
Here is a basic example: (please note: jQuery only required for demo)
$('.tri').click(function() {
alert("triangle clicked!");
});
.wrap {
height: 200px;
width: 200px;
position: relative;
overflow: hidden;
margin: 2px auto;
}
.wrap .tri {
position: absolute;
height: 70%;
width: 70%;
background: tomato;
transform-origin: bottom left;
bottom: 0;
transition: all 0.6s;
left: 0;
cursor: pointer;
transform: rotate(45deg);
}
.wrap2 {
transform: rotate(180deg);
}
.wrap .tri:hover {
background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap">
<div class="tri"></div>
</div>
<div class="wrap wrap2">
<div class="tri"></div>
</div>

Resources