<div class="menu-02" id="js-menu-02"><a class="menu-02__btn" href="#">
<div class="menu-02__icon">
<div class="menu-02__icon-bar"></div>
<div class="menu-02__icon-bar"></div>
<div class="menu-02__icon-bar"></div>
</div>
</a>
<div class="menu-02__content">
<div class="menu-02__bg">
<div class="menu-02__bg-item"></div>
<div class="menu-02__bg-item"></div>
<div class="menu-02__bg-item"></div>
<div class="menu-02__bg-item"></div>
</div>
<div class="menu-02__links">
<li><a class="menu-02__link" href="#">LINK 01</a></li>
<li><a class="menu-02__link" href="#">LINK 02</a></li>
<li><a class="menu-02__link" href="#">LINK 03</a></li>
<li><a class="menu-02__link" href="#">LINK 04</a></li>
</div>
</div>
</div>
.menu-02#js-menu-02
a.menu-02__btn(href='#')
.menu-02__icon
.menu-02__icon-bar
.menu-02__icon-bar
.menu-02__icon-bar
.menu-02__content
.menu-02__bg
.menu-02__bg-item
.menu-02__bg-item
.menu-02__bg-item
.menu-02__bg-item
.menu-02__links
each link in links
li
a.menu-02__link(href=link.link) #{ link.text }
{
"links": [
{
"link": "#",
"text": "LINK 01"
},
{
"link": "#",
"text": "LINK 02"
},
{
"link": "#",
"text": "LINK 03"
},
{
"link": "#",
"text": "LINK 04"
}
]
}
$BLOCK_NAME: '.menu-02';
// 変数
$color_primary: #00bfa6;
$color_white: #fff;
$color_black: #4a4a4a;
$duration_default: 0.5s;
#{ $BLOCK_NAME } {
&__btn {
position: fixed;
top: 0;
right: 0;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
width: 72px;
height: 48px;
background: $color_primary;
}
&__icon {
position: relative;
transform: translateY(-2px);
}
&__icon-bar {
position: absolute;
left: -15px;
width: 30px;
height: 2px;
background: $color_white;
transition: all $duration_default;
transform-origin: center center;
@at-root #{ $BLOCK_NAME }__btn:hover & {
background: $color_black;
}
&:nth-child(1) {
top: -10px;
@at-root #{ $BLOCK_NAME }__btn.is-active & {
top: 0;
transform: rotate(-45deg);
}
}
&:nth-child(2) {
top: 0;
@at-root #{ $BLOCK_NAME }__btn.is-active & {
opacity: 0;
}
}
&:nth-child(3) {
top: 10px;
@at-root #{ $BLOCK_NAME }__btn.is-active & {
top: 0;
transform: rotate(45deg);
}
}
}
&__content {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
display: none;
}
&__bg-item {
position: absolute;
top: 0;
bottom: 0;
width: 0;
background: $color_primary;
transform-origin: right;
&:nth-child(1) {
left: 0;
}
&:nth-child(2) {
left: 25%;
}
&:nth-child(3) {
left: 50%;
}
&:nth-child(4) {
left: 75%;
}
}
&__links {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
max-width: 300px;
transform: translate(-50%, -50%);
}
&__link {
display: block;
padding: 6px;
font-size: 24px;
font-weight: bold;
color: $color_white;
text-align: center;
opacity: 0;
transition: color $duration_default;
transform: translateX(-20px);
&:hover {
color: $color_black;
}
}
}
'use strict';
import { gsap } from 'gsap';
export const menu02 = ()=> {
const menu = new Menu02('js-menu-02');
menu.init();
}
class Menu02 {
el: HTMLElement;
btnEl: HTMLElement;
bgEls: NodeListOf<HTMLElement>;
contentEl: HTMLElement;
linkEls: NodeListOf<HTMLElement>;
constructor(elId: string) {
this.el = document.getElementById(elId);
if (!this.el) return;
this.btnEl = this.el.querySelector('.menu-02__btn');
this.bgEls = this.el.querySelectorAll('.menu-02__bg-item');
this.contentEl = this.el.querySelector('.menu-02__content');
this.linkEls = this.el.querySelectorAll('.menu-02__link');
}
/**
* 初期化
*/
init(): void {
if (!this.el) return;
this.onClickHandler();
}
/**
* メニューを開く
*/
open(): void {
this.btnEl.classList.add('is-active');
const tl = gsap.timeline();
tl.set(this.contentEl, {
display: 'block'
})
.to(this.bgEls, {
duration: .2,
width: '26%',
stagger: {
each: 0.1
}
})
.to(this.linkEls, {
delay: .2,
duration: .3,
x: 0,
opacity: 1
});
}
/**
* メニューを閉じる
*/
close(): void {
this.btnEl.classList.remove('is-active');
const tl = gsap.timeline();
tl.set(this.bgEls, {
width: '25%'
})
.to(this.linkEls, {
duration: .3,
x: 20,
opacity: 0
})
.to(this.bgEls, {
delay: .2,
duration: .2,
scaleX: 0,
stagger: {
each: 0.1
}
})
.set([this.contentEl, this.bgEls, this.linkEls], {
clearProps: 'all'
});
}
/**
* ボタンクリック時の挙動設定
*/
onClickHandler(): void {
this.btnEl.addEventListener('click', e => {
e.preventDefault();
if (this.btnEl.classList.contains('is-active')) {
this.close();
} else {
this.open();
}
});
}
}