Direction-aware hover effect
by avgustre
HTML
<header>
<div class='container'>
<h1>Direction-aware hover effect</h1>
<p>CSS & bits of JS</p>
</div>
</header>
<div class='container'>
<ul>
</ul>
</div>
SCSS
@import url(https://fonts.googleapis.com/css?family=Bree+Serif);
$duration: 300ms;
$timing-fn: ease;
$turquoise: #1ABC9C;
$wet-asphalt: #34495E;
$midnight-blue: #2C3E50;
$clouds: #ECF0F1;
/* the important bits */
li {
perspective: 400px;
}
.info {
// hide-initial-state
transform: rotate3d(1,0,0, 90deg);
width: 100%;
height: 100%;
padding: 20px;
position: absolute;
top: 0;
left: 0;
border-radius: 4px;
pointer-events: none;
background-color: transparentize($turquoise, .1);
}
.in-top .info {
transform-origin: 50% 0%;
animation: in-top $duration $timing-fn 0ms 1 forwards;
}
.in-right .info {
transform-origin: 100% 0%;
animation: in-right $duration $timing-fn 0ms 1 forwards;
}
.in-bottom .info {
transform-origin: 50% 100%;
animation: in-bottom $duration $timing-fn 0ms 1 forwards;
}
.in-left .info {
transform-origin: 0% 0%;
animation: in-left $duration $timing-fn 0ms 1 forwards;
}
.out-top .info {
transform-origin: 50% 0%;
animation: out-top $duration $timing-fn 0ms 1 forwards;
}
.out-right .info {
transform-origin: 100% 50%;
animation: out-right $duration $timing-fn 0ms 1 forwards;
}
.out-bottom .info {
transform-origin: 50% 100%;
animation: out-bottom $duration $timing-fn 0ms 1 forwards;
}
.out-left .info {
transform-origin: 0% 0%;
animation: out-left $duration $timing-fn 0ms 1 forwards;
}
@keyframes in-top {
from {transform: rotate3d(-1,0,0, 90deg)}
to {transform: rotate3d(0,0,0, 0deg)}}
@keyframes in-right {
from {transform: rotate3d(0,-1,0, 90deg)}
to {transform: rotate3d(0,0,0, 0deg)}}
@keyframes in-bottom {
from {transform: rotate3d(1,0,0, 90deg)}
to {transform: rotate3d(0,0,0, 0deg)}}
@keyframes in-left {
from {transform: rotate3d(0,1,0, 90deg)}
to {transform: rotate3d(0,0,0, 0deg)}}
@keyframes out-top {
from {transform: rotate3d(0,0,0, 0deg)}
to {transform: rotate3d(-1,0,0, 104deg)}}
@keyframes out-right {
from {transform: rotate3d(0,0,0, 0deg)}
to ...
JavaScript
// - Noel Delgado | @pixelia_me
const nodes = [].slice.call(document.querySelectorAll('li'), 0);
const directions = {
0: 'top',
1: 'right',
2: 'bottom',
3: 'left'
};
const classNames = ['in', 'out'].map(p => Object.values(directions).map(d => `${p}-${d}`)).reduce((a, b) => a.concat(b));
const getDirectionKey = (ev, node) => {
const {
width,
height,
top,
left
} = node.getBoundingClientRect();
const l = ev.pageX - (left + window.pageXOffset);
const t = ev.pageY - (top + window.pageYOffset);
const x = l - width / 2 * (width > height ? height / width : 1);
const y = t - height / 2 * (height > width ? width / height : 1);
return Math.round(Math.atan2(y, x) / 1.57079633 + 5) % 4;
};
class Item {
constructor(element) {
this.element = element;
this.element.addEventListener('mouseover', ev => this.update(ev, 'in'));
this.element.addEventListener('mouseout', ev => this.update(ev, 'out'));
}
update(ev, prefix) {
this.element.classList.remove(...classNames);
this.element.classList.add(`${prefix}-${directions[getDirectionKey(ev, this.element)]}`);
}
}
nodes.forEach(node => new Item(node));