4/28(화) HTML, CSS 기초

허경수·2026년 4월 28일

프론트엔드

목록 보기
19/29

🎓 CSS 실전: hover로 열리는 사이드바 + 중첩 메뉴 만들기 🗂️

position: fixed, transition, ::after 가상 요소까지 —
지금까지 배운 CSS 개념을 총동원해서 실무형 사이드바 메뉴를 만들어봅니다!


1. 완성 결과물 미리보기 👀

  • 평소에는 사이드바가 화면 왼쪽에 숨어있다가
  • 마우스를 올리면 스르르 나타납니다
  • 메뉴 아이템에 hover하면 하위 메뉴가 오른쪽으로 펼쳐집니다
  • 열려있는 메뉴는 [+], 닫힌 메뉴는 [-]로 표시됩니다

2. 📝 HTML 구조

<h1>to2.kr/br9</h1>

<!-- 사이드바 -->
<div class="side-bar">

  <!-- 열림/닫힘 아이콘 -->
  <div class="icon-status">
    <div></div>  <!-- 닫힌 상태 아이콘 -->
    <div></div>  <!-- 열린 상태 아이콘 -->
  </div>

  <!-- 중첩 메뉴 -->
  <nav class="menu-box-1">
    <ul>
      <li>
        <a href="#">1차 메뉴 아이템 1</a>
        <ul>
          <li><a href="#">2차 메뉴 아이템 1</a></li>
          <li>
            <a href="#">2차 메뉴 아이템 2</a>
            <ul>
              <li><a href="#">3차 메뉴 아이템 1</a></li>
              <li><a href="#">3차 메뉴 아이템 2</a></li>
              <li><a href="#">3차 메뉴 아이템 3</a></li>
            </ul>
          </li>
          <li><a href="#">2차 메뉴 아이템 3</a></li>
        </ul>
      </li>
      <li><a href="#">1차 메뉴 아이템 2</a></li>
      <li><a href="#">1차 메뉴 아이템 3</a></li>
      <li>
        <a href="#">1차 메뉴 아이템 4</a>
        <ul>
          <li><a href="#">2차 메뉴 아이템 1</a></li>
          <li><a href="#">2차 메뉴 아이템 2</a></li>
          <li><a href="#">2차 메뉴 아이템 3</a></li>
          <li>
            <a href="#">2차 메뉴 아이템 4</a>
            <ul>
              <li><a href="#">3차 메뉴 아이템 1</a></li>
              <li><a href="#">3차 메뉴 아이템 2</a></li>
              <li><a href="#">3차 메뉴 아이템 3</a></li>
              <li><a href="#">3차 메뉴 아이템 4</a></li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </nav>
</div>

<!-- 본문 -->
<div class="con">
  Lorem ipsum dolor, sit amet consectetur...
</div>

🔍 메뉴 계층 구조

ul (1차)
 ├── li > a "1차 메뉴 아이템 1"
 │    └── ul (2차)
 │         ├── li > a "2차 메뉴 아이템 1"
 │         ├── li > a "2차 메뉴 아이템 2"
 │         │    └── ul (3차)
 │         │         ├── li > a "3차 메뉴 아이템 1"
 │         │         └── ...
 │         └── li > a "2차 메뉴 아이템 3"
 ├── li > a "1차 메뉴 아이템 2"
 └── ...

3. 🎨 전체 CSS 코드

/* 노멀라이즈 */
body, ul, li {
  margin: 0;
  padding: 0;
  list-style: none;
}
a {
  color: inherit;
  text-decoration: none;
}

/* 사이드바 */
.side-bar {
  position: fixed;
  top: 0;
  left: -270px;
  width: 300px;
  height: 100%;
  background-color: #efefef;
  transition: background-color .4s, left .4s, color .4s;
}
.side-bar:hover {
  left: 0;
  color: white;
}
.side-bar:hover, .side-bar > .menu-box-1 > ul ul {
  background-color: black;
}

/* 아이콘 */
.side-bar > .icon-status > div {
  text-align: right;
  padding: 5px;
}
.side-bar > .icon-status > div:last-child {
  display: none;
}
.side-bar:hover > .icon-status > div:last-child {
  display: block;
}
.side-bar:hover > .icon-status > div:first-child {
  display: none;
}

/* 메뉴 */
.side-bar > .menu-box-1 ul > li {
  position: relative;
}
.side-bar > .menu-box-1 ul > li > a {
  display: block;
  font-weight: bold;
  padding: 10px;
  white-space: nowrap;
}
.side-bar > .menu-box-1 ul > li:hover > a {
  background-color: white;
  color: black;
}

/* [+] / [-] 아이콘 */
.side-bar > .menu-box-1 ul > li > a:not(:only-child)::after {
  content: "[+]";
}
.side-bar > .menu-box-1 ul > li:hover > a:not(:only-child)::after {
  content: "[-]";
}

/* 하위 메뉴 */
.side-bar > .menu-box-1 > ul ul {
  display: none;
  position: absolute;
  left: 100%;
  top: 0;
  width: 200px;
}
.side-bar > .menu-box-1 ul > li:hover > ul {
  display: block;
}

/* 본문 */
.con {
  border: 10px solid red;
  width: 800px;
  margin-left: auto;
  margin-right: auto;
}

4. CSS 코드 단계별 설명 🎨

STEP 1 — 노멀라이즈

body, ul, li {
  margin: 0;
  padding: 0;
  list-style: none;
}
a {
  color: inherit;
  text-decoration: none;
}

💡 브라우저 기본 스타일 초기화. 모든 CSS 작업 전 가장 먼저 작성합니다.


STEP 2 — 사이드바 기본 설정

.side-bar {
  position: fixed;    /* 스크롤해도 항상 같은 자리에 고정 */
  top: 0;
  left: -270px;       /* 평소에는 화면 왼쪽 밖에 숨겨둠 */
  width: 300px;
  height: 100%;
  background-color: #efefef;
  /* 배경색, 위치, 글자색을 0.4초에 걸쳐 부드럽게 전환 */
  transition: background-color .4s, left .4s, color .4s;
}

💡 left: -270px이 핵심입니다. 너비 300px 중 270px을 화면 밖으로 밀어두고, 30px만 살짝 보이게 해서 사이드바의 존재를 암시합니다.

화면 왼쪽 끝:
|-270px ←   [사이드바 300px]  | 30px만 보임

STEP 3 — hover 시 사이드바 등장

.side-bar:hover {
  left: 0;        /* 화면 안으로 들어옴 */
  color: white;   /* 글자색 흰색으로 변경 */
}

/* hover 시 배경색 black으로 변경 (2차 이하 메뉴도 함께) */
.side-bar:hover, .side-bar > .menu-box-1 > ul ul {
  background-color: black;
}

💡 transition: left .4s가 적용되어 있어서 left: -270px → 0이 0.4초 동안 부드럽게 전환됩니다.

hover 전: [사이드바] → 왼쪽에 숨어있음
hover 후: [사이드바] → 스르르 나타남 (0.4초)

STEP 4 — 열림/닫힘 아이콘 전환

/* 기본: ▼(닫힌 상태) 표시, ▶(열린 상태) 숨김 */
.side-bar > .icon-status > div:last-child {
  display: none;
}

/* hover 시: ▶ 표시, ▼ 숨김 */
.side-bar:hover > .icon-status > div:last-child {
  display: block;
}
.side-bar:hover > .icon-status > div:first-child {
  display: none;
}
상태:first-child (▼):last-child (▶)
기본보임숨김
hover숨김보임

STEP 5 — 메뉴 아이템 스타일

/* 하위 메뉴의 기준점 설정 */
.side-bar > .menu-box-1 ul > li {
  position: relative;
}

/* 링크를 block으로 — 클릭 영역 확장 */
.side-bar > .menu-box-1 ul > li > a {
  display: block;
  font-weight: bold;
  padding: 10px;
  white-space: nowrap;  /* 텍스트 줄바꿈 방지 */
}

/* hover 시 해당 메뉴 아이템 강조 */
.side-bar > .menu-box-1 ul > li:hover > a {
  background-color: white;
  color: black;
}

💡 position: relativeli에 준 이유는, 하위 ulposition: absolute로 배치할 때 기준점이 되기 위해서입니다!


STEP 6 — [+] / [-] 아이콘 자동 표시

/* 하위 메뉴가 있는 항목 뒤에 [+] 표시 */
.side-bar > .menu-box-1 ul > li > a:not(:only-child)::after {
  content: "[+]";
}

/* hover 시 [-]로 변경 */
.side-bar > .menu-box-1 ul > li:hover > a:not(:only-child)::after {
  content: "[-]";
}

💡 :not(:only-child)의 의미 — "유일한 자식이 아닌 경우" 즉, 형제 요소(하위 ul)가 있는 a 태그에만 적용합니다.

하위 메뉴 없음: 1차 메뉴 아이템 2        (::after 없음)
하위 메뉴 있음: 1차 메뉴 아이템 1 [+]   (::after = "[+]")
hover 후:      1차 메뉴 아이템 1 [-]    (::after = "[-]")

STEP 7 — 하위 메뉴 펼침 효과

/* 기본: 하위 ul 숨김 */
.side-bar > .menu-box-1 > ul ul {
  display: none;
  position: absolute;  /* li(relative) 기준으로 배치 */
  left: 100%;          /* 부모 li의 오른쪽에 붙임 */
  top: 0;
  width: 200px;
}

/* hover 시: 하위 ul 표시 */
.side-bar > .menu-box-1 ul > li:hover > ul {
  display: block;
}

hover 전:
[1차 메뉴 아이템 1 [+]]

hover 후:
[1차 메뉴 아이템 1 [-]] [2차 메뉴 아이템 1]
                         [2차 메뉴 아이템 2 [+]]
                         [2차 메뉴 아이템 3]
                                          ↑
                                  left: 100% → 오른쪽에 붙음

STEP 8 — 본문 영역

.con {
  border: 10px solid red;
  width: 800px;
  margin-left: auto;
  margin-right: auto;
}

5. 📖 이 예제에서 사용한 개념 총정리

개념사용 위치역할
position: fixed.side-bar스크롤해도 고정
left: -270px.side-bar화면 밖에 숨기기
transition.side-bar부드러운 슬라이드 효과
position: relativeli하위 메뉴의 기준점
position: absolute하위 ulli 오른쪽에 붙이기
display: none/block하위 ul, 아이콘hover 시 보이기/숨기기
::aftera:not(:only-child)[+] / [-] 아이콘
:not(:only-child)a하위 메뉴 있는 항목만 선택
white-space: nowrapa텍스트 줄바꿈 방지

0개의 댓글