※ 해당 포스트는 http://100dayscss.com/의 2번 글의 설명을 위해 작성자가 다시 재구성한 포스팅입니다.

※ 무단 스크랩은 허용하지 않습니다.





햄버거 버튼이라고 불리는 메뉴 버튼을 만들어보겠습니다.

우선 눈에 잘 띄도록 배경부터 지정을 해보겠습니다.


먼저 width, height이 150px인 정사각형을 만들었고, 밋밋하지 않게하기 위해 정사각형에 약간의 box-shadow를 입힌 상태입니다. box-shadow를 모르시겠다면 여기를 클릭하세요.

다음에는 우리가 만든 녹색 상자 안에 버튼처럼 생긴 컴포넌트들을 안에다가 넣어줘 보겠습니다.


See the Pen ybQXLd by Munkyu Yang (@moonformeli) on CodePen.



/* 추가된 부분 */ 을 주목해서 봐주세요. .line 클래스를 가지는 3개의 div를 추가해 width, height, margin를 갖고 있죠? 그리고 딱딱해보이지 않도록 역시 box-shadow와 border-radius를 설정해주었습니다. 


여기서 주목할만한 부분은, #wrapper div의 상태 값이 position:absolute로 변경되었습니다. 이 이유는, CSS에서는 부모의 position 속성이 absolute 혹은 relative면 그 자식의 position이 absolute, relative일 경우 기준점이 부모의 좌측 최 상단에서부터(0,0 지점) 시작됩니다. 지금 보고 계시는 예제는 #wrapper의 시작 위치가 윈도우의 좌측상단으로 정해져있고 따로 움직이지 않았기때문에 여기서는 #wrapper의 position을 설정하지 않아도 괜찮습니다. 그런데 이 것을 움직이게 될 경우에는 자식 태그들을 position으로 움직이려면(특히 absolute의 경우) 정말 먼 길을 달려가야만 하겠죠? 그리고, 부모-자식 관계를 position으로 묶으면 추후에 코드 유지보수에도 많은 도움이 됩니다.


그리고 .line을 감싸는 #line-wrapper를 추가해 cursor에 대한 상태 값을 지정해 주었습니다. 이렇게 하지 않고 .line의 cursor를 변경하면, .line은 3개의 div이기 때문에 그 사이에 존재하는 공백(background)에서는 cursor가 적용되지 않습니다.


See the Pen XRygRK by Munkyu Yang (@moonformeli) on CodePen.


자, 여기서부터 조금씩 복잡해지기 시작합니다.


우선,

jQuery의 선택자에 대해 모르시는 분은 잠깐 보고 오세요.

- 선택자

- toggleClass

CSS의 animation에 대해 모르시는 분은 잠깐 보고 오세요.

- animation - w3schools

- animation - Youtube tutorial video by NetNinja (추천)


제 아무리 CSS가 날고 기어도 CSS는 CSS일 뿐, 액션에 대한 영역은 JS에게 맡겨야 하는 상황이 오게 마련이죠..

추가된 jQuery를 봐주시기 바랍니다. JavaScript를 쓰지 않고 jQuery를 사용한 이유는 jQuery가 DOM제어에 더 특화되어 있고 JavaScript를 사용하는 것보다 쉽게 구현할 수 있습니다. (편하신 분들은 JavaScript를 사용하셔도 괜찮습니다.)


.line들의 부모 div인 #line-wrapper를 클릭하게되면 각각의 아이디에 맞는 div를 찾아 각각 개별적인 클래스 네임을 부여해줍니다. toggleClass를 이용하면 경우의 수에 따라 addClass, removeClass를 매번 해줘야하는 상황을 피할 수 있죠. 저는 toggleClass를 더 선호하는 편입니다. 물론 내부적인 동작은 같을 겁니다.


추가된 CSS 코드에서는, 예를 들어, .line-top 클래스가 적용이 될 경우에 어떤 속성 값을 받을 건지를 설정을 해주었는데요. @keyframes를 사용하면 좀 더 복잡한 애니메이션 효과를 쉽게 구현할 수 있습니다. 직접 transform으로 구현해도 상관없지만 그럴 경우엔 transition까지 같이 사용해줘야하고, 애니메이션이 끝난 후에 상태를 어떻게 놔둘 것인지도 직접 정해줘야해서 까다로워지죠. forwards 속성을 지정하지 않으면 애니메이션이 끝남과 동시에 다시 처음의 상태로 돌아가게 됩니다. 저희는 이 다음의 애니메이션도 부여할 것이기 때문에 이대로 놔두겠습니다.



See the Pen ZKmymp by Munkyu Yang (@moonformeli) on CodePen.


추가된 CSS에서는 위, 아래의 .line이 겹쳐지고 난 후에 rotate 속성을 주어 회전하는 듯한 느낌을 주었습니다. 애니메이션을 저렇게 두 줄 이상으로 작성하게되면 첫 번째로 지정된 애니메이션부터 실행이되고 그 다음 순서로 넘어가게 됩니다. 여기서 두 번째 애니메이션을 순서에 맞게 진행시키고 싶다면, animation-delay 효과를 이용해야합니다. 그렇지 않으면 지정한 애니메이션이 모두 다 동시에 발생하게 되죠.  rotate을 할 때, translateY로 설정해주지 않으면 어떤 일이 일어날까요? .line-* 가 있었던 위치에서 rotate가 실행되게 됩니다. 왜냐하면, 지정한 애니메이션의 0% 지점에서 translateY를 따로 설정하지 않으면 자동적으로 초기 위치로 시작한다고 인식하기 때문입니다.

이제 다시 클릭을 했을 때 돌아가는 코드를 한 번에 보겠습니다.



See the Pen LyXjOM by Munkyu Yang (@moonformeli) on CodePen.


코드를 보시면 추가된 부분이 제법 많습니다. 우선 HTML을 보시면 .init 이라는 클래스를 지정해줬고 CSS에서는 이 클래스에서 animation을 none을 주고 우선순위를 부여합니다. 이렇게하는 이유는, 버튼을 다시 눌렀을 때 애니메이션을 반대로 지정해줘야 하는데 이런 기능을 가진 클래스를 처음부터 갖고 있으면 버튼을 누르기도 전에 reverse 애니메이션이 실행이 되어버립니다. 그런데 여기서 생각해야 할 것은, 애니메이션 실행 ↔ 애니메이션 반대로 실행 이 버튼의 클릭에 따라 한 가지만 실행이 되야하죠. 그리고 이러한 작업이 버튼 클릭에 따라 번갈아가면서 발생해야 합니다. 그 말은, .line-top에 있는 애니메이션은 그 반대의 애니메이션을 갖고 있는 .line-top-reverse와는 동시에 클래스로 존재해서는 안된다는 뜻이 됩니다.


그렇다면 버튼을 눌렀을 때 애니메이션이 실행되게 하기 위해선 버튼을 누른 후에 .line-top을 부여해줘야하고, 그 말은 다시, .line-top-reverse는 코드 실행 시작시에 처음으로 갖고 있는 클래스라는 뜻입니다. 그런데 윗 단락에서 설명한 것을 다시 말하자면, .line-top-reverse는 나름의 애니메이션을 갖고 있기 때문에, 코드 실행이 될 때 자동으로 실행이 되겠죠. 이 것을 어떻게 막냐,이 문제에 직면하게 됩니다. CSS에서는 조건문이라는 것이 없기 때문에 제어를 할 수가 없죠. 그래서 .init을 만들어 강제적으로 모든 애니메이션을 없애버린 것입니다. 그리고 jQuery 부분에서는 .line 클래스를 찾아 .init 클래스를 지워버리죠. 제가 만든 샘플 코드에서는 클릭 이벤트가 실행될 때마다 .init을 찾아 삭제하겠지만, 다른 방법들도 많으니 고민해보시기 바랍니다.


반대로 정의하고 싶은 애니메이션은 기존에 지정한 애니메이션을 반대로 작성해주기만 하면 금방이죠. 그런데 여기서 @keyframes line-mid-invisible에 주목해보세요. 의미없이 보이는 애니메이션이 들어가 있습니다. 시작과 끝에서 모두 scale로 같은 값을 지정한다는 것은 무슨 의미일까요? 저 부분은 그 자체로의 의미보다는 .mid-reverse 설정과 연결지어서 봐야합니다. 아무렇게나 만든 것 같은 line-mid-invisible 애니메이션이 먼저 지정이 되어 있고 그 다음에 본 애니메이션이 연결이 되어있죠.  이 것은 'animation delay'와 어느정도 연관이 있습니다.




최초의 클릭 후 애니메이션이 실행이 되면 클래스명의 네이밍은 어떻게 될까요. .line-mid이 생기고 .mid-reverse.init은 없어지겠죠.  그리고 다시 클릭하면 .mid-reverse 클래스명이 생기면서 reverse 애니메이션을 실행하게 될텐데, 우리가 원하는 #line-mid의 경우 rotate된 나머지 두 라인이 다시 원래대로 돌아올 때까지 기다렸다가 다음 애니메이션부터 같이 실행되길 원합니다. 그런 마음에서 animation-delay를 설정해 줬는데, 예상과는 다르게 애니메이션이 실행되기 전까지의 시간은 우리가 초기 속성값을 정해놓은 그 상태 그대로 기다리게 됩니다. 즉, 애니메이션 대기 큐에는 올라갔지만 기다리는 동안 이렇다할 상태변화가 없기 때문에 원래 갖고 있던 값 그대로 갖고 있는채로 기다리게 되는 것입니다. 


우리는 mid가 보이지 않았다가 서서히 나타나는 효과를 원했으므로, 애니메이션을 기다리는 동안(animation-delay)에도 계속 보이지 않는 상태로 유지시켜주면 더 좋겠죠. 그래서 scale을 0으로 만들고 기다리는 작업을 하고 있는 것입니다. 직접 한 번 실행해보면서 이해를 해보도록 하세요.


이로써 햄버거 메뉴 버튼 만들기는 끝났습니다. 기초적인 기능이지만 세련된 느낌을 줄 수 있는 좋은 효과이기때문에, 한 번 익혀놓으시면 다른 스타일로도 얼마든지 응용이 가능한 매우 유용한 기술입니다.


설명을 위해 글이 다소 길어졌지만 끝까지 읽어주셔서 감사합니다. 다음에는 다른 효과에 대해 알아보도록 하겠습니다.

+ Recent posts