June 25, 2025

텍스트만 있는 `div`를 버튼으로 사용하기 🚫

HTML
UX
JavaScript
SEO/접근성

Summary

div를 버튼처럼 사용하면 키보드 접근성, 스크린 리더 지원 등 웹 접근성을 심각하게 저해하며 불필요한 개발 공수를 야기합니다. 대신 시맨틱 button 또는 a 요소를 사용하여 내장된 접근성 이점을 활용하고 코드의 견고함을 높여야 합니다.

Why Wrong?

div는 왜 버튼이 될 수 없는가?

div 요소는 아무런 시맨틱(의미)도, 내장된 동작(behavior)도 없는 일반적인 컨테이너 요소입니다. 개발자가 divonclick 이벤트 핸들러를 추가하여 시각적으로 버튼처럼 보이게 할 수는 있지만, 이는 여러 심각한 문제를 야기합니다:

  1. 키보드 접근성 부족: div는 기본적으로 탭(Tab) 키로 포커스를 받을 수 없습니다. 스크린 리더 사용자나 마우스 사용이 어려운 사용자는 키보드로 해당 요소를 활성화할 수 없습니다. 비록 tabindex="0" 속성을 추가하여 포커스를 가능하게 하더라도, 엔터(Enter) 키나 스페이스(Space) 키로 클릭 이벤트를 발생시키는 동작은 수동으로 onKeyDown 이벤트를 통해 구현해야 합니다. 이는 네이티브 button 요소가 자동으로 제공하는 기능을 번거롭게 재구현하는 것입니다.
  2. 스크린 리더 의미론 부족: 스크린 리더는 div를 단순히 일반 텍스트 블록으로 인식하며, '버튼'이라는 역할을 전달하지 않습니다. role="button" ARIA 속성을 추가하여 의미를 부여할 수 있지만, 이 역시 네이티브 button이 제공하는 견고함과 모든 브라우저/스크린 리더 조합에서의 일관성을 보장하기 어렵습니다. 예를 들어, 네이티브 button은 '눌려짐' 상태(aria-pressed)나 '비활성화' 상태(disabled)를 자동으로 관리하지만, div 기반 버튼은 이 모든 것을 수동으로 구현해야 합니다.
  3. 예상치 못한 UX 문제: divbutton:active:focus와 같은 내장된 의사 클래스(pseudo-classes) 동작을 제공하지 않아, 사용자가 요소와 상호작용할 때 시각적인 피드백이 부족할 수 있습니다. 이는 사용자의 혼란을 가중시키고 전반적인 사용자 경험을 저해합니다.
  4. 개발 및 유지보수 비용 증가: 위에서 언급된 모든 접근성 및 기능적 문제를 해결하기 위해 divtabindex, 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> -->