I have the following snippet to illustrate this issue.
According to everything I have read, elements positioned using transformZ should be on top as they are 'closer.' I can't position the active/flipped card 'on top' using z-index because flickering occurs during the transition. Yet the elements are positioned in the default order of the browser, which means the later elements are on top. Transform-style and perspective are both applied to the parents.
Why aren't the closer elements on top?
.card {
position: relative;
width: 33.333%; height: 12rem;
float: left;
transform-style: preserve-3d;
perspective: 30rem;
}
.front, .back {
position: absolute;
width: 100%; height: 100%;
transition: transform 1s;
backface-visibility:hidden;
}
.front {
background-color: #66ccff;
}
.back {
background-color: #dd8800;
transform: rotateY(180deg);
}
.card:hover .front{ transform: rotateY(180deg);}
.card:hover .back { transform: rotateY(360deg) translateZ(5em);}
.card2 {
position: relative;
width: 33.333%; height: 12rem;
perspective: 30rem;
float: left;
}
.front2, .back2 {
position: absolute;
width: 100%; height: 100%;
transition: transform 1s;
backface-visibility:hidden;
}
.front2 {
background-color: #66ccff;
}
.back2 {
background-color: #dd8800;
transform: rotateY(180deg);
z-index: 99;
}
.card2:hover .front2 { transform: rotateY(180deg);}
.card2:hover .back2 { transform: rotateY(360deg) translateZ(5em);}
.card3 {
position: relative;
width: 33.333%; height: 12rem;
perspective: 30rem;
float: left;
}
.front3, .back3 {
position: absolute;
width: 100%; height: 100%;
transition: transform 1s;
backface-visibility:hidden;
}
.front3 {
background-color: #66ccff;
}
.back3 {
background-color: #dd8800;
transform: rotateY(180deg);
z-index: 99;
}
.card3:hover .front3 { transform: rotateY(180deg);}
.card3:hover .back3 { transform: rotateY(360deg) translateZ(5em);}
<div class="card">
<div class="front">
<span>Front</span>
</div>
<div class="back">
<span>Back</span>
</div>
</div>
<div class="card2">
<div class="front2">
<span>Front</span>
</div>
<div class="back2">
<span>Back</span>
</div>
</div>
<div class="card3">
<div class="front3">
<span>Front</span>
</div>
<div class="back3">
<span>Back</span>
</div>
</div>
It's because the use of persepctive create a stacking context
Using this property with a value different than 0 and none creates a new stacking context. Also, in that case, the object will act as a containing block for position: fixed elements that it contains.ref
So what you said is all true but it happens inside the card element then the card elements are positionned considering the tree order.
An easy fix is to adjust z-index of card element considering some delay to avoid the bad effect.
.card {
position: relative;
width: 33.333%; height: 12rem;
float: left;
transform-style: preserve-3d;
perspective: 30rem;
z-index:0;
transition:z-index 0s .5s;
}
.front, .back {
position: absolute;
width: 100%; height: 100%;
transition: transform 1s;
backface-visibility:hidden;
}
.front {
background-color: #66ccff;
}
.back {
background-color: #dd8800;
transform: rotateY(180deg);
}
.card:hover .front{ transform: rotateY(180deg);}
.card:hover .back { transform: rotateY(360deg) translateZ(5em);}
.card:hover {
z-index:1;
}
<div class="card">
<div class="front">
<span>Front</span>
</div>
<div class="back">
<span>Back</span>
</div>
</div>
<div class="card">
<div class="front">
<span>Front</span>
</div>
<div class="back">
<span>Back</span>
</div>
</div>
<div class="card">
<div class="front">
<span>Front</span>
</div>
<div class="back">
<span>Back</span>
</div>
</div
Related
I have created a flip board animation with CSS transitions, and it works fine in Chrome/Firefox/Edge, but in Safari it flickers a lot during the transition, but the final state is correct.
I thought it might be a problem with the z-index in the transitions, but when removing those the flickering is still there.
I have autoprefixer on so I don't think it's an issue with backface-visibility.
If you look at this codepen in both Chrome and Safari, you can see the how it's supposed to be in Chrome, and the flickering issue in Safari.
https://codepen.io/joel-udd/pen/QWpEQMM
<div class="board board-1">
<div class="row-1">
<div class="letter-wrapper">
<div class="behind-letter">
<div class="behind bottom"><span>F</span></div>
<div class="behind top">I</div>
</div>
<div class="letter">
<div class="flip front">H</div>
<div class="flip back"><span>I</span></div>
</div>
<div class="letter">
<div class="flip front">G</div>
<div class="flip back"><span>H</span></div>
</div>
<div class="letter">
<div class="flip front">F</div>
<div class="flip back"><span>G</span></div>
</div>
</div>
</div>
</div>
.board {
display: inline-block;
position: relative;
perspective: 1000px;
.letter-wrapper {
display: inline-block;
position: relative;
width: 11vw;
margin-left: 2px;
height: 14vw;
.flip, .behind {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
width: 100%;
font-size: 14vw;
span {
display: inline-block;
transform: translateY(-50%);
}
}
.letter {
display: inline-block;
position: absolute;
top: 2px;
width: 100%;
height: 7vw;
transform: rotateX(0);
transform-style: preserve-3d;
transform-origin: bottom center;
.flip {
height: 100%;
backface-visibility: hidden;
&.back {
transform: rotateX(180deg);
}
}
&:nth-child(2) {
z-index: 10;
}
&:nth-child(3) {
z-index: 20;
}
&:nth-child(4) {
z-index: 30;
}
}
.behind-letter {
display: inline-block;
position: absolute;
width: 100%;
height: 100%;
z-index: 5;
.behind {
height: 50%;
&.bottom {
top: calc(50% + 2px);
}
}
}
}
&.active {
.row-1 {
.letter-wrapper {
.letter {
transform: rotateX(-180deg);
&:nth-child(2) {
z-index: 50;
transition: transform .5s .5s, z-index 0s .6s;
}
&:nth-child(3) {
z-index: 40;
transition: transform .5s .3s, z-index 0s .4s;
}
&:nth-child(4) {
transition: transform .5s .1s;
}
}
}
}
}
}
Thanks!
I want to rotate my element repeatedly, without back flip. When I call my function first time it will rotateX('180deg'), and the second will be rotateX('360deg') but the problem when I call third time it will be backflip, so any idea to make this flip keeping forward without back flip?
function myFunction() {
if (document.getElementById("front").style.transform == "" || document.getElementById("front").style.transform == "rotateX(0deg)") {
document.getElementById("front").style.transform = "rotateX(180deg)";
document.getElementById("back").style.transform = "rotateX(0deg)";
} else if (document.getElementById("front").style.transform == "rotateX(180deg)") {
document.getElementById("front").style.transform = "rotateX(360deg)";
document.getElementById("back").style.transform = "rotateX(180deg)";
} else {
document.getElementById("front").style.transform = "";
document.getElementById("back").style.transform = "rotateX(-180deg)";
}
}
.flipcard {
position: relative;
width: 220px;
height: 160px;
perspective: 500px;
}
.flipcard.h .back {
transform: rotateX(-180deg);
}
.flipcard .front,
.flipcard .back {
position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box;
transition: all 0.5s ease-in;
color: white;
background-color: #000;
padding: 10px;
backface-visibility: hidden;
}
<div class="flipcard h">
<div class="front" id="front">
This is the front side
</div>
<div class="back" id="back">
This is the back side
</div>
</div>
<button onclick="myFunction()">Flip The Image</button>
Simplify DOM, simplify JS and optimize CSS.
This is the best way to make a spinning card:
var card = document.querySelector('.card');
card.addEventListener( 'click', function() {
card.classList.toggle('is-flipped');
});
body { font-family: sans-serif; }
.card {
position: relative;
cursor: pointer;
transform-style: preserve-3d;
transform-origin: center right;
transition: transform 1s;
width: 200px;
height: 260px;
border: 1px solid #CCC;
margin: 40px 0;
perspective: 600px;
}
.card.is-flipped {
transform: rotateX(-180deg);
}
.card__face {
position: absolute;
width: 100%;
height: 100%;
line-height: 260px;
color: white;
text-align: center;
font-weight: bold;
font-size: 40px;
backface-visibility: hidden;
}
.card__face--front {
background: red;
}
.card__face--back {
background: blue;
transform: rotateX(180deg);
}
<div class="card">
<div class="card__face card__face--front">front</div>
<div class="card__face card__face--back">back</div>
</div>
You can do something like this:
$('#btnClick').click(function() {
$('.flip-container').toggleClass("flipped");
});
.flip-container.flipped .flipper {
-webkit-transform: rotateX(180deg);
-moz-transform: rotateX(180deg);
-o-transform: rotateX(180deg);
transform: rotateX(180deg);
position: relative;
}
.flip-container,
.front,
.back {
width: 200px;
height: 200px;
}
.flip-container {
-webkit-perspective: 1000;
-moz-perspective: 1000;
-o-perspective: 1000;
perspective: 500;
cursor: pointer;
top: 0;
width: 200px;
height: 200px;
}
.flip-container .back {
transform: rotateX(-180deg);
background-color: #000;
}
.flipper {
-webkit-transition: 0.6s;
-webkit-transform-style: preserve-3d;
-moz-transition: 0.6s;
-moz-transform-style: preserve-3d;
-o-transition: 0.6s;
-o-transform-style: preserve-3d;
transition: 0.6s;
transform-style: preserve-3d;
position: relative;
width: 200px;
height: 200px;
display: block;
}
.flip-container .front,
.flip-container .back {
position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box;
transition: all 0.6s ease-in;
color: white;
background-color: #000;
padding: 10px;
backface-visibility: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flip-container">
<div class="flipper">
<div class="front">
<p>This is the front side </p>
</div>
<div class="back">
<p> This is the back side </p>
</div>
</div>
</div>
<button id="btnClick">Flip The Image</button>
I wanna create brochure which open to the left and the right when someone hover over it.
I use transform-origin: 0% and transform: rotateY(-180deg) for the left site of the brochure to open to the left site (Card red and blue). For the right side I use of course transform-origin: 100% and transform: rotateY(180deg) to open to the right site (Card green).
But the actual behavior of the right side is, that it applies transform-origin: 0% and rotates behind the left site of the brochure (Thats why you can't see it, but its there).
I can't understand why transform-origin: 100% don't take affect.
here is the code: https://jsfiddle.net/eL6q3hp4/2/
.book-container {
height: 350px;
width: 250px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-webkit-perspective: 1000px;
-moz-perspective: 1000px;
perspective: 1000px;
}
.book-part {
height: auto;
width: auto;
position: absolute;
transform-style: preserve-3d;
top: 0;
left: 0;
}
.book-part > .card {
height: 350px;
width: 250px;
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
}
/* RIGHT SITE */
.right-part {
transform-origin: 0%;
}
.right-card {
transform: rotateY(-180deg);
}
.book-container:hover .right-part {
transform: rotateY(180deg);
transition: 0.7s;
transition-delay: 0.3s;
}
/* LEFT SITE */
.left-part {
transform-origin: 100%;
}
.left-card {
transform: rotateY(180deg);
}
.book-container:hover .left-part {
transform: rotateY(-180deg);
transition: 0.7s;
}
.middle-card {
background-color: blue;
}
.right-card {
background-color: green;
}
.left-card {
background-color: red;
}
.front-card {
background-color: yellow;
}
<div class="book-container">
<div class="book-part middle-part">
<div class="card middle-card"></div>
</div>
<div class="book-part right-part">
<div class="card right-card"></div>
</div>
<div class="book-part left-part">
<div class="card left-card"></div>
<div class="card front-card"></div>
</div>
</div>
Remove absolute position from .book-part and invert the rotation values. You can also add a front card to the right block
I also added transition to the closing effect:
.book-container {
height: 350px;
width: 250px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
perspective: 1000px;
}
.book-part {
transform-style: preserve-3d;
}
.book-part>.card {
height: 350px;
width: 250px;
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
}
/* RIGHT SITE */
.right-part {
transform-origin: 0%;
transition: 0.7s;
}
.right-card {
transform: rotateY(180deg);
}
.book-container:hover .right-part {
transform: rotateY(-180deg);
transition-delay: 0.3s;
}
/* LEFT SITE */
.left-part {
transform-origin: 100%;
transition: 0.7s;
transition-delay: 0.3s;
}
.left-card {
transform: rotateY(-180deg);
}
.book-container:hover .left-part {
transform: rotateY(180deg);
transition-delay: 0s;
}
<div class="book-container">
<div class="book-part middle-part">
<div class="card middle-card" style="background:blue"></div>
</div>
<div class="book-part right-part">
<img class="card right-card" style="background:green">
<img class="card front-card" style="background:pink;">
</div>
<div class="book-part left-part">
<img class="card left-card" style="background:red">
<img class="card front-card" style="background:yellow">
</div>
</div>
You can also simplify your code like below:
.book-container {
height: 350px;
width: 250px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
perspective: 1000px;
background:blue;
}
.book-container > div{
transform-style: preserve-3d;
}
.book-container > div:before,
.book-container > div:after{
content:"";
height: 350px;
width:100%;
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
background:yellow;
}
/* RIGHT SITE */
.right-part {
transform-origin: 0%;
transition: 0.7s;
}
.book-container .right-part:before {
transform: rotateY(180deg);
background:green;
}
.book-container:hover .right-part {
transform: rotateY(-180deg);
transition-delay: 0.3s;
}
/* LEFT SITE */
.left-part {
transform-origin: 100%;
transition: 0.7s;
transition-delay: 0.3s;
}
.book-container .left-part:before {
transform: rotateY(180deg);
background:red;
}
.book-container:hover .left-part {
transform: rotateY(180deg);
transition-delay: 0s;
}
<div class="book-container">
<div class="right-part">
</div>
<div class="left-part">
</div>
</div>
I don't know if in the original situation you work with dynamic sizes (in which case this solution would not apply), but you can use a pixel value for transform-origin to make it work:
.book-container {
height: 350px;
width: 250px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-webkit-perspective: 1000px;
-moz-perspective: 1000px;
perspective: 1000px;
}
.book-part {
height: auto;
width: auto;
position: absolute;
transform-style: preserve-3d;
top: 0;
left: 0;
}
.book-part > .card {
height: 350px;
width: 250px;
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
}
/* RIGHT SITE */
.right-part {
transform-origin: 250px;
}
.right-card {
transform: rotateY(180deg);
}
.book-container:hover .right-part {
transform: rotateY(180deg);
transition: 0.7s;
transition-delay: 0.3s;
}
/* LEFT SITE */
.left-part {
transform-origin: 0%;
}
.left-card {
transform: rotateY(-180deg);
}
.book-container:hover .left-part {
transform: rotateY(-180deg);
transition: 0.7s;
}
.middle-card {
background-color: blue;
}
.right-card {
background-color: green;
}
.left-card {
background-color: red;
}
.front-card {
background-color: yellow;
}
<div class="book-container">
<div class="book-part middle-part">
<div class="card middle-card"></div>
</div>
<div class="book-part right-part">
<div class="card right-card"></div>
</div>
<div class="book-part left-part">
<div class="card left-card"></div>
<div class="card front-card"></div>
</div>
</div>
I'm trying to implement a flip on an image but its preserve 3d (or probably backface-visibility) is not working on ie11.
This solution didn't work for me: -webkit-transform-style: preserve-3d not working
Here is a pen for you to try stuff and also a fiddle: http://codepen.io/vandervals/pen/XbedKY?editors=110
.container {
-ms-perspective: 1500px;
perspective: 1500px;
}
.canvas {
position: relative;
width: 300px;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50% 0;
transition: transform 1s ease 0s;
-ms-transform-style: preserve-3d;
transform-style: preserve-3d;
overflow: visible;
}
.canvas img {
max-width: 100%;
backface-visibility: hidden;
position: relative;
z-index: 2;
}
input:checked + .canvas {
transform: rotateY(180deg);
}
.red {
background: red;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 1;
backface-visibility: hidden;
transform: rotateY(180deg);
}
<div class="container">
<input type="checkbox">
<div class="canvas">
<img src="http://todofondosdeamor.com/wp-content/uploads/images/48/gatitos-1__400x300.jpg">
<div class="red"></div>
</div>
</div>
<p>That checkbox over there</p>
Internet Explorer doesn't support preserve-3d in any version (probably Spartan will).
You need to change the way you have set the transforms if you want it to work (on the item directly instead of the container)
.container{
perspective: 1500px;
}
.canvas{
position: relative;
width: 300px;
transform-origin: 50% 50% 0;
transform-style: preserve-3d;
overflow: visible;
}
.canvas img{
max-width: 100%;
backface-visibility: hidden;
position: relative;
z-index: 2;
transition: transform 1s ease 0s;
}
input:checked + .canvas img {
transform: rotateY(180deg);
}
.red{
background: red;
width: 100%;
height: 100%;
position: absolute;
top:0;
left:0;
z-index: 1;
backface-visibility: hidden;
transform: rotateY(180deg);
transition: transform 1s ease 0s;
}
input:checked + .canvas .red {
transform: rotateY(360deg);
}
<div class="container">
<input type="checkbox">
<div class="canvas">
<img src="http://todofondosdeamor.com/wp-content/uploads/images/48/gatitos-1__400x300.jpg">
<div class="red"></div>
</div>
</div>
<p>That checkbox over there</p>
I have a fiddle http://jsfiddle.net/nLhgT/
I followed the instructions here http://davidwalsh.name/css-flip and http://desandro.github.io/3dtransforms/docs/card-flip.html When I flip the card, only the front side is being shown (flipped). I can't seem to get the backface to show. I've read similar questions on stackoverflow saying the backface must be rotated first. It is indeed rotated initially in my example.
HTML
<ul>
<li>
<div class="container">
<div class="card">
<div class="front">
front
</div>
<div class="back">
back
</div>
</div>
</div>
</li>
</ul>
CSS
li {
width: 300px;
height: 260px;
position: relative;
perspective: 800px;
list-style-type: none;
}
.card {
width: 100%;
height: 100%;
position: absolute;
transform-style: preserve-3d;
-webkit-transition-duration: 400ms;
transition-duration: 400ms;
}
.card div {
display: block;
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.card .front {
background: red;
}
.card .back {
background: blue;
-webkit-transform: rotateY( 180deg );
transform: rotateY(180deg);
}
.card.flip {
-webkit-transform: rotateY(180deg);
transform: rotateY(180deg);
}
JS
$(document.body).on('click', '.card', function() {
console.log("CLICK");
document.querySelector('.card').classList.toggle("flip");
});
The only difference in my example is that the card is within an unordered list. I intend to make a list of these cards. But I don't think that should affect things.
So the main problem is that preserve-3d isn't supported by IE. Huge bummer, but not much that can be done about it. Therefore, you should be applying the transform to each child element, not the entire card.
The best way I've found of making a card flip is as follows:
Transform each face. The front should default to 0, the back to 180. When flipped, they should be 180 and 360 respectively.
Apply a z-index to them. The visible face should have something like 10, while the hidden one has 0. This ensures that the right one is in front at all times (even in browsers that don't support transformations)
Here is my update to your Fiddle showing a working card flip.
Here you go...
Demo Fiddle
HTML:
<ul>
<li>
<div class="container" id="flip-toggle">
<div class="card">
<div class="front">front</div>
<div class="back">back</div>
</div>
</div>
</li>
</ul>
CSS:
li {
width: 300px;
height: 260px;
position: relative;
perspective: 800px;
list-style-type: none;
}
.container {
-webkit-perspective: 1000;
-moz-perspective: 1000;
perspective: 1000;
border: 1px solid #ccc;
}
#flip-toggle.flip .card {
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
transform: rotateY(180deg);
filter: FlipH;
-ms-filter:"FlipH";
}
.container, .front, .back {
width: 300px;
height: 260px;
}
.card {
-webkit-transition: 0.6s;
-webkit-transform-style: preserve-3d;
-moz-transition: 0.6s;
-moz-transform-style: preserve-3d;
transition: 0.6s;
transform-style: preserve-3d;
position: relative;
width: 100%;
height: 100%;
}
.front, .back {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
.front {
background: red;
z-index: 2;
}
.back {
background: blue;
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
transform: rotateY(180deg);
}
JS:
$(document.body).on('click', '.card', function () {
console.log("CLICK");
document.querySelector('#flip-toggle').classList.toggle('flip');
});