본문 바로가기
웹 프로그래밍/프론트엔드

[HTML/CSS] 사이드바 메뉴 만들기 : 늘어나는 2차 메뉴 만들기 feat. overflow: hidden

by me_in_sk 2023. 5. 22.
반응형

 

 

지난 포스팅에서는 transform 속성을 이용하여 미리 만들어둔 사이드바 메뉴를 화면 너머로 숨겨놨다가 나타나게 하는 방식으로 사이드바 메뉴를 만들었다. 잘못된 방식은 아니지만, 개인마다 사용하는 화면의 크기와 비율이 다르기 때문에 알맞다고 하기에는 부족한 느낌이 든다. 이번 포스팅에서는 실제로 너비가 늘어나며 메뉴가 등장하는 사이드바 메뉴를 만들어 보자.

 

 

우선 완성된 이미지를 보자

 

완성-메뉴
늘어나는 기능을 갖춘 사이드바 메뉴

 

화면의 좌측에 아이콘만 보이는 메뉴바가 마우스를 인식하면 늘어나게 되면서 2차 메뉴들이 나타나는 것을 볼 수 있지만, 이미지만 봐서는 지난 포스팅에서 만든 사이드바와의 차이를 알 수 없다. 지난 포스팅과 가장 큰 차이는 이번 포스팅에서 만들 사이드바 메뉴는 실제로 늘어나는 형태이기 때문에 위치를 수정할 필요가 없어 transform 속성을 이용하지 않는다는 것에 있다. 

 

 

지난 포스팅의 내용을 참고하고자 하면 아래의 링크를 참고하면 된다.

 

[HTML/CSS] 사이드바 메뉴 만들기 : 나타나는 2차 메뉴 만들기 feat. transform: translate

 

[HTML/CSS] 사이드바 메뉴 만들기 : 나타나는 2차 메뉴 만들기 feat. transform: translate

오늘은 사이드바 메뉴를 만들어 보자. 사이드 메뉴는 이름에 나와 있듯이 사이트의 상단에 위치한 일반적인 메뉴 바와 달리 사이트의 측면에 있는 메뉴 바를 일컫는다. 우리는 이런 사이드바 중

me-in-journey.com


 

기본 마크업부터 살펴보자

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">

<aside class="side-bar">
  <section class="side-bar__icon-box">
    <section class="side-bar__icon-1">
      <div></div>
      <div></div>
      <div></div>
    </section>
  </section>
  <ul>
    <li>
      <a href="#">
        <span><i class="fa-solid fa-cat"></i></span>
        <span>menu1</span>
      </a>
      <ul>
        <li><a href="#">text1</a></li>
        <li><a href="#">text2</a></li>
        <li><a href="#">text3</a></li>
        <li><a href="#">text4</a></li>
      </ul>
    </li>
    <li>
      <a href="#">
        <span><i class="fa-solid fa-dragon"></i></span>
        <span>menu2</span>  
      </a>
      <ul>
        <li><a href="#">text1</a></li>
        <li><a href="#">text2</a></li>
        <li><a href="#">text3</a></li>
        <li><a href="#">text4</a></li>
      </ul>
    </li>
    <li>
      <a href="#">
        <span><i class="fa-solid fa-dove"></i></span>
        <span>menu3</span>
      </a>
      <ul>
        <li><a href="#">text1</a></li>
        <li><a href="#">text2</a></li>
        <li><a href="#">text3</a></li>
        <li><a href="#">text4</a></li>
      </ul>
    </li>
    <li>
      <a href="#">
        <span><i class="fa-solid fa-fish"></i></span>
        <span>menu4</span>
      </a>
      <ul>
        <li><a href="#">text1</a></li>
        <li><a href="#">text2</a></li>
        <li><a href="#">text3</a></li>
        <li><a href="#">text4</a></li>
      </ul>
    </li>
  </ul>
</aside>

 

위의 HTML 코드를 아무런 CSS 작업 없이 출력하면 아래와 같은 모습을 보인다.

 

마크업-메뉴
마크업 메뉴

 

우리가 원하는 형태의 무언가를 만들기 위해서는 아래와 같이 노멀라이즈 과정을 통해 필요하지 않은 속성들을 정리해줄 필요가 있다. 이러한 노멀라이즈 과정을 통해 우리가 원하지 않는 형태를 방해받지 않고 구성해 나갈 수 있게 된다.

 

 

/* 노멀라이즈 시작 */
body, ul, li {
  margin: 0;
  padding: 0;
  list-style: none;
}

a {
  color: inherit;
  text-decoration: none;
}
/* 노멀라이즈 끝 */

위의 노멀라이즈를 적용

노멀-메뉴
노멀라이즈가 적용된 메뉴

 

다음으로, 사이드바 메뉴를 만들기 이전에 overflow 속성에 대해 간단하게 알아보자. overflow 속성은 한정된 공간에 대하여 모자라거나 넘치는 콘텐츠를 제어할 수 있도록 해준다. 이에 아래와 같이 메뉴 요소가 사이드바를 넘어서는 것을 해결해 보자.

 

 

좁은 사이드바를 만들어 보자

/* 2차 메뉴 가두기 */
.side-bar > ul > li {
  position: relative;
}

/* 2차 메뉴 숨기기 */
.side-bar > ul ul {
  display: none;
  position: absolute;
  top: 0;
  left: 100%;
  width: 100%;
  background-color: #666;
}

body {
  background-color: #444;
  height: 3333px;
}

.side-bar {
  position: fixed;
  min-height: 100vh;
  width: 100px;
  background-color: black;
  transition: .5s;
}

.side-bar ul > li > a {
  display: block;
  color: white;
  font-size: 1.7rem;
  padding: 10px 20px;
  white-space: nowrap;
}

 

위의 속성들을 적용

넘친-메뉴
사이드바를 넘어선 메뉴

 

위의 이미지에서 우리가 지정한 사이드바의 공간을 메뉴 요소가 벗어난 것을 볼 수 있다. 이는 overflow의 hidden 값을 통해 해결할 수 있으며, hidden은 정해진 공간 밖으로 넘쳐 나오는 요소를 보이지 않도록 숨겨주는 역할을 한다.

이것을 이용하여 평상시 사이드바가 좁아진 형태일 때는 hidden을 통해 메뉴 요소를 숨기고, 마우스 인식 시에 사이드바가 늘어나면서 공간을 확장하는 것으로 자연스럽게 메뉴를 노출할 수 있다.

 

 

넘치는 메뉴를 숨겨보자

.side-bar {
  position: fixed;
  min-height: 100vh;
  width: 100px;
  background-color: black;
  overflow: hidden;	/* 넘치는 메뉴 요소 숨기기 */
  transition: .5s;
}

/* 마우스 인식 시 너비 확장 */
.side-bar:hover {
  width: 270px;
}

 

위의 속성들을 적용

숨김-메뉴
hidden이 적용된 사이드바

 

이번 포스팅에서 목표로 하던 핵심 기능이 구현되었다. 하지만 여기에는 숨겨진 이슈가 존재한다. 해당 이슈는 사이드바가 2차 메뉴를 갖는 것에서 발생하게 되는데, 사이드바의 overflow 속성이 hidden이면 2차 메뉴의 등장에 영향을 준다는 것이다.

이에 대한 해결 방법은 크게 두 가지다. 첫째는 2차 메뉴를 드롭다운 형식으로 구성하여 1차 메뉴 요소의 아래에 드롭다운으로 2차 메뉴를 표현하는 방법, 두 번째는 사이드바가 마우스를 인식하면 overflow 원래의 기본값인 visible 값으로 돌려주는 것이다. 여기서는 두 번째 방법을 구현해 보자.

 

 

2차 메뉴 구현

/* 2차 메뉴 공간 제한 해제 */
.side-bar:hover {
  width: 270px;
  overflow: visible;
}

.side-bar ul > li:hover > a {
  background-color: #888
}

.side-bar > ul > li:hover > ul {
  display: block;
}

/* 사이드바가 늘어나기 전 메뉴 노출 차단 */
.side-bar > ul > li > a > span:last-child {
  opacity: 0;
  transition: .5s .1s;
}

.side-bar:hover > ul > li > a > span:last-child {
  opacity: 1;
}

 

위의 속성들을 적용

2차-메뉴
늘어나는 2차 메뉴

 

overflow 속성이 visible로 변하는 순간 사이드바 내부의 메뉴들이 사이드바가 충분히 늘어나기 이전에 나타나는 것을 방지하고자 opacity 속성을 이용해 사이드바가 충분히 늘어날 때까지 자연스러운 모션을 구현해 주었다. 

다음으로 평상시의 사이드바에는 아이콘의 모습만 보이게 하여 깔끔한 느낌을 주는 등의 꾸미기만 해주면 간단한 사이드바 메뉴를 완성할 수 있다.

 

 

사이드바를 꾸며 보자

.side-bar > ul > li > a > span:first-child {
  position: relative;
  display: inline-block;
  border: 5px solid white;
  border-radius: 50%;
  width: 3rem;
  height: 3rem;
}

.side-bar > ul > li > a > span > i {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.side-bar > ul > li > a > span {
  vertical-align: middle;
}

 

위의 속성들을 적용

아이콘-메뉴
아이콘만 보이는 사이드바

쨔쟌-! 목표로 하는 기능을 갖춘 사이드바를 완성하였다. 이에 추가로 움직이는 화살표 아이콘을 추가한 종합 CSS 코드를 포스팅 아래에 첨부해 두었다. 이번 포스팅에서는 직접 늘어나는 사이드바 메뉴를 만들었으며, 해당 구조는 사이드바가 아니더라도 다양한 곳에서 사용할 수 있으니 구조를 이해하고 넘어가는 것을 추천하겠다. 다음 포스팅에서는 슬라이더에 대해 다뤄보도록 하자.

 

◆함께 보면 좋은 글

 


위 단계들의 종합 CSS 코드를 남기며 이번 포스팅을 마친다.

/* 노멀라이즈 시작 */
body, ul, li {
  margin: 0;
  padding: 0;
  list-style: none;
}

a {
  color: inherit;
  text-decoration: none;
}
/* 노멀라이즈 끝 */

/* 커스텀 시작 */

/* 사이드바-아이콘 시작 */
.side-bar__icon-box {
  display: flex;
  justify-content: flex-start;
  margin-left: 20px;
  margin-top: 20px;
  margin-bottom: 50px;
}

.side-bar__icon-1 {
  position: relative;
  width: 30px;
  height: 22px;
  margin: 15px;
  transition: .5s;
}

:root {
  --side-bar__icon: .5s;
}

.side-bar__icon-1 > div {
  position: absolute;
  width: 100%;
  height: 20%;
  background-color: white;
  transition: all var(--side-bar__icon);
}

.side-bar__icon-1 > div:nth-of-type(1) {
  top: 0;
  width: auto;
  left: 0;
  right: 0;
  transition: all var(--side-bar__icon), left calc(var(--side-bar__icon) / 2) calc(var(--side-bar__icon) / 2), right calc(var(--side-bar__icon) / 2) calc(var(--side-bar__icon) / 2), height calc(var(--side-bar__icon) / 2) 0s;
}

.side-bar__icon-1 > div:nth-of-type(2) {
  top: 40%;
  transform-origin:bottom left;
}

.side-bar__icon-1 > div:nth-of-type(3) {
  top: 80%;
  left: auto;
  right: 0;
  transform-origin:bottom right;
}

.side-bar:hover .side-bar__icon-1 > div:nth-of-type(2) {
  transform:rotate(45deg);
  width: 70.5%;
  height: 25%;
}

.side-bar:hover .side-bar__icon-1 > div:nth-of-type(3) {
  top: 40%;
  transform:rotate(-45deg);
  width: 70.5%;
  height: 25%;
}

.side-bar:hover .side-bar__icon-1 > div:nth-of-type(1) {
  left: 41%;
  right: 41%;
  height: 100%;
  transition: all var(--side-bar__icon), left calc(var(--side-bar__icon) / 2) 0s, right calc(var(--side-bar__icon) / 2) 0s, height calc(var(--side-bar__icon) / 2) calc(var(--side-bar__icon) / 2);
}
/* 사이드바-아이콘 끝 */

/* 사이드바-메뉴 시작 */
.side-bar > ul ul {
  display: none;
  position: absolute;
  top: 0;
  left: 100%;
  width: 100%;
  background-color: #666;
}

body {
  background-color: #444;
  height: 3333px;
}

.side-bar {
  position: fixed;
  min-height: 100vh;
  width: 100px;
  background-color: black;
  overflow: hidden;
  transition: .5s;
}

.side-bar ul > li > a {
  display: block;
  color: white;
  font-size: 1.7rem;
  padding: 10px 20px;
  white-space: nowrap;
}

.side-bar > ul > li > a > span:first-child {
  position: relative;
  display: inline-block;
  border: 5px solid white;
  border-radius: 50%;
  width: 3rem;
  height: 3rem;
  margin-right: 15px;
}

.side-bar > ul > li > a > span:last-child {
  opacity: 0;
}

.side-bar > ul > li > a > span > i {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.side-bar ul > li > a > span {
  vertical-align: middle;
}

.side-bar:hover {
  width: 270px;
  overflow: visible;
}

.side-bar:hover > ul > li > a > span:last-child {
  opacity: 1;
  transition: .5s .1s;
}

.side-bar ul > li:hover > a {
  background-color: #888
}

.side-bar > ul > li {
  position: relative;
}

.side-bar > ul > li:hover > ul {
  display: block;
}
/* 사이드바-메뉴 끝 */

/* 커스텀 끝 */
반응형

댓글