Header + Nav — 모바일 햄버거 메뉴

넓은 화면과 좁은 화면에서 메뉴가 다르게 동작해야 합니다

10초 핵심 요약

01

Header 기본 구조

// src/components/Header.astro
---
const { siteName } = Astro.props;
---
<header class="site-header">
  <a href="/" class="site-header__logo">{siteName}</a>
  <nav class="site-header__nav">...</nav>
</header>
.site-header {
  display: flex;
  justify-content: space-between; /* 로고는 왼쪽 끝, 메뉴는 오른쪽 끝 */
  align-items: center;
}
02

햄버거 버튼과 .open 토글 — 라이브 데모

예상해보세요 — 아래 버튼을 누르면 메뉴가 나타나야 합니다. 이 동작을 만드는 JS 코드는 몇 줄일까요?

MySite
  • 카테고리
  • 소개
// script.js
function toggleMenu(btn) {
  const nav = document.querySelector('.site-header__nav');
  const isOpen = nav.classList.toggle('open');
  btn.setAttribute('aria-expanded', isOpen);
}

classList.toggle()는 클래스가 있으면 빼고 없으면 붙이는 함수입니다. 메뉴가 열려있는지 여부를 true/false 변수로 따로 저장하지 않고, .open 클래스가 있는지 없는지로만 판단합니다. CSS도 이 클래스 하나만 보고 반응합니다.

.site-header__nav { max-height: 0; overflow: hidden; transition: max-height .25s; }
.site-header__nav.open { max-height: 300px; }
03

aria-expanded — 스크린 리더를 위한 신호

aria-expanded는 화면에 보이지 않지만, 스크린 리더 사용자에게 "이 버튼을 누르면 펼쳐지는 요소가 있고, 지금 열려있는지 닫혀있는지"를 알려줍니다. 시각적으로 아무 차이가 없어도 접근성에 중요한 속성입니다.

04

Day 18 완료 체크리스트

justify-content: space-between으로 로고/메뉴를 양 끝 배치했다.
햄버거 버튼 클릭 시 .open 클래스가 토글되는 걸 확인했다.
aria-expanded 속성의 목적을 설명할 수 있다.
스스로 설명해보기 — 메뉴가 열렸는지 여부를 변수 대신 .open 클래스로 관리하는 이유를 설명할 수 있나요?

오늘의 용어

justify-content: space-between
자식 요소들을 양 끝으로 밀어 배치하는 Flex 속성
classList.toggle()
클래스가 있으면 제거, 없으면 추가하는 JS 메서드
aria-expanded
접힘/펼침 상태를 스크린 리더에 알리는 접근성 속성