Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery direction-aware hover with CSS3 transition

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:

Mouse in from bottom Mouse in from right

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.

like image 401
Levi Cole Avatar asked Jan 20 '16 12:01

Levi Cole


2 Answers

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

like image 121
vals Avatar answered Nov 20 '22 06:11

vals


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

like image 1
iMoses Avatar answered Nov 20 '22 06:11

iMoses