I am struggling to get direction-aware hover and css transitions to work properly. Basically I am trying to have a grid of elements with a front and back face, and when on hover have a css transition to flip that element to show the back face.
Transition example (without direction-aware): fiddle
As you can see, no matter which way your mouse enters an element it always flips up. I want it to flip whichever way the mouse enters in/out.
Example:
And here is my attempt with direction-aware: fiddle
I am using jQuery to add classes relevant to the mouse in/out direction.
.hover-in-top {}
.hover-in-right {}
.hover-in-bottom {}
.hover-in-left {}
.hover-out-top {}
.hover-out-right {}
.hover-out-bottom {}
.hover-out-left {}
As you can see from the direction-aware example it kind of works but there are major glitches which I can't get my head round. (I've been overthinking this and my brain has just imploded.)
Anyway I hope this makes sense. Thanks.
I have a partial solution to your question.
But I needed to change some of the transitions to animations
$('.box-container .box').each(function() {
$(this).on('mouseenter mouseleave', function(e) {
var $this = $(this),
width = $this.width(),
height = $this.height();
var x = (e.pageX - $this.offset().left - (width / 2)) * (width > height ? (height / width) : 1),
y = (e.pageY - $this.offset().top - (height / 2)) * (height > width ? (width / height) : 1);
// top = 0, right = 1, bottom = 2, left = 3
var dir_num = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180) / 90) + 3) % 4,
directions = ['top', 'right', 'bottom', 'left'];
// If mouse enter
if (e.type === 'mouseenter') {
// Remove all hover out classes
$this.removeClass(function(index, css) {
return (css.match(/(^|\s)hover-out-\S+/g) || []).join(' ');
});
// Add in direction class
$this.addClass('hover-in-' + directions[dir_num]);
}
// If mouse leave
if (e.type === 'mouseleave') {
// Remove all hover in classes
$this.removeClass(function(index, css) {
return (css.match(/(^|\s)hover-in-\S+/g) || []).join(' ');
});
// Add out direction class
$this.addClass('hover-out-' + directions[dir_num]);
}
});
});
* {
box-sizing: border-box;
}
.box-container {
padding: 20px;
width: 600px;
}
.box-container:after {
content: '';
display: block;
clear: both;
}
.box-container .box {
float: left;
width: 50%;
height: 200px;
position: relative;
perspective: 600px;
border: 1px solid transparent;
}
.box-container .box .front, .box-container .box .back {
float: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform-style: preserve-3d;
backface-visibility: hidden;
transition: all 1s ease-in-out;
color: white;
font-size: 60px;
}
.box-container .box .front {
background: blue;
transform: rotateX(0) rotateY(0);
z-index: 900;
}
.box-container .box .back {
background: red;
z-index: 800;
}
.box-container .box:hover .front {
z-index: 900;
}
.box-container .box:hover .back {
z-index: 1000;
transform: rotateX(180) rotateY(0);
}
.box-container .box.hover-in-top .front,
.box-container .box.hover-out-bottom .back {
transform: rotateX(-179deg) rotateY(0);
}
.box-container .box.hover-in-top .back,
.box-container .box.hover-out-bottom .front {
animation: Xminus 1s ease-in-out;
}
@keyframes Xminus {
from {transform: rotateX(179deg) rotateY(0);}
to {transform: rotateX( 0deg) rotateY(0);}
}
.box-container .box.hover-in-bottom .front,
.box-container .box.hover-out-top .back {
transform: rotateX(179deg);
}
.box-container .box.hover-in-bottom .back,
.box-container .box.hover-out-top .front {
animation: Xplus 1s ease-in-out;
}
@keyframes Xplus {
from {transform: rotateX(-179deg) rotateY(0);}
to {transform: rotateX( 0deg) rotateY(0);}
}
.box-container .box.hover-in-right .front,
.box-container .box.hover-out-left .back {
transform: rotateY(-179deg);
}
.box-container .box.hover-in-right .back,
.box-container .box.hover-out-left .front {
animation: Yminus 1s ease-in-out;
}
@keyframes Yminus {
from {transform: rotateX(0deg) rotateY(179deg);}
to {transform: rotateX(0deg) rotateY( 0deg);}
}
.box-container .box.hover-in-left .front,
.box-container .box.hover-out-right .back {
transform: rotateY(179deg);
}
.box-container .box.hover-in-left .back,
.box-container .box.hover-out-right .front {
animation: Yplus 1s ease-in-out;
}
@keyframes Yplus {
from {transform: rotateX(0deg) rotateY(-179deg);}
to {transform: rotateX(0deg) rotateY( 0deg);}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box-container">
<div class="box">
<div class="front">FRONT</div>
<div class="back">BACK</div>
</div>
<div class="box">
<div class="front">FRONT</div>
<div class="back">BACK</div>
</div>
<div class="box">
<div class="front">FRONT</div>
<div class="back">BACK</div>
</div>
<div class="box">
<div class="front">FRONT</div>
<div class="back">BACK</div>
</div>
</div>
The problem with animations if that if you leave the div before the animation has ended, the animation will break
But if move slowly, and stay on the divs until the animation ends, this will work ok.
I hope that somebody finds a better solution
I believe that the best way to approach the problem is not to use CSS transitions.
You can easily implement it using jQuery's animate
, utilizing jQuery animations queue to keep all of your animations synced.
I modified your example to animate the transition in JavaScript.
Code example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With