I tried to create this effect using transitions. It should look like you are opening a box.
There are 2 problems:
The order in which the box closes is same as in which it opens. Is there anyway to close the box in reverse order of its opening so that the box goes back in the same state it was when closed?
The ends of the green and yellow flaps are hidden during transition because of the red and blue flaps, so it doesn't look 3D. Is there a way I can show all flaps in 3D way?
I would prefer if the solution was in pure CSS , no JavaScript please.
#box {
position: relative;
top: 170px;
left: 170px;
width: 300px;
height: 300px;
border: 1px solid black;
perspective: 800px;
}
#flap1, #flap2, #flap3, #flap4 {
position: absolute;
}
#flap1 {
background-color: red;
width: 150px;
height: 300px;
z-index: 1;
transform-origin: 0 0;
transition: transform 1s;
}
#flap2 {
left: 150px;
background-color: blue;
width: 150px;
height: 300px;
z-index: 1;
transform-origin: 100% 0;
transition: transform 1s ease 0.3s;
}
#flap3 {
background-color: green;
width: 300px;
height: 150px;
transform-origin: 0 0;
transition: transform 1s ease 0.6s;
}
#flap4 {
background-color: yellow;
top: 150px;
width: 300px;
height: 150px;
transform-origin: 0 100%;
transition: transform 1s ease 0.9s;
}
#box:hover #flap1{
transform: rotateY(-170deg);
}
#box:hover #flap2{
transform: rotateY(170deg);
}
#box:hover #flap3{
transform: rotateX(170deg);
}
#box:hover #flap4{
transform: rotateX(-170deg);
}
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="box">
<div id="flap1"></div>
<div id="flap2"></div>
<div id="flap3"></div>
<div id="flap4"></div>
</div>
</body>
</html>
For Question 1:
If you give the delay in forward order for the :hover selectors and in the reverse order within default selectors, it will achieve the exact reverse animation.
For Question 2:
The fix and the explanation are as follows:
For part of the transition duration, the green and yellow boxes don't look like they have 3D effect because there are a couple of elements with higher z-index which is being placed above. This prevents the stretched area (due to perspective rotate) from showing up and thus it looks like it's only 2D (while it actually is not). To overcome this, we need to instruct the browsers to preserve the 3D aspect of the transform. This is done using transform-style: preserve-3d.
When we do the above, the flaps will all open with a 3D effect but near the start of the animation and its end, we will see a flicker on the blue flap when the transition actually starts and ends for the blue flap. It seems like this is because the z-index loses effect when 3D transform is used and there is a small amount of time between the losing of the z-index effect and starting of the preserve-3D effect during which the blue flap temporarily goes behind. To address this, the 3D equivalent of z-index: 1 (which is, translateZ(1px)) is added. The translate in Z-axis brings the element closer by 1px to your eye and keeps it above the yellow and green flaps.
Finally, despite all the above, there is a small glitch at the end of hover out animation, where the green flap shows through the blue flap. To overcome this, I had changed the delay timings a bit.
(Contrary to what I originally mentioned, the translateZ(0px) is not required and can be removed.)
#box {
position: relative;
top: 170px;
left: 170px;
width: 300px;
height: 300px;
border: 1px solid black;
perspective: 800px;
transform-style: preserve-3d;
}
#flap1, #flap2, #flap3, #flap4 {
position: absolute;
}
#flap1 {
background-color: red;
width: 150px;
height: 300px;
z-index: 1;
transform: translateZ(1px);
transform-origin: 0 0;
transition: transform 1s 1.5s;
}
#flap2 {
left: 150px;
background-color: blue;
width: 150px;
height: 300px;
z-index: 1;
transform: translateZ(1px);
transform-origin: 100% 0;
transition: transform 1s ease 1s;
}
#flap3 {
background-color: green;
width: 300px;
height: 150px;
transform-origin: 0 0;
transition: transform 1s ease 0.5s;
}
#flap4 {
background-color: yellow;
top: 150px;
width: 300px;
height: 150px;
transform-origin: 0 100%;
transition: transform 1s ease;
}
#box:hover #flap1 {
transform: rotateY(-170deg) translateZ(1px);
transition: transform 1s ease;
}
#box:hover #flap2 {
transform: rotateY(170deg) translateZ(1px);
transition: transform 1s ease 0.5s;
}
#box:hover #flap3 {
transform: rotateX(170deg);
transition: transform 1s ease 1s;
}
#box:hover #flap4 {
transform: rotateX(-170deg);
transition: transform 1s ease 1.5s;
}
<div id="box">
<div id="flap1"></div>
<div id="flap2"></div>
<div id="flap3"></div>
<div id="flap4"></div>
</div>
Related
I am trying to add transition timing when switching the text alignment via :hover. The transition is added to the color properly, but not the text alignment.
example: Codepen
div {
background-color: #ff4000;
height: 300px;
width: 600px;
}
div:hover>h1 {
color: #ddd;
text-align: right;
transition: .6s ease-in !important;
}
<div>
<h1>Lorem Ipsum</h1>
</div>
I guess it was just the CSS Working Group decided not to implement it for whatever reasons. But there are other ways around, see the following demo by using position and transform tricks.
div {
background-color: #ff4000;
height: 300px;
width: 600px;
position: relative;
}
h1 {
position: absolute;
left: 0;
top: 0;
white-space: nowrap;
margin: 0;
transition: 0.6s ease-in;
}
div:hover > h1 {
color: #ddd;
left: 100%;
transform: translateX(-100%);
}
<div>
<h1>Lorem Ipsum</h1>
</div>
Another approach is to animate width.
div {
background-color: #ff4000;
height: 300px;
width: 600px;
}
h1 {
width: 0;
text-align: right;
white-space: nowrap;
margin: 0;
transition: 0.6s ease-in;
}
div:hover > h1 {
color: #ddd;
width: 100%;
}
<div>
<h1>Lorem Ipsum</h1>
</div>
transform: translateX()
text-align is not animatable but position and transforms are -- the latter being the better choice because it's less GPU/CPU intensive than the former. The following is a what was added as the first leg of the animation in the demo.
transform:translateX(300px);
transition: transform .6s ease-in;
Demo
div {
background-color: #ff4000;
height: 300px;
width: 600px;
}
h1 {
transform: translateX(0px);
transition: transform .6s ease-out;
}
div:hover>h1 {
color: #ddd;
width: 200px;
transform: translateX(300px);
transition: transform .6s ease-in;
}
<div>
<h1>Lorem Ipsum</h1>
</div>
So, I have an icon, a circle icon, I want to make this icon when it hovered it will has coin flip transform, just like https://desandro.github.io/3dtransforms/examples/card-02-slide-flip.html but it flip two times so it goes back to the first position.
This is the HTML code:
<div class="bg">
<div class="icon">
<img src="football.png">
</div>
</div>
This is the CSS code:
.bg {
padding: 6px 6px;
float: left;
width: 20%;
}
.icon {
width: 100px;
height: 100px;
overflow: hidden;
border-radius: 50%;
box-shadow: 3px 3px 10px black;
border: 0px;
background-color: white;
margin-left: auto;
margin-right: auto;
display: block;
}
.icon img{
left: 50%;
top: 50%;
height: 100%;
width: auto;
}
.icon:hover {
transform: translateX( -1px ) rotateY( 180deg );
}
so the transform is not soft like the example from the link, and when the first flip (or rotation) I want to change the icon with different image, but when the second rotate it will back to first image. Any suggestion? thanks before
You forgot to add the animation itself, the transition.
.bg {
padding: 6px 6px;
float: left;
width: 20%;
}
.icon {
width: 100px;
height: 100px;
overflow: hidden;
border-radius: 50%;
box-shadow: 3px 3px 10px black;
border: 0px;
background-color: white;
margin-left: auto;
margin-right: auto;
display: block;
/* TRANSITION HERE!! */
-webkit-transition: transform 1s ease;
-moz-transition: transform 1s ease;
-ms-transition: transform 1s ease;
-o-transition: transform 1s ease;
transition: transform 1s ease;
/* END OF TRANSITION */
}
.icon img{
left: 50%;
top: 50%;
height: 100%;
width: auto;
}
.icon:hover {
transform: translateX( -1px ) rotateY( 180deg ); /* ALSO EXTRA TRANSFORM PROPERTIES ADDED FOR COMPATIBILITY*/
-ms-transform: translateX( -1px ) rotateY(180deg); /* IE 9 */
-webkit-transform: translateX( -1px ) rotateY(180deg); /* Chrome, Safari, Opera */
}
<div class="bg">
<div class="icon">
<img src="https://i.stack.imgur.com/RVjde.jpg">
</div>
</div>
I hope this helped.
Cheers!
You can define an animation the following:
#keyframes flip_animation {
from {transform: rotateY(0deg);}
to {transform: rotateY(360deg);}
}
And add this animation you your CSS-Class
.icon:hover {
animation-name: flip_animation;
animation-duration: 1s;
}
See this link for more information about animations in CSS.
How do I activate the CSS animation when the .move class is added to the .box using only CSS? The animation should translate first and when the translate has finished the rotate should begin where the translate ended. Also, how do I make the end state of the animation to be persistent at 100% and reset to 0% when the .move class is removed?
$(".test").click(function(){
$(".box").toggleClass("move")
});
body{
padding: 45px;
}
.test{
margin-top: 15px;
}
.box{
height: 45px;
width: 45px;
background: black;
}
.move{
background: blue;
}
.box{
animation: slide 0.5s, rotate 0.5s;
animation-delay: 0s, 0.5s;
}
#keyframes slide{
100%{
transform: translateX(450px);
}
}
#keyframes rotate{
100%{
transform: rotate(45deg);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<button class="test">Toggle</button>
You can add multiple transforms by placing them together:
transform:translateX(450px) rotate(45deg);
To do this with a key-frame animation, you want to do all stages as a single animation. You will want to apply the animation to the .move class and set animation-fill-mode: forwards to persist the last frame until the class is removed.
$(".test").click(function(){
$(".box").toggleClass("move")
});
body{
padding: 45px;
}
.test{
margin-top: 15px;
}
.box{
height: 45px;
width: 45px;
background: black;
}
.move{
background: blue;
animation: slide 1s;
animation-fill-mode: forwards;
}
#keyframes slide{
50%{
transform: translateX(450px);
}
100%{
transform:translateX(450px) rotate(45deg);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<button class="test">Toggle</button>
That is possible by setting multiple transitions on the element, combined with the transition-delay property.
One note: since each transition has a one to one correspondence to a property, and since you are using the transform property for both the "move" and "rotate" operations, it won't work the way you've written it.
For the "move" operation, I am using margin-left rather than the transform property. You can use any method, as long as it is animatable and doesn't overload a property that you are using for one of the other transitions.
$(".test").click(function(){
$(".box").toggleClass("move")
});
body {
padding: 45px;
}
.test {
margin-top: 15px;
}
.box {
height: 45px;
width: 45px;
background: black;
transition:
margin-left 0.5s,
transform 0.5s;
/* delays for when the .move class was just removed */
transition-delay: 0.5s, 0s;
}
.box.move {
background: blue;
margin-left: 450px;
transform: rotate(45deg);
/* delays for when the .move class was just added */
transition-delay: 0s, 0.5s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<button class="test">Toggle</button>
You can also specify the delay directly in the transition shorthand property, like this.
/* transitions for when the .move class was just removed */
transition:
margin-left 0.5s 0.5s,
transform 0.5s 0s;
It seems what you're looking for is a solution based on transition, not animation (unless I misunderstand what you're looking for, in which case please comment):
$(".test").click(function(){
$(".box").toggleClass("move")
});
.test, .box {
margin-top: 15px;
}
.box {
height: 45px;
width: 45px;
background: black;
position: relative;
left: 0;
transition: left 5s, transform 5s linear 5s;
}
.box.move {
background: blue;
left: 450px;
transform: rotate(45deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<button class="test">Toggle</button>
This may kinda invalidate what you're trying to do, but you're setting transform twice - if you need to target multiple transform properties on one element, you need to do it in one tranform declaration, like this:
.box{
animation: boxStuff 0.5s
}
#keyframes boxStuff{
100%{
transform: translateX(450px) rotate(45deg);;
}
}
Otherwise whichever is further down is just overriding the other. Maybe you can use a margin or something instead of translateX to work around this?
For the other half of your question, you should be able to add this to the .move class to stop on the last animation frame until the move class is removed.
animation-fill-mode: forwards;
If I understood you correctly, this is the result you want.
<a class="test">Toggle</a>
<div class="box"></div>
.box {
width: 200px;
height: 200px;
margin-left: 0;
background: gold;
transform: rotate(0deg);
transition: transform .3s 0s, margin .3s .3s;
}
.move {
margin-left: 50px;
transform: rotate(45deg);
transition: margin .3s 0s, transform .3s .3s;
}
and here's a fiddle https://jsfiddle.net/VilleKoo/owsm0f7h/1/
This is how I want to scale my images, smoothly without any jumps.
My attempt does not work like in the gallery above, the image (red square in my case) jumps, my code:
section {
background-color: rgba(0, 0, 0, 0.701961);
width: 400px;
height: 400px;
}
div {
position: absolute;
top: 120px;
left: 120px;
width: 160px;
height: 160px;
background-color: red;
-webkit-transition: all .2s ease-in-out;
}
div:hover {
-webkit-transform: scale(1.8);
}
<section>
<div></div>
</section>
How to fix this? The red square jumps. Is it possible to scale smoothly with CSS Transition at all like in the gallery in the link at the beginning?
What do you mean by "jumps"? Try this, jumps too?
section {
background-color: rgba(0, 0, 0, 0.701961);
width: 400px;
height: 400px;
}
div {
position: absolute;
top: 120px;
left: 120px;
width: 160px;
height: 160px;
background-color: red;
-webkit-transition: -webkit-transform 0.4s;
transition: transform 0.4s;
}
div:hover {
-webkit-transform: scale(1.8) rotate(0.01deg);
transform: scale(1.8) rotate(0.01deg);
}
<section>
<div></div>
</section>
Also, you could try the variant with a container for an image (like in the first link of your question).
JSFiddle
.banner {
position: relative;
z-index: 1;
cursor: pointer;
border: 1px solid #dfe2e5;
background: #000;
width: 310px;
height: 150px;
-webkit-transition: border-color 0.1s;
transition: border-color 0.1s;
overflow: hidden;
}
.banner:hover {
border-color: #bdc1c5;
}
.banner__image-container {
overflow: hidden;
height: 100%;
}
.banner__image {
-webkit-transition: all 0.4s;
transition: all 0.4s;
}
.banner:hover .banner__image {
-webkit-transform: scale(1.15) rotate(0.01deg);
transform: scale(1.15) rotate(0.01deg);
opacity: 0.5;
}
<div class="banner">
<div class="banner__image-container">
<img class="banner__image" src="https://picsum.photos/310/150/?image=1022"/>
</div>
</div>
I sometimes solve strange jumps on transition by adding rotate(0.01deg) on the transform property, like so:
.element:hover {
transform: scale(1.5) rotate(0.01deg);
}
I am using following code to display a hidden div on hover. I'm using the CSS transition property for to fade in the hidden div. Is it possible to slide in the hidden (for example from left to right) div instead of fading in using the CSS only?
Here's my code:
HTML
<div class="box">
<img src="http://farm9.staticflickr.com/8207/8275533487_5ebe5826ee.jpg">
<div class="hidden"></div>
</div>
CSS
.box{
position: relative;
}
.box .hidden{
background: yellow;
height: 300px;
position: absolute;
top: 0;
left: 0;
width: 500px;
opacity: 0;
transition: all 1s ease;
}
.box:hover .hidden{
opacity: 1;
}
Demo:
http://jsfiddle.net/u2FKM/
Something like this?
DEMO
And the code I used:
.box{
position: relative;
overflow: hidden;
}
.box:hover .hidden{
left: 0px;
}
.box .hidden {
background: yellow;
height: 300px;
position: absolute;
top: 0;
left: -500px;
width: 500px;
opacity: 1;
-webkit-transition: all 0.7s ease-out;
-moz-transition: all 0.7s ease-out;
-ms-transition: all 0.7s ease-out;
-o-transition: all 0.7s ease-out;
transition: all 0.7s ease-out;
}
I may also add that it's possible to move an elment using transform: translate(); , which in this case could work something like this - DEMO nr2
Just to add my answer, it seems that the transitions need to be based on initial values and final values within the css properties to be able to manage the animation.
Those reworked css classes should provide the expected result :
.box{
position: relative;
top:0px;
left:0px;
width:0px;
}
.box:hover .hidden{
opacity: 1;
width: 500px;
}
.box .hidden{
background: yellow;
height: 300px;
position: absolute;
top: 0px;
left: 0px;
width: 0px;
opacity: 0;
transition: all 1s ease;
}
<div class="box">
<a href="#">
<img src="http://farm9.staticflickr.com/8207/8275533487_5ebe5826ee.jpg"></a>
<div class="hidden"></div>
</div>
http://jsfiddle.net/u2FKM/2199/
I added the vendor prefixes, and changed the animation to all, so you have both opacity and width that are animated.
Is this what you're looking for ? http://jsfiddle.net/u2FKM/3/
transition-property:width;
This should work. you have to have browser dependent code
This may be the good solution for you: change the code like this very little change
.box{
position: relative;
}
.box:hover .hidden{
opacity: 1;
width:500px;
}
.box .hidden{
background: yellow;
height: 334px;
position: absolute;
top: 0;
left: 0;
width: 0;
opacity: 0;
transition: all 1s ease;
}
See demo here