HTML 구조화
HTML의 header부분이 매번 같은 코드가 반복되어 이를 분류하여 재사용하기로 하였다.
수정전
<!doctype html>
<html lang="ko-KR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HeaderHtml</title>
</head>
<body>
<!--헤더-->
<header
id="header"
class="h-20 border-b border-gray-300 bg-white dark:border-gray-700 dark:bg-gray-800 dark:text-white fixed top-0 left-0 right-0 z-50"
>
<div class="flex items-center">
<button
id="menuBtn"
class="cursor-pointer hover:border-white hover:rounded hover:bg-gray-100 dark:hover:bg-gray-700 flex justify-center items-center h-12 w-12 m-5"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-7 w-7 flex justify-center items-center"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
</button>
<div class="sm:ml-1 text-2xl flex gap-4 justify-center items-center">
<a href="./index.html" class="cursor-pointer">
<img
class="w-6 h-6 sm:w-[32px] sm:h-[32px]"
src="https://img.icons8.com/tiny-color/32/code.png"
alt="code"
/>
</a>
<h1 class="hidden sm:block text-2xl">개인 개발 블로그</h1>
<h1 class="block text-xl sm:hidden">개발 블로그</h1>
</div>
<div
class="relative flex justify-end items-center flex-grow mr-5 gap-2"
>
<div
id="searchWrap"
class="w-0 overflow-hidden transition-all duration-300 ease-out"
>
<input
id="searchInput"
type="text"
class="w-60 h-10 rounded-full bg-gray-100 dark:bg-gray-700 dark:text-gray-200 pl-4 pr-4 placeholder-gray-500"
placeholder="검색어를 입력해주세요."
/>
</div>
<button
id="searchBtn"
class="cursor-pointer hover:border-white hover:rounded hover:bg-gray-100 dark:hover:bg-gray-700"
>
<img
class="ml-auto"
width="40"
height="40"
src="https://img.icons8.com/ios-glyphs/40/search--v1.png"
alt="search--v1"
/>
</button>
</div>
<div class="relative ml-auto mr-10 w-8 h-8 hidden sm:flex">
<button
id="darkmode_btn"
class="w-full h-full hover:cursor-pointer group relative"
>
<!-- 큰 원 -->
<div
id="darkmode_toggle_position"
class="absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 w-12 h-12 bg-white border border-gray-400 rounded-full shadow-sm z-11 group-hover:bg-gray-100 dark:group-hover:bg-gray-700 dark:border-gray-600 dark:bg-gray-800"
></div>
<!-- 작은 원 -->
<div
class="absolute left-8 top-2 border rounded-full w-8 h-8 z-10 border-gray-400 bg-white shadow-sm group-hover:bg-gray-100 dark:group-hover:bg-gray-700 dark:border-gray-600 dark:bg-gray-800"
></div>
<!-- moon 아이콘 -->
<div class="duration-300 ease-out">
<img
id="moon_light"
class="absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 w-8 h-8 z-11 transition-all duration-300 ease-out"
src="https://img.icons8.com/ios-filled/50/do-not-disturb-2.png"
alt="sun--v1"
/>
<img
id="moon_dark"
class="absolute left-10 top-4 w-4 h-4 z-11 transition-all duration-300 ease-out"
src="../img/moon-dark.png"
alt="sun--v1"
/>
</div>
<!-- sun 아이콘 -->
<div class="duration-300 ease-out">
<img
id="sun_light"
class="absolute left-10 top-4 w-4 h-4 z-11 transition-all duration-300 ease-out"
src="https://img.icons8.com/ios-filled/50/sun--v1.png"
alt="do-not-disturb-2"
/>
<img
id="sun_dark"
class="absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 w-8 h-8 z-11 transition-all duration-300 ease-out"
src="../img/sun-dark.png"
alt="do-not-disturb-2"
/>
</div>
</button>
</div>
</div>
<!--메뉴바-->
<div
id="menuBar"
class="fixed border-r border-gray-300 transform -translate-x-full transition-transform duration-300 ease-out top-20 left-0 bg-gray-100 dark:bg-gray-900 dark:text-white flex w-100 h-full z-11"
>
<nav class="flex flex-col h-full w-full">
<div
class="border-b border-gray-700 bg-white dark:bg-gray-800 h-20 flex items-center"
>
<p class="text-2xl ml-5">메뉴</p>
<button
id="menuExitBtn"
class="cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-600 hover:rounded ml-auto mr-5"
>
<img
width="30"
height="30"
src="https://img.icons8.com/ios-filled/30/delete-sign--v1.png"
alt="delete-sign--v1"
/>
</button>
</div>
<div
class="flex items-center pt-4 pb-4 text-lg border-b border-gray-700"
>
<button
id="logout"
class="flex-1 hover:text-gray-500 hover:cursor-pointer dark:hover:text-gray-500"
>
로그아웃
</button>
<button
id="user"
class="flex-1 hover:text-gray-500 hover:cursor-pointer dark:hover:text-gray-500"
>
내정보
</button>
<a
id="login"
class="flex-1 text-center hover:text-gray-500 hover:cursor-pointer dark:hover:text-gray-500"
href="./login.html"
>로그인</a
>
<a
id="signup"
class="flex-1 text-center hover:text-gray-500 hover:cursor-pointer dark:hover:text-gray-500"
href="./signup.html"
>회원가입</a
>
</div>
<ul class="flex flex-col gap-12 mt-5 mb-5 text-2xl p-5">
<li>
<a
href="./index.html"
class="hover:text-gray-500 dark:hover:text-gray-500"
>Home</a
>
</li>
<li>
<a
href="./about.html"
class="hover:text-gray-500 dark:hover:text-gray-500"
>About</a
>
</li>
<li>
<a
href="./devLog.html"
class="hover:text-gray-500 dark:hover:text-gray-500"
>DevLog</a
>
</li>
<li>
<a href="" class="hover:text-gray-500 dark:hover:text-gray-500"
>연락처</a
>
</li>
</ul>
</nav>
</div>
</header>
<script type="module" src="/src/main.js"></script>
<script src="/components/menuBtn.js"></script>
<script type="module" src="/components/darkmode/darkmode_index.js"></script>
<script src="/components/searchBtn.js"></script>
</body>
</html>
수정후
<!doctype html>
<html lang="ko-KR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HeaderHtml</title>
</head>
<body>
<!--헤더-->
<header
id="header"
class="h-20 border-b border-gray-300 bg-white dark:border-gray-700 dark:bg-gray-800 dark:text-white fixed top-0 left-0 right-0 z-50"
>
<div class="flex items-center">
<button
id="menuBtn"
class="cursor-pointer hover:border-white hover:rounded hover:bg-gray-100 dark:hover:bg-gray-700 flex justify-center items-center h-12 w-12 m-5"
aria-label="메뉴버튼"
aria-expanded="false"
aria-controls="menuBar"
>
<!-- 다크 모드일때 -->
<img class="hidden dark:block" width="40" height="40" src="../img/mode/dark/menubar_dark.png" alt="" />
<!-- 라이트 모드일때 -->
<img class="block dark:hidden" width="40" height="40" src="../img/mode/light/menubar_light.png" alt="" />
</button>
<div class="sm:ml-1 text-2xl flex gap-4 justify-center items-center">
<a href="./index.html" class="cursor-pointer">
<img
class="w-6 h-6 sm:w-[32px] sm:h-[32px]"
src="https://img.icons8.com/tiny-color/32/code.png"
alt="메인로고"
/>
</a>
<h1 class="text-2xl">
<span class="hidden sm:block">개인 개발 블로그</span>
<span class="block sm:hidden text-xl">개발 블로그</span>
</h1>
</div>
<div class="relative flex justify-end items-center flex-grow mr-5 gap-2">
<button id="searchBtn" class="cursor-pointer hover:border-white hover:rounded hover:bg-gray-100 dark:hover:bg-gray-700">
<!-- 다크 모드 -->
<img class="ml-auto hidden dark:block" width="40" height="40" src="../img/mode/dark/search_dark.png" alt="검색" />
<!-- 라이트 모드 -->
<img class="ml-auto bolck dark:hidden" width="40" height="40" src="../img/mode/light/search_light.png" alt="검색" />
</button>
<div
id="searchWrap"
class="w-0 overflow-hidden transition-all duration-300 ease-out"
>
<input
id="searchInput"
type="text"
class="w-60 h-10 rounded-full bg-gray-100 dark:bg-gray-700 dark:text-gray-200 pl-4 pr-4 placeholder-gray-500"
placeholder="검색어를 입력해주세요."
aria-label="검색어 입력"
/>
</div>
</div>
<div class="relative ml-auto mr-10 w-8 h-8 hidden sm:flex">
<button id="darkmode_btn" class="w-full h-full hover:cursor-pointer group relative" aria-label="다크 모드" aria-pressed="false">
<!-- 큰 원 -->
<span id="darkmode_toggle_position" class="absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 w-12 h-12 bg-white border border-gray-400 rounded-full shadow-sm z-11 group-hover:bg-gray-100 dark:group-hover:bg-gray-700 dark:border-gray-600 dark:bg-gray-800"></span>
<!-- 작은 원 -->
<span class="absolute left-8 top-2 border rounded-full w-8 h-8 z-10 border-gray-400 bg-white shadow-sm group-hover:bg-gray-100 dark:group-hover:bg-gray-700 dark:border-gray-600 dark:bg-gray-800"></span>
<!-- moon 아이콘 -->
<div class="duration-300 ease-out">
<!-- 다크 모드 -->
<img id="moon_light" width="40" height="40" class="absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 w-8 h-8 z-11 transition-all duration-300 ease-out" src="../img/mode/light/moon_light.png" alt=""/>
<!-- 라이트 모드 -->
<img id="moon_dark" width="30" height="30" class="absolute left-10 top-4 w-4 h-4 z-11 transition-all duration-300 ease-out" src="../img/mode/dark/moon_dark.png" alt=""/>
</div>
<!-- sun 아이콘 -->
<div class="duration-300 ease-out">
<!-- 라이트모드 -->
<img id="sun_dark" width="40" height="40" class="absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 w-8 h-8 z-11 transition-all duration-300 ease-out" src="../img/mode/dark/sun_dark.png" alt=""/>
<!-- 다크모드 -->
<img id="sun_light" width="30" height="30" class="absolute left-10 top-4 w-4 h-4 z-11 transition-all duration-300 ease-out" src="../img/mode/light/sun_light.png" alt=""/>
</div>
</button>
</div>
</div>
<!--메뉴바-->
<div id="menuBar" class="fixed border-r border-gray-300 transform -translate-x-full transition-transform duration-300 ease-out top-20 left-0 bg-gray-100 dark:bg-gray-900 dark:text-white flex w-100 h-full z-11" inert aria-hidden="true">
<aside class="flex flex-col h-full w-full">
<div class="border-b border-gray-700 bg-white dark:bg-gray-800 h-20 flex items-center">
<h2 class="text-2xl ml-5">메뉴</h2>
<button id="menuExitBtn" class="cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-600 hover:rounded ml-auto mr-5" aria-label="메뉴 닫기">
<!-- 다크 모드 -->
<img class="hidden dark:block" width="30" height="30" src="../img/mode/dark/delete_dark.png" alt=""/>
<!-- 라이트 모드 -->
<img class="block dark:hidden" width="30" height="30" src="../img/mode/light/delete_light.png" alt=""/>
</button>
</div>
<div class="flex items-center pt-4 pb-4 text-lg border-b border-gray-700">
<button id="logout" class="flex-1 hover:text-gray-500 hover:cursor-pointer dark:hover:text-gray-500" aria-label="로그아웃">로그아웃</button>
<button id="user" class="flex-1 hover:text-gray-500 hover:cursor-pointer dark:hover:text-gray-500" aria-label="내정보">내정보</button>
<a id="login" class="flex-1 text-center hover:text-gray-500 hover:cursor-pointer dark:hover:text-gray-500" href="./login.html" aria-label="로그인">로그인</a>
<a id="signup" class="flex-1 text-center hover:text-gray-500 hover:cursor-pointer dark:hover:text-gray-500" href="./signup.html" aria-label="회원가입">회원가입</a>
</div>
<nav>
<ul class="flex flex-col gap-12 mt-5 mb-5 text-2xl p-5">
<li><a href="./index.html" class="hover:text-gray-500 dark:hover:text-gray-500" aria-label="Home 이동">Home</a></li>
<li><a href="./about.html" class="hover:text-gray-500 dark:hover:text-gray-500" aria-label="About 이동">About</a></li>
<li><a href="./devLog.html" class="hover:text-gray-500 dark:hover:text-gray-500" aria-label="DevLog 이동">DevLog</a></li>
<li><a href="" class="hover:text-gray-500 dark:hover:text-gray-500" aria-label="연락처 이동">연락처</a></li>
</ul>
</nav>
</aside>
</div>
</header>
<script type="module" src="/src/main.js"></script>
<script src="../components/menuBtn.js"></script>
<script type="module" src="../components/a11y_menuBtn.js"></script>
<script type="module" src="/components/darkmode/darkmode_index.js"></script>
<script src="/components/searchBtn.js"></script>
</body>
</html>
개선사항
- svg로 사용하던 이미지 파일을 사이즈에 딱 맞는 png 아이콘으로 변경
- ARIA 속성 추가 (label, expended, controls, hidden, pressed, inert)
- 적용 위치 - 메뉴, 검색, 다크모드, 네비게이션
- 다크모드 토글 구조 개선 (div 요소 → span 요소, button에 aria-pressed 추가)
- 의미 없는 요소에서 의미가 있는 요소로 변경
- 메뉴 영역 구조 개선(div 요소 → nav 요소로 감쌈, 제목 p 요소 → h2 요소로 변경)
- 문서 내 h1 중복제거
- 검색 버튼과 입력창 구조 개선
- 접근성 전용 JS 추가(Tap을 이용하여 이동시 메뉴창에서 다시 나올때 기존에 있던 위치로 이동되는 로직 및 ARIA 속성 변경)
- alt 텍스트 개선
전반적으로 시멘틱하지 않으면서 동시에 접근성 측면에서 떨어지던 코드를 다시한번 리팩토링 및 구조를 개선하였다.
결론
단순히 UI 리펙토링을 한것이 아닌, 접근성 + 시멘틱 구조(검색엔진 최적화) + 유지보수성 모두를 고려한 구조적 개선을 실행했다.
'Front-End > HTML' 카테고리의 다른 글
| HTML - 트위터 클론 코딩 - 2 (0) | 2025.12.15 |
|---|---|
| HTML - 트위터 클론 코딩 - 1 (1) | 2025.12.13 |
| HTML/CSS - a 태그를 이용하여 자동 스크롤 / 부드러운 스크롤 (0) | 2025.12.12 |
| HTML/CSS - 비디오 메인화면 제작하기 (2) | 2025.12.12 |
| HTML/CSS - <header> (0) | 2025.11.25 |