<div class="layout">
<div class="hover">
<div class="content">Item 1</div>
<div class="overlay"></div>
</div>
<div class="hover">
<div class="content">Item 2</div>
<div class="overlay"></div>
</div>
<div class="hover">
<div class="content">Item 3</div>
<div class="overlay"></div>
</div>
<div class="hover">
<div class="content">Item 4</div>
<div class="overlay"></div>
</div>
<div class="hover">
<div class="content">Item 5</div>
<div class="overlay"></div>
</div>
<div class="hover">
<div class="content">Item 6</div>
<div class="overlay"></div>
</div>
</div>
.hover {
overflow: hidden;
perspective: 400px;
.overlay {
transform: translate3d(0, -100%, 0);
animation-duration: 0.6s;
animation-fill-mode: forwards;
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
// ENTER
&.mouseenter {
&.top {
perspective-origin: center top;
.overlay {
animation-name: swing--enter-top;
transform-origin: center top;
}
}
&.right {
perspective-origin: right center;
.overlay {
animation-name: swing--enter-right;
transform-origin: right center;
}
}
&.bottom{
perspective-origin: center bottom;
.overlay {
animation-name: swing--enter-bottom;
transform-origin: center bottom;
}
}
&.left {
perspective-origin: left center;
.overlay {
animation-name: swing--enter-left;
transform-origin: left center;
}
}
}
// LEAVE
&.mouseleave {
&.top {
perspective-origin: center top;
.overlay {
animation-name: swing--leave-top;
transform-origin: center top;
}
}
&.right {
perspective-origin: right center;
.overlay {
animation-name: swing--leave-right;
transform-origin: right center;
}
}
&.bottom {
perspective-origin: center bottom;
.overlay {
animation-name: swing--leave-bottom;
transform-origin: center bottom;
}
}
&.left {
perspective-origin: left center;
.overlay {
animation-name: swing--leave-left;
transform-origin: left center;
}
}
}
}
// ANIMATIONS
@keyframes swing--enter-top {
0% { transform: rotate3d(-1, 0, 0, 90deg); }
100% { transform: none; }
}
@keyframes swing--enter-right {
0% { transform: rotate3d(0, -1, 0, 90deg); }
100% { transform: none; }
}
@keyframes swing--enter-bottom {
0% { transform: rotate3d(1, 0, 0, 90deg); }
100% { transform: none; }
}
@keyframes swing--enter-left {
0% { transform: rotate3d(0, 1, 0, 90deg); }
100% { transform: none; }
}
@keyframes swing--leave-top {
0% { transform: none; }
100% { transform: rotate3d(-1, 0, 0, 90deg); }
}
@keyframes swing--leave-right {
0% { transform: none; }
100% { transform: rotate3d(0, -1, 0, 90deg); }
}
@keyframes swing--leave-bottom {
0% { transform: none; }
100% { transform: rotate3d(1, 0, 0, 90deg); }
}
@keyframes swing--leave-left {
0% { transform: none; }
100% { transform: rotate3d(0, 1, 0, 90deg); }
}
/**
* BASIC CSS FOR DEMO PURPOSE
*/
body {
font-family: system-ui;
background: #f06d06;
color: white;
text-align: center;
}
.layout {
width: 800px;
margin: 0 auto;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.hover {
background-color: #4472C4;
position: relative;
display: flex;
flex: 1 1 30%;
margin: 1%;
height: 150px;
align-items: center;
justify-items: center;
}
.content {
flex: 1;
text-align: center;
line-height: 150px;
}
.overlay {
position: absolute;
height: 100%;
width: 100%;
background-color: #f08080;
text-align: center;
}
View Compiled
/*
* Get the direction by which an element as been hovered.
*
* It is done by determining in which quadrant is the mouse
* inside the element when mouseenter/mouseleave event starts.
* This is done using trigonometry on the pointer position
* relative to the center of the element.
* @see https://freelance-drupal.com/node/79 for details
*
* @param event
* The event triggering the computation.
*
* @result string
* Can be 'top', 'right', 'bottom', 'left' depending on the situation.
*/
const getHoverDirection = function (event) {
var directions = ['top', 'right', 'bottom', 'left'];
var item = event.currentTarget;
// Width and height of current item
var w = item.offsetWidth;
var h = item.offsetHeight;
// Calculate the x/y value of the pointer entering/exiting, relative to the center of the item.
// Scale (sort of normalize) the coordinate on smallest side to the scale of the longest.
var x = (event.clientX - item.getBoundingClientRect().left - (w / 2)) * (w > h ? (h / w) : 1);
var y = (event.clientY - item.getBoundingClientRect().top - (h / 2)) * (h > w ? (w / h) : 1);
// Calculate the angle to the center the pointer entered/exited
// and convert to clockwise format (top/right/bottom/left = 0/1/2/3).
var d = Math.round(Math.atan2(y, x) / 1.57079633 + 5) % 4;
return directions[d];
};
document.addEventListener('DOMContentLoaded', function (event) {
// Loop over items (in a IE11 compatible way).
var items = document.getElementsByClassName('hover');
for (var i = 0; i < items.length; i++) {
// Loop over the registered event types.
['mouseenter', 'mouseleave'].forEach(function (eventname) {
items[i].addEventListener(eventname, function (event) {
// Retrieve the direction of the enter/leave event.
var dir = getHoverDirection(event);
// Reset classes.
// event.currentTarget.className = 'item hover';
// > If support for IE11 is not needed.
// event.currentTarget.classList.remove('mouseenter', 'mouseleave', 'top', 'right', 'bottom', 'left');
// > If support for IE11 is needed.
event.currentTarget.classList.remove('mouseenter');
event.currentTarget.classList.remove('mouseleave');
event.currentTarget.classList.remove('top');
event.currentTarget.classList.remove('right');
event.currentTarget.classList.remove('bottom');
event.currentTarget.classList.remove('left');
// Add the event and direction classes.
// > If support for IE11 is not needed.
// event.currentTarget.classList.add(event.type, dir);
// > If support for IE11 is needed.
event.currentTarget.className += ' ' + event.type + ' ' + dir;
}, false);
});
}
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.