HTML
.menu-toggle
우측 상단에 위치할 햄버거 메뉴 토글
nav
햄버거 메뉴 토글을 클릭하면 우측에서 등장할 a링크들+p문단
-->> .nav-link로 a 링크 관리하고, 크기를 large 클래스와 small 클래스로 구분
-->> .contact 클래스에 연락처 공간
.logo
좌측 상단에 위치할 로고
.welcome
좌측 중단에 위치할 홈페이지 소개글
.button
좌측 소개글 아래에 위치할 더보기 버튼
.img
홈페이지 소개글 우측 중단에 위치할 이미지
<body>
<div class="menu-toggle">
<span></span>
<span></span>
<span></span>
</div>
<nav class="nav">
<div class="nav-left">
<ul>
<li class="nav-link"><a class="large" href="#">About</a></li>
<li class="nav-link"><a class="large" href="#">Our Work</a></li>
<li class="nav-link"><a class="large" href="#">Contact</a></li>
<li class="nav-link"><a class="large" href="#">Web Design</a></li>
<li class="nav-link"><a class="small" href="#">eCommerce</a></li>
<li class="nav-link"><a class="small" href="#">Blog</a></li>
</ul>
<div class="contact">
<p class="large">Get in touch</p>
<p class="small">01234 567891</p>
<p class="small">woolee@gmail.com</p>
</div>
</div>
<div class="nav-right"></div>
</nav>
<div class="logo">COMPANY LOGO</div>
<div class="welcome">
<h1 class="message">hamburger navigation tutorial</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex, rem labore ratione quidem dolorum ab laudantium harum minus? Earum modi magnam saepe, optio voluptatibus possimus voluptatum ratione tenetur distinctio accusantium.</p>
</div>
<div class="button">
<h4>See More</h4>
</div>
<div class="img">
<img src="./M1.jpg" alt="">
<div class="explore">
<h4>Explore</h4>
</div>
</div>
<script src="app.js"></script>
</body>
CSS
position:relatvie;의 경우 기준점을 자기 자신으로 잡는데, 이때 자기 자신이란 position:static;을 말한다. 즉, HTML 문서 상 원래 있어야 하는 위치(normal flow).
block인 div로 요소들을 잡았으므로 이걸 고려해서 위치를 잘 잡아야 한다.
.menu-toggle
위치 고정해두고
top/right으로 우측 상단에 위치시키고
flex-direction:column으로 span 태그 세로로 배치
버튼 클릭하면 active 클래스를 붙여 줄 것이고
active 붙으면 회전하도록 transform 부여
그리고 active 붙었을 때의 span을 45deg로 꺾어서 'x' 표현하기
가운데 span은 감춰주고
.nav-left
햄버거 메뉴 토글을 클릭하면 등장할 .nav-left
평소에는 left:-50%로 감춰두고
active 클래스가 붙으면 left:0;으로 보여주기
.nav-right
얘도 햄버거 메뉴 토글을 누르면 .nav-left 오른쪽에 등장할 검은색 배경인데 얘도 평소에는 left:-50%;로 숨겨뒀다가
active가 붙으면 left:50%;로 .nav-left 오른쪽에 배치하기
.nav-link
흰색 바탕 안에 있는 링크들도 순차적으로 등장하는 인터랙션 구현을 위해
얘네도 left:-10%;로 숨겨뒀다가
active가 붙으면 left:0%;로 보여주기
.contact
이번에 컨택은 left 위치로 지우는 게 아니라 opacity:0;으로 지워뒀다가 active 붙으면 opacity:1;로 보여주기
.logo
좌측 상단 로고
얘도 active가 붙으면 하얀색 배경 위에 놓이므로 그때는 어두운 색상으로 변경해주기
.welcome
top: 값을 보면 position:relative;이므로 원래 normal flow로 기본적으로 중간에 밀려 있는 상태에서 30vh만 준거라고 생각하면 된다.
.button
:hover하면 흰색 배경으로 채워넣기
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
a {
text-decoration: none;
color: black;
}
a:hover {
opacity: 0.5;
}
.large {
font-size: 1.2rem;
text-transform: uppercase;
}
.small {
font-size: 0.8rem;
color: #161616a9;
}
body {
background: #272c2c;
}
.menu-toggle {
position: fixed;
z-index: 9999;
right: 5%;
top: 4rem;
width: 2rem;
height: 2rem;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: space-around;
transition: 0.5s;
}
.menu-toggle.active {
transform: rotate(-180deg);
}
.menu-toggle span {
background: #ffffff;
width: 100%;
height: 3px;
}
.menu-toggle.active span:nth-child(1) {
position: absolute;
background: #ffffff;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(45deg);
}
.menu-toggle.active span:nth-child(2) {
opacity: 0;
}
.menu-toggle.active span:nth-child(3) {
position: absolute;
background: #ffffff;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-45deg);
}
nav {
position: fixed;
height: 100vh;
width: 100%;
z-index: 100;
pointer-events: none;
}
.nav.active {
pointer-events: none;
}
.nav-left {
position: relative;
z-index: 10;
left: -50%;
top: 0;
width: 50%;
height: 100vh;
background-color: #ffffff;
transition: 0.8s;
}
.nav-left.active {
left: 0;
transition: 0.5s;
}
.nav-left ul {
position: relative;
top: 35%;
left: 10%;
height: 30%;
display: flex;
flex-direction: column;
justify-content: space-between;
list-style: none;
}
.nav-right {
position: absolute;
z-index: 9;
left: -50%;
top: 0;
width: 50%;
height: 100vh;
background-color: #000000;
transition: 0.8s;
}
.nav-right.active {
left: 50%;
transition: 0.5s;
}
.nav-link {
opacity: 0;
position: relative;
left: -10%;
}
.nav-link.active {
opacity: 1;
transition: 0.5s;
left: 0;
}
.contact {
position: absolute;
opacity: 0;
bottom: 10%;
left: 0;
pointer-events: none;
}
.contact.active {
opacity: 1;
left: 10%;
transition: 0.5s;
}
.logo {
position: fixed;
top: 4rem;
left: 5%;
z-index: 100;
color: white;
font-size: 1.5rem;
text-transform: uppercase;
pointer-events: none;
transition: 1s;
}
.logo.active {
color: #000000;
}
.welcome {
color: rgb(255, 255, 255);
position: relative;
left: 5%;
top: 30vh;
width: 40%;
text-transform: uppercase;
}
p {
margin-top: 1rem;
}
.button {
position: relative;
z-index: 1;
color: white;
border: 1px solid white;
left: 5%;
top: 35vh;
border: 1px solid white;
width: 8rem;
padding: 0.2rem;
text-align: center;
transition: 0.5s;
}
.button:hover {
cursor: pointer;
background-color: white;
color: #272c2c;
transition: 0.5s;
}
.img {
position: relative;
left: 50%;
top: 10vh;
height: 400px;
}
img {
height: 100%;
filter: grayscale(40%);
}
.explore {
position: absolute;
text-align: center;
line-height: 33.5px;
background: black;
cursor: pointer;
color: white;
padding: 1.5rem;
text-transform: uppercase;
bottom: 0;
left: 0;
width: 20%;
height: 20%;
}
.explore:hover {
opacity: 0.6;
}
JS
.menu-toggle을 클릭하면
차례대로 navRight, navLeft, logo, nav 모두 active 클래스를 붙여준다.
classList.toggle의 경우 클래스 유무를 체크해서 없으면 add, 있으면 remove
클래스를 붙인 상태에서
contact과 navRight은 일단 active 클래스를 지워 두고,
if문을 걸어서 active 클래스가 있으면 active를 navRight에 추가해주고
for문 순회하면서 active 제거 하고 다시 차례대로 active 클래스를 추가해주는데, 추가 순서를 i*100으로 시간을 지정해줌으로써 차례대로 인터랙션 구현하도록
--
우측 상단 클릭 버튼에 닫기와 열기가 모두 구현되어 있도록 하기 위해서
classList.toggle로 구현한 거고,
다만 active 클래스가 붙어 있으면
열리는 순서를 주기 위해서 일단 contact/navRight을 지워뒀다가 (navLeft는 먼저 active 붙은 상태)
navRight의 경우 left:50%;까지 와야 하므로 setTimeout으로 먼저 active 추가해주고
navLinks도 한번 지워줬다가 다시 navLinks 순회하면서 active 추가해줘서 순서를 맞추는 방법. 그 다음에 contact 열어주는 순서로.
이렇게 순서를 navLeft >> navRight >> navLinks[i] >> contact 로 잡으면
navRight이 오래걸리므로 navRight과 navLinks[i] 열리는 속도가 거의 비슷해진다.
let menuTog = document.querySelector('.menu-toggle');
let nav = document.querySelector('.nav');
let navLeft = document.querySelector('.nav-left');
let navRight = document.querySelector('.nav-right');
let navLinks = Array.from(document.querySelectorAll('.nav-link'));
let contact = document.querySelector('.contact');
let logo = document.querySelector('.logo');
menuTog.addEventListener('click', () => {
menuTog.classList.toggle('active');
navRight.classList.toggle('active');
navLeft.classList.toggle('active');
logo.classList.toggle('active');
nav.classList.toggle('active');
// Remove active class to restart delayed effect
contact.classList.remove('active');
navRight.classList.remove('active');
if (menuTog.classList.contains('active')) {
setTimeout(() => {
navRight.classList.add('active');
}, 100)
for (let i=0; i<navLinks.length; i++) {
navLinks[i].classList.remove('active');
setTimeout(() => {
navLinks[i].classList.add('active')
}, i * 100)
}
setTimeout(() => {
contact.classList.add('active');
}, 700)
}
})
참고