만들던 자기소개 페이지를 엎고 다시 시작했다. 레퍼런스를 찾으면 찾을수록 나의 밑천이 드러나 무척 힘들다. 정말 감각적인 디자인이나 쿨한 레이아웃은 많은데 도저히 모르겠다... 일단 내가 할 수 있는 범위에서 열심히 해보리다.
새롭게 자기소개 페이지를 만들며 예전에 봤던 귀여운 toggle 버튼 기능을 추가하려고 한다. 이제부터 시작!
버거라 불리는 흰 막대기 3개를 누르면 오른쪽에서 숨어있던 navigation bar가 튀어나오는 기능인데 css와 약간의 js로 만들 수 있다. width와 responsive와 translate 등 css 의 여러 개념이 들어가 다시 복습하기 좋은 기능이다.
먼저 html
<body>
<nav>
<div class="log">
<h4>The Nav</h4>
</div>
<ul class="nav-links">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Work</a></li>
</ul>
<div class="toggle">
<div class="line-1"></div>
<div class="line-2"></div>
<div class="line-3"></div>
</div>
</nav>
</body>
간단한 html 끝!
css
nav {
display: flex;
justify-content: space-around;
align-items: center;
background-color: sandybrown;
height: 8vh;
}
nav
전체에 height를 8vh만 주었다.
대략 이런 모습. 스타일링하는 것은 생략하고 nav-link(ul)
에 width 40%를 준다. 이제 햄버거 손질에 들어가면 된다.
.toggle div {
margin: 3px;
transition: all 0.3s ease;
width: 23px;
height: 3px;
background: black;
}
이제부터 반응형이다. 반응형은 아직도 잘 모르겠다. 직관적인 느낌으로 이해하기가 어려워 많이 배워야할 부분이다. 그럼 반응형 갑시다.
@media screen and (max-width: 1024px) {
.nav-links {
width: 60%;
}
}
하나씩 보자면 @media screen
이 부분은 브라우저에게 반응할 타입을 지정해주는 것이고 여기서는 screen이다 (max-width: 1024px)
이 부분은 screen의 최대 너비를 지정해주는 것인데 최대가 1024px이니 1024px보다 작은 screen에서 적용될 property를 아래 적으면 된다.
아이폰X에서 보았을 때
@media screen and (max-width: 768px) {
.nav-links {
background-color: rebeccapurple;
display: flex;
align-items: center;
flex-direction: column;
}
}
768px 이하에서 .nav-links
가 어떻게 변할지 지정해주는 것이다. 중요한 것만 보자면 direction을 column으로 바꿨다.
이제 저 녀석을 화면 오른쪽에 위치시켜야 한다.
@media screen and (max-width: 768px) {
.nav-links {
background-color: rebeccapurple;
display: flex;
align-items: center;
flex-direction: column;
position: absolute;
right: 0px;
top: 8vh;
}
}
주황 nav
의 height만큼 top에 8vh를 주었다. 이제 width와 height를 주면 된다.
@media screen and (max-width: 768px) {
.nav-links {
background-color: rebeccapurple;
display: flex;
align-items: center;
flex-direction: column;
position: absolute;
right: 0px;
top: 8vh;
height: 92vh;
width: 30%;
}
}
top에서 떨어진 만큼을 빼고 height에 92vh를 주었다.
얼추 모양이 잡혔다. 이제 저 햄버거 버튼을 누르면 보라색 ul이 오른쪽에서 튀어나오면 된다. 그러므로 화면 밖으로 일단 퇴장시켜야 한다.
transform: translateX(100%);
transition: transform 0.5s ease-in;
요 두 개를 추가해주면 되는데 transform: translateX(100%)
는 X축으로 100%만큼 이동하라는 것이다. 다시 말해 보라 ul이 차지하는 영역만큼 X축(오른쪽)으로 이동하면 된다. 음수면 당연히 반대인 왼쪽이 된다. transition: transform 0.5s ease-in
은 저 transform이 발동할 때 얼마나 앙증맞게 움직일지 결정하는 것인데 transform 이 녀석을 0.5초 동안 ease-in 한다 라는 뜻이다.
@media screen and (max-width: 768px) {
.nav-links {
background-color: rebeccapurple;
display: flex;
align-items: center;
flex-direction: column;
position: absolute;
right: 0px;
top: 8vh;
height: 92vh;
width: 30%;
transform: translateX(100%);
transition: transform 0.5s ease-in;
}
.nav-links li {
opacity: 0;
}
.nav-links .toggle {
display: block;
}
}
li
는 숨기고 .toggle
에는 block을 해준다.
이제 toggle(햄버거)를 달래야 한다. toggle 버튼을 누르면 toggle이 변하는 animation 을 줄 건데 js에서 classlist.toggle
을 해야하니 일단 toggle에 추가할 class만 만들어주면 된다. 3단 막대는 클릭하는 순간 "X"로 변할 것이다. 헷갈리니(내가) 하나씩 살펴보자.
.toggleAnimation .line-1 {
transform: rotate(-45deg)
}
.toggleAnimation .line-2 {
opacity: 0;
}
.toggleAnimation .line-3 {
transform: rotate(45deg)
}
첫 번째 line은 -45도 만큼 회전했고
두 번째 line은 종적을 감췄다. 그리고 세 번째는 45도 만큼 회전해 저런 모습이 되었다. 이제 첫 번째와 세번째 line을 살살 움직여 "X"를 만들면 된다.
.toggleAnimation .line-1 {
transform: rotate(-45deg) translate(-4px, 5px);
}
.toggleAnimation .line-2 {
opacity: 0;
}
.toggleAnimation .line-3 {
transform: rotate(45deg) translate(-3px, -5px);
}
자연스럽게 "X"가 되기 위해서는 약간의 노가다가 필요한데 하나씩 대입하면서 가장 자연스럽게 변하는 것을 찾으면 된다.
이제 저 햄버거 버튼을 누르면 "X"로 변한다. "X"가 되는 순간 숨어있던 보라 ul도 나와야 한다. js의 도움이 필요하기에
.nav-active {
transform: translateX(0%);
}
를 넣어주면 된다. class에 .nav-active
가 추가되면 보라 ul이 원래 자리로 나온다는 뜻이다.
이제 숨겼던 보라 ul 속 li을 나타나게 하면 된다. css의 @keyframes
문법을 사용한다. @keyframes은 시간에 변화에 따라 나타나거나 사라질 때 사용한다.
@keyframes navLinkFade {
from {
opacity: 0;
transform: translateX(5px);
}
to {
opacity: 1;
transform: translateX(0px);
}
}
navLinkFade
라는 animation이 적용되면 투명도가 0이고 X축으로 5px로 갔다 투명도가 1로 되면서 원점으로 돌아오게 된다. 이제 마지막 javascript 부분.
javascipt
const toggleBtn = document.querySelector(".toggle")
const ul = document.querySelector(".nav-links")
const li = document.querySelectorAll(".nav-links li")
function toggleHandler() {
toggleBtn.classList.toggle("toggleAnimation")
ul.classList.toggle("nav-active")
li.forEach((link, index) => {
console.log(link)
if (link.style.animation) {
link.style.animation = "";
} else {
link.style.animation = "navLinkFade 0.5s ease forwards 0.4s";
}
})
}
function init() {
toggleBtn.addEventListener("click", toggelHandler)
}
init()
보기에 요란하고 복잡한데 간단하게 설명하자면 init()
은 실행 함수고 init()
함수 안에는 소위 햄버거라 불리는 toggleBtn
를 누르면 toggleHandler
라는 함수를 실행할 것이라는 정의가 있다.
toggleHandler()
함수에는 총 3가지 이벤트가 있는데 toggle 버튼을 누를 때 "X"로 만드는toggleAnimation
을 활성화 할 거라는
toggleBtn.classList.toggle("toggleAnimation")
그리고 보라 ul이 튀어나오는 "nav-active"
를 ul에 추가할 것이라는
ul.classList.toggle("nav-active")
마지막으로 각 li에 navLinkFade
를 주는 forEach 함수가 있다.
li.forEach((link, index) => {
console.log(link, index)
if (link.style.animation) {
link.style.animation = "";
} else {
link.style.animation = `navLinkFade 0.5s ease forwards ${index / 3 + 1}s`;
}
})
forEach 함수를 후려치자면 각 li를 link라 하고 index는 link에 부여된 색인이다. 만약 link에 animation이 있으면 그냥 두고 없다면 navLinkFade
animation을 추가하는 건데 ease forwards 는 스리슬쩍 앞으로 나온다는 뜻이다.
forwards 뒤에 초(s)가 들어간다. 만약 link가 순서대로 하나씩 나오길 원한다면 각 index를 전체 li 수인 3으로 나눈 값에 1을 더한 ${index / 3 + 1}s 를 작성해주면 된다.
완성뀨