오늘은 마우스 클릭에 반응에 나타났다 사라지는 사이드 메뉴를 구현하는 방법을 알아보자.
우선 본격적으로 시작하기전에 새로운 selector들의 개념과 사용법을 알아두고 들어가자.
속성 선택자는 지정하는 속성을 가진 element만을 선택적으로 styling해주는 방식이다.
element[attribute="value"] { styling }
의 format으로 쓸 수 있다.
예를 들어
input[id="sidemenu"] { background: red; }
와 같이 써주면 id의 value로 sidemenu를
가지는 input element를 선택해 배경색을 red로 주겠다는 의미이다.
pseudo-class selector는 element가 특정한 상태에 있을 때를 styling 해주는 selector를 의미한다.
input[id="check"]: checked { /* input type="checkbox"라고 가정 */ background: blue; }
위와 같이 쓰면 id가 check인 input element가 checked상태일 때만
배경색을 파랗게 바꿔주겠다는 것을 의미한다.
Adjacent Sibling Combinator(인접 형제 선택자)는
두 개의 element를 선택, 전자 바로 다음에 오는 후자 element를 styling해준다.
input[id="check"] + label { background: black; }
이렇게 써주면 id의 value로 "check"를 가지는 input element
바로 다음에 오는 label element의 배경색을 black으로 바꿔준다.
이상 모든 selector들은 다른 selector들과 함께 사용할 수 있다.
기본적인 메커니즘은 checkbox를 하나 만들고, pseudo-class selector를 활용해
그 checkbox가 check 된 상태인지 아닌지에 따라
다른 element의 styling을 바꾸는 방식으로 사이드 메뉴를 화면에
표현했다가 치웠다가 하는 것이다.
우선 checkbox를 만들어준다.
<input type="checkbox" id="sidemenu">
이를 CSS에서 styling 해준다.
input[id="sidemenu"] { display: none; }
여기서 display의 value none는 화면에 렌더링되지는 않지만 계속 브라우저 상에서
존재하고, 동작하게 element를 styling 해준다는 것을 의미한다.
<label for="sidemenu"> </label>
이 label element의 크기를 css에서 다음과 같이 조정한다.
input[id="sidemenu"] + label { display: blocked; width: 60px; height: 40px; cursor: pointer; background: yellowgreen; }
여기까지 하고 브라우저에서 불러오면 checkbox는 보이지 않지만 그 위치에 커서를
두면 커서의 모양이 바뀌는 것을 확인할 수 있다.
label의 모양을 만들고 이를 변형하는 것을 구현하면 보다 그럴싸한 sidemenu 구현이
가능해진다.
우선 <label> 안에 <span>를 3개 추가해준다.
이 span element들을 다음과 같이 styling 해준다.
input[id="sidemenu"] + label > span { display: block; width: 100%; height: 5px; border-radius: 30px; background: black; }
여기까지 하고 브라우저를 보면 다음과 같이 나타난다.
이제 각각의 span을 따로 styling해 위치를 바꿔줘야 한다.
각각의 span들에 class를 넣어 속성을 부여할 수도 있지만 여기서는 nth-child라는 키워드를 사용해본다.
css에 다음과 같이 추가하자.
input[id="sidemenu"] + label > span:nth-child(1) { top: 0px; } input[id="sidemenu"] + label > span:nth-child(2) { top:50%; } input[id="sidemenu"] + label > span:nth-child(3) { bottom: 0px; }
이렇게 해도 차이가 없는데, 각 span을 parent element(label)를 기준으로 배치하려면
label과 span에 position 속성을 부여해야 한다. 다음을 각 element에 대해 추가한다.
input[id="sidemenu"] + label { postition: relative; }
input[id="sidemenu"] + label > span { position: absolute; }
이 후, 브라우저에서 보면 다음과 같다.
두번째 span이 약간 아래로 밀린 이유는, element의 배치를 정할 때,
기준이 항상 왼쪽 상단부터 시작하기 때문이다. 이를 보정하기 위해 다음을 추가한다.
input[id="sidemenu"] + label > span:nth-child(2) { tranform: translateY(-50%) /* 자신의 크기의 -50%만큼 element 위치를 이동 */ }
이제 클릭에 따라 성질을 바꾸는 것을 css로 구현해보자.
앞에서 checkbox의 display 성질 값을 none으로 주면 화면상에 렌더링 되지는 않지만
여전히 동작하고 있다는 것을 다시 한 번 생각해보면 된다.
여기서 pseudo-class selector가 활용된다.
input[id="sidemenu"]:checked + label > span:nth-child(1) { top:50%; transform: translateY(-50%) rotate(45deg); /* 위치 조정, 객체 회전 */ }
input[id="sidemenu"]:checked + label > span:nth-child(2) { opactiy: 0; }
input[id="sidemenu"]:checked + label > span:nth-child(3) { top:50%; transform: translateY(50%) rotate(-45deg); }
여기까지 왔으면 label의 background값은 지워도 된다.
stripe 3개에서 x자로 span의 배치를 바꿀 때, 이 변화를 눈에 보일 정도로
서서히 보여주고 싶다면 transition 속성을 추가하면 된다. span의 성질에 다음과 같이
추가하자.
input[id="sidemenu"] + label > span { transition: all 0.35s; /* 오른쪽의 숫자가 변형 시간을 의미한다. */ }
이제 전에 했던 것과 마찬가지로 <div>을 만들고 그 안에 list들을 넣음으로써
메뉴를 구현해 볼 것이다. 다른 점이 있다면 화면에 렌더링이 되는지의 여부를 사용자가
클릭으로 바꿀 수 있다는 것이다.
label 하단에 다음과 같이 division을 추가한다.
<div id="header"> <ul> <li><a href="#">menu1</a></li> <li><a href="#">menu1</a></li> <li><a href="#">menu1</a></li> <li><a href="#">menu1</a></li> <li><a href="#">menu1</a></li> </ul> </div>
대응하는 css에서는 다음과 같이 써주면 된다.
#sidemenu + label + #header { position:fixed; /* 스크롤을 내려도 항상 같은 자리에 유지할 수 있게 하는 명령어 */ width: 300px; height: 100%; background: rgb(136, 136, 136); top: 0px; padding: 60px 25px 25px 25px; box-sizing:border-box; left:-300px; /* element의 크기만큼 화면 바깥으로 이동했으므로 보이지 않게 된다. */ transition: all 0.35s; }
#sidemenu:checked + label + #header { left: 0px; /* sidemenu가 체크된 상태라면 위치를 이동, 화면에 나타나게 만든다. */
이렇게 하고 span을 클릭하면 사이드 메뉴가 튀어나오게 되는데,
다시 클릭을 할 수 없게 된다. 이를 수정하기 위해 z-index를 추가해주면 된다.
label[id="sidemenu"] + label > span { z-index:2; }
이렇게 하면 열고 닫을 수 있는 기능을 포함한 사이드 메뉴가 완성된다.