Inspired by the menu on https://www.cssdesignawards.com/woty2017/
This is a great trick for a much more immersive menu.
A Pen by James Bosworth on CodePen.
<!-- @NOTE: the onclicks are used for touch devices since I'm lazy and didnt use <a> tags --> | |
<div class="Menu"> | |
<ul class="Menu-list" data-offset="10"> | |
<li class="Menu-list-item" data-offset="20" onclick> | |
Home | |
<span class="Mask"><span>Home</span></span> | |
<span class="Mask"><span>Home</span></span> | |
</li> | |
<li class="Menu-list-item" data-offset="16" onclick> | |
About | |
<span class="Mask"><span>About</span></span> | |
<span class="Mask"><span>About</span></span> | |
</li> | |
<li class="Menu-list-item" data-offset="12" onclick> | |
Work | |
<span class="Mask"><span>Work</span></span> | |
<span class="Mask"><span>Work</span></span> | |
</li> | |
<li class="Menu-list-item" data-offset="8" onclick> | |
Contact | |
<span class="Mask"><span>Contact</span></span> | |
<span class="Mask"><span>Contact</span></span> | |
</li> | |
</ul> | |
</div> |
var $menu = $('.Menu-list'), | |
$item = $('.Menu-list-item'), | |
w = $(window).width(), //window width | |
h = $(window).height(); //window height | |
$(window).on('mousemove', function(e) { | |
var offsetX = 0.5 - e.pageX / w, //cursor position X | |
offsetY = 0.5 - e.pageY / h, //cursor position Y | |
dy = e.pageY - h / 2, //@h/2 = center of poster | |
dx = e.pageX - w / 2, //@w/2 = center of poster | |
theta = Math.atan2(dy, dx), //angle between cursor and center of poster in RAD | |
angle = theta * 180 / Math.PI - 90, //convert rad in degrees | |
offsetPoster = $menu.data('offset'), | |
transformPoster = 'translate3d(0, ' + -offsetX * offsetPoster + 'px, 0) rotateX(' + (-offsetY * offsetPoster) + 'deg) rotateY(' + (offsetX * (offsetPoster * 2)) + 'deg)'; //poster transform | |
//get angle between 0-360 | |
if (angle < 0) { | |
angle = angle + 360; | |
} | |
//poster transform | |
$menu.css('transform', transformPoster); | |
//parallax for each layer | |
$item.each(function() { | |
var $this = $(this), | |
offsetLayer = $this.data('offset') || 0, | |
transformLayer = 'translate3d(' + offsetX * offsetLayer + 'px, ' + offsetY * offsetLayer + 'px, 20px)'; | |
$this.css('transform', transformLayer); | |
}); | |
}); |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> |
// === Variables ===== | |
$perspective: 60rem; | |
$font-size: 4.25rem; | |
$split-position: 49%; | |
$split-thickness: 4px; | |
$split-color: #FF2C75; | |
// === Settings ===== | |
%font-settings { | |
font-family: "Gilroy ExtraBold", system-ui, sans-serif; | |
font-style: normal; | |
font-weight: normal; | |
-webkit-font-smoothing: antialiased; | |
-webkit-font-kerning: normal; | |
-webkit-text-size-adjust: 100%; | |
} | |
// === Codepen Setup ===== | |
html, | |
body { | |
width: 100vw; | |
height: 100vh; | |
} | |
body { | |
@extend %font-settings; | |
background: linear-gradient(45deg, #02001F,#1F1B4E); | |
transform-style: preserve-3d; | |
transform: perspective($perspective); | |
position: fixed; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
// === Menu <ul> ===== | |
.Menu-list { | |
font-size: $font-size; | |
line-height: 1.2; | |
text-transform: uppercase; | |
text-align: center; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
transform: rotateX(-10deg) rotateY(20deg); // overwritten by JS | |
} | |
// === Menu item ===== | |
.Menu-list-item { | |
position: relative; | |
color: transparent; | |
cursor: pointer; | |
// === Split Line ===== | |
&::before { | |
content: ''; | |
display: block; | |
position: absolute; | |
top: $split-position; | |
left: -10%; | |
right: -10%; | |
height: $split-thickness; | |
border-radius: $split-thickness; | |
margin-top: -($split-thickness / 2); | |
background: $split-color; | |
transform: scale(0); | |
transition: transform .8s cubic-bezier(.16,1.08,.38,.98); | |
z-index: 1; | |
} | |
} | |
// === Top/bottom mask ===== | |
.Mask { | |
display: block; | |
position: absolute; | |
overflow: hidden; | |
color: $split-color; | |
top: 0; | |
height: $split-position; | |
transition: all .8s cubic-bezier(.16,1.08,.38,.98); | |
span { display: block; } | |
} | |
// === Bottom mask specific ===== | |
.Mask + .Mask { | |
top: $split-position - 0.1; | |
height: 100 - $split-position + 0.1; | |
span { transform: translateY(-$split-position); } | |
} | |
// === Where the fun stuff happens ===== | |
.Menu-list-item:hover, | |
.Menu-list-item:active { | |
.Mask { color: #FFF; transform: skewX(12deg) translateX(5px); } | |
.Mask + .Mask { transform: skewX(12deg) translateX(-5px); } | |
&::before { transform: scale(1); } | |
} |
<link href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/183516/gilroy-webfont.css" rel="stylesheet" /> |