June 25, 2025
텍스트만 있는 `div`를 버튼으로 사용하기 🚫
HTML
UX
JavaScript
SEO/접근성
Summary
div를 버튼처럼 사용하면 키보드 접근성, 스크린 리더 지원 등 웹 접근성을 심각하게 저해하며 불필요한 개발 공수를 야기합니다. 대신 시맨틱 button 또는 a 요소를 사용하여 내장된 접근성 이점을 활용하고 코드의 견고함을 높여야 합니다.
Why Wrong?
div는 왜 버튼이 될 수 없는가?
div 요소는 아무런 시맨틱(의미)도, 내장된 동작(behavior)도 없는 일반적인 컨테이너 요소입니다. 개발자가 div에 onclick 이벤트 핸들러를 추가하여 시각적으로 버튼처럼 보이게 할 수는 있지만, 이는 여러 심각한 문제를 야기합니다:
- 키보드 접근성 부족:
div는 기본적으로 탭(Tab) 키로 포커스를 받을 수 없습니다. 스크린 리더 사용자나 마우스 사용이 어려운 사용자는 키보드로 해당 요소를 활성화할 수 없습니다. 비록tabindex="0"속성을 추가하여 포커스를 가능하게 하더라도, 엔터(Enter) 키나 스페이스(Space) 키로 클릭 이벤트를 발생시키는 동작은 수동으로onKeyDown이벤트를 통해 구현해야 합니다. 이는 네이티브button요소가 자동으로 제공하는 기능을 번거롭게 재구현하는 것입니다. - 스크린 리더 의미론 부족: 스크린 리더는
div를 단순히 일반 텍스트 블록으로 인식하며, '버튼'이라는 역할을 전달하지 않습니다.role="button"ARIA 속성을 추가하여 의미를 부여할 수 있지만, 이 역시 네이티브button이 제공하는 견고함과 모든 브라우저/스크린 리더 조합에서의 일관성을 보장하기 어렵습니다. 예를 들어, 네이티브button은 '눌려짐' 상태(aria-pressed)나 '비활성화' 상태(disabled)를 자동으로 관리하지만,div기반 버튼은 이 모든 것을 수동으로 구현해야 합니다. - 예상치 못한 UX 문제:
div는button의:active나:focus와 같은 내장된 의사 클래스(pseudo-classes) 동작을 제공하지 않아, 사용자가 요소와 상호작용할 때 시각적인 피드백이 부족할 수 있습니다. 이는 사용자의 혼란을 가중시키고 전반적인 사용자 경험을 저해합니다. - 개발 및 유지보수 비용 증가: 위에서 언급된 모든 접근성 및 기능적 문제를 해결하기 위해
div에tabindex,role, 다양한 키보드 이벤트 핸들러를 수동으로 추가하고 테스트하는 것은 불필요한 개발 시간을 소모하고 코드의 복잡성을 증가시켜 유지보수성을 떨어뜨립니다.
How to Fix?
시맨틱 HTML 요소를 사용하여 웹 접근성 및 견고성 확보
상호작용이 필요한 모든 요소에는 그 목적에 맞는 시맨틱 HTML 요소를 사용해야 합니다. 이는 웹 표준을 준수하고, 브라우저가 제공하는 내장된 접근성 기능을 자동으로 활용하여 모든 사용자가 웹사이트를 동등하게 이용할 수 있도록 합니다.
- 클릭 가능한 동작을 수행하는 경우:
button요소를 사용하세요.button은 키보드 내비게이션(탭, 엔터, 스페이스)과 스크린 리더 의미론을 자동으로 제공합니다. 또한disabled속성을 통해 비활성화 상태를 쉽게 관리할 수 있습니다. - 다른 페이지로 이동하거나 페이지 내 특정 섹션으로 이동하는 경우:
a(앵커) 요소를 사용하세요.a태그는href속성을 통해 링크의 목적지를 명확히 하고, 브라우저의 내비게이션 히스토리와 상호작용하는 기능을 제공합니다.
스타일링 팁: button이나 a 태그의 기본 스타일이 만족스럽지 않다면, CSS를 사용하여 완전히 새로운 디자인을 적용할 수 있습니다. border: none;, background: none;, font: inherit;, text-decoration: none; 등을 사용하여 기본 스타일을 초기화한 후, 원하는 대로 padding, background-color, border-radius 등을 적용하면 됩니다. 중요한 것은 시맨틱 구조를 유지하면서 시각적 표현만 변경하는 것입니다.
Before Code (Bad)
<style>
.my-button {
padding: 10px 20px;
background-color: #007bff;
color: white;
border-radius: 5px;
cursor: pointer;
display: inline-block;
}
</style>
<div class="my-button" onclick="alert('클릭!')">
클릭하세요!
</div>After Code (Good)
<style>
/* 버튼의 기본 스타일을 초기화하고 .my-button 스타일을 적용 */
.my-button {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none; /* button 기본 border 제거 */
border-radius: 5px;
cursor: pointer;
font-family: inherit; /* 폰트 상속 */
font-size: inherit; /* 폰트 사이즈 상속 */
text-align: center;
text-decoration: none; /* a 태그 underline 제거 */
display: inline-block; /* 너비 조절 */
/* 필요에 따라 line-height, text-transform 등 추가 */
}
/* 포커스 시 시각적 표시 제공 (접근성 필수) */
.my-button:focus {
outline: 2px solid #0056b3; /* 기본 outline 대신 명확한 outline */
outline-offset: 2px;
}
/* Hover 및 Active 상태 */
.my-button:hover {
background-color: #0056b3;
}
.my-button:active {
background-color: #003f8e;
}
</style>
<button class="my-button" onclick="alert('클릭!')">
클릭하세요!
</button>
<!-- 또는 링크처럼 동작해야 한다면 -->
<!-- <a href="/dashboard" class="my-button">
대시보드로 이동
</a> -->