반응형
반응형 헤더 작업 시 유의사항
1. 반응형 레이아웃 설계
📌 브레이크포인트 정의
- 중요 이유: 브레이크포인트가 일관되지 않으면 예기치 않은 레이아웃 깨짐이 발생.
- 팁: SCSS 사용하는 경우 @mixin media($device) 식으로 공통 처리하면 유지보수 용이
📌 디자인 일관성 유지
- 각 해상도에서 메뉴 순서, 로고 위치, 버튼 형태가 다르면 사용자 혼란.
→ 예: PC에선 오른쪽에 있는 메뉴가 모바일에서 맨 아래로 가면 UX가 불편해짐
2.내비게이션 메뉴 처리
📌 메뉴 개수에 따른 처리
- 메뉴가 많으면 PC에서는 가로로 충분하지만, 모바일에서는 한 줄에 다 안 들어감.
→ 가로 스크롤, 아코디언, "더보기" 처리 등으로 설계 필요.
📌 서브 메뉴가 있는 경우
- PC: hover로 보여주는 드롭다운
- 모바일: 클릭/터치 시 열리는 아코디언 구조 필요
- 주의: hover 기반 구조는 터치 디바이스에서 작동하지 않음 → JS로 toggle 필요
3. 접근성
📌 aria-label, aria-expanded 활용
- aria-label="메뉴 열기": 스크린리더가 버튼의 기능을 설명하는 역할로 토글에 따라 다른 텍스트 제어가 필요하지 않음
- aria-expanded="true/false": 현재 상태 전달하므로, 토글에 따라 js로 true/false 변경 필요
<button class="menu-toggle" aria-label="메뉴 열기" aria-expanded="false">☰</button>
- 스크린리더 사용자(예: VoiceOver, NVDA)는 버튼에 접근했을 때 아래와 같이 들을 수 있음:
- 처음 접근 시: "메뉴 열기, 버튼, 펼쳐지지 않음" (aria-label="메뉴 열기" + aria-expanded="false")
- 버튼을 클릭해서 메뉴가 열리면: "메뉴 열기, 버튼, 펼쳐짐"(aria-expanded="true"로 변경되었기 때문)
기능 | 접근성 효과 |
시각적 아이콘 (☰) | 의미 전달이 어려움 → aria-label로 보완 |
상태 정보 | aria-expanded로 현재 메뉴 상태 전달 |
동작 | 키보드, 스크린리더 사용자가 메뉴를 조작할 수 있음 |
역할 구분 | <button> 태그로 명확한 역할 전달 (링크와 구분) |
📌 시맨틱 태그 사용
- <nav>: 내비게이션 영역임을 명시
- <button>: 햄버거 메뉴 클릭 요소는 <a> 대신 <button>을 반드시 사용해야 함
- <ul><li><a>: 목록형 메뉴 구조는 접근성 + 키보드 탐색에 적합
4. 터치/모바일 UX 최적화
📌 터치 영역 확보
- 모바일에서는 44px x 44px 이상 클릭 가능한 영역 확보가 필요 (애플/구글 가이드 기준)
- 버튼이나 메뉴 간격이 좁으면 오작동 가능성이 있음
📌 스크롤 방지 처리
- 모바일에서 메뉴가 열렸을 때 배경 스크롤이 되면 UX 혼란
- 해결 방법
document.body.style.overflow = 'hidden'; // 메뉴 열릴 때
document.body.style.overflow = ''; // 메뉴 닫힐 때
📌 키보드 탐색
- Tab 키로 포커스 이동이 되고, Enter 또는 Space로 메뉴를 열 수 있어야 함
- Escape로 메뉴 닫기 기능도 UX 향상에 도움이 됨
5. 스타일 및 애니메이션 처리
📌 자연스러운 슬라이드
- max-height vs transform 비교:
- max-height: 콘텐츠 높이 제한으로 슬라이드처럼 보이게 할 수 있음 (간단함). 높이는 충분히 높은 임의 값 지정
- transform: translateY(), opacity: GPU 가속 → 부드럽고 성능 좋음 (하지만 구조 복잡할 수 있음)
- max-height는 CSS 애니메이션에 사용하기 좋지만, 콘텐츠 높이가 유동적인 경우 JavaScript로 실제 높이를 측정해 style.maxHeight = nav.scrollHeight + "px" 형태로 설정하는 방법도 있음
📌 transition 성능
- 속성별 transition 성능 차이:
- 좋음: transform, opacity, color
- 나쁨: height, width, top, left (layout 재계산 발생)
- 성능 민감할 땐 transform 기반 slide 방식 고려
6. 레이어 구조 및 위치 이슈
📌 메뉴 위치 결정
- 모바일에서 메뉴가 헤더 아래에 뜰지, 전체 화면을 덮을지 기획단에서 확정 필요
- position: absolute 또는 fixed 중 선택
📌 스크롤 시 고정 여부
- 헤더를 고정할지 말지에 따라 콘텐츠 여백 설정이 달라짐
- position: sticky → 최근 많이 쓰이는 방법
- position: fixed → 화면 상단 고정, top offset 고려해야 함
7. 유지보수성과 확장성
📌 변수/믹스인 활용
- SCSS라면 $breakpoint-mobile, $header-height, $z-index-header 등으로 통일된 값 사용
- @mixin mobile 같은 구조를 쓰면 미디어쿼리 일관성 높음
📌 네이밍 규칙
- BEM 방식 추천:
- .header, .header__inner, .gnb, .gnb__list, .menu-toggle
- 의미가 명확하고 구조 추적이 쉬움
📌 JS 최소화
- 복잡한 이벤트 처리 대신 class 토글 중심으로 작성
- 외부 라이브러리 없이 가벼운 vanilla JS로 구현 가능
8. 테스트 사항
📌 다양한 기기/브라우저 테스트
- 데스크탑: Chrome, Firefox, Edge, Safari
- 모바일: Android Chrome, iOS Safari → 필수 확인
- 반응형 뷰 툴이 아닌 실제 기기로 확인 추천
📌 키보드/스크린리더 테스트
- 키보드로 포커스 이동해 보며 탭 순서, 메뉴 열림/닫힘 여부 확인
- 스크린리더(TalkBack, VoiceOver)로 햄버거 버튼의 설명이 읽히는지 확인
📌 graceful degradation
- JS가 꺼졌을 때도 최소한 메뉴에 접근은 가능해야 함
- 메뉴를 기본적으로 보이게 처리하고, JS로 닫히게 바꾸는 방식도 가능
유의사항
항목 | 설명 |
슬라이드 방식 | max-height로 구현 시, 콘텐츠 높이가 달라질 경우 최대값 충분히 확보 필요 (ex. 500px) |
위치 | position: absolute + top: 100%을 사용해 header 바로 아래에 출력되도록 처리 |
접근성 | <button aria-label="메뉴 열기"> 사용 → 스크린리더도 메뉴 버튼 역할 인식 가능 |
구조 유지 | 마크업 변경 없이, CSS와 JS만으로 반응형 구현 가능 |
z-index | nav가 다른 콘텐츠 위에 오도록 z-index 필요 |
터치 UX | 메뉴 아이템 간격 충분히 확보 (padding, gap)하여 터치 쉽게 함 |
기본 반응형 헤더 구조
기본 마크업 예
<header class="header">
<div class="header__inner">
<h1 class="logo"><a href="/">MyLogo</a></h1>
<nav class="gnb">
<ul class="gnb__list">
<li><a href="#">Home</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
<button class="menu-toggle" aria-label="메뉴 열기" aria-expanded="false">☰</button>
</div>
</header>
<script>
const toggleBtn = document.querySelector('.menu-toggle');
const navList = document.querySelector('.gnb');
toggleBtn.addEventListener('click', () => {
const isOpen = navList.classList.toggle('active');
// classList.toggle(className) 해당클래스가 있으면 true,
없으면 false를 반환하여 불리언 값을 반환하여 제어 가능
toggleBtn.setAttribute('aria-expanded', isOpen)
})
</script>
[Responsive] header 기본 -1
...
codepen.io
반응형