Svelte는 접근성 위반을 컴파일 타임에 경고합니다 — 다른 프레임워크에서는 별도 린터가 필요한 기능입니다.

개념 정의

웹 접근성(a11y, Accessibility) 은 장애가 있는 사용자도 웹 콘텐츠를 동등하게 이용할 수 있도록 하는 것입니다. Svelte 컴파일러는 접근성 위반을 자동으로 감지하여 경고합니다.

Svelte의 내장 a11y 검사

SVELTE
<!-- 경고: img 요소에 alt 속성이 없음 -->
<img src="/photo.jpg" />

<!-- 올바른 사용 -->
<img src="/photo.jpg" alt="프로필 사진" />
<img src="/decoration.png" alt="" />  <!-- 장식용 이미지는 빈 alt -->

<!-- 경고: 클릭 이벤트가 있는 비대화형 요소에 키보드 이벤트 없음 -->
<div onclick={handleClick}>클릭하세요</div>

<!-- 올바른 사용 — button 사용 또는 role 추가 -->
<button onclick={handleClick}>클릭하세요</button>
<div role="button" tabindex="0" onclick={handleClick} onkeydown={handleKey}>클릭하세요</div>

주요 a11y 경고 목록

  • a11y-missing-attribute: alt, aria-label 등 필수 속성 누락
  • a11y-click-events-have-key-events: 클릭 이벤트에 키보드 이벤트 필요
  • a11y-no-static-element-interactions: 정적 요소에 이벤트 핸들러
  • a11y-label-has-associated-control: label이 폼 컨트롤과 연결 안 됨
  • a11y-autofocus: autofocus 속성 사용 경고

시맨틱 HTML

SVELTE
<!-- 나쁜 예 — div로 모든 것을 만듦 -->
<div class="header">...</div>
<div class="nav">...</div>
<div class="main">...</div>
<div class="footer">...</div>

<!-- 좋은 예 — 시맨틱 태그 사용 -->
<header>...</header>
<nav aria-label="주 내비게이션">...</nav>
<main>...</main>
<footer>...</footer>

ARIA 속성 활용

SVELTE
<script>
  let isOpen = $state(false);
  let isLoading = $state(false);
</script>

<!-- 드롭다운 메뉴 -->
<button
  aria-expanded={isOpen}
  aria-haspopup="true"
  aria-controls="dropdown-menu"
  onclick={() => isOpen = !isOpen}
>
  메뉴
</button>

{#if isOpen}
  <ul id="dropdown-menu" role="menu">
    <li role="menuitem"><a href="/settings">설정</a></li>
    <li role="menuitem"><a href="/profile">프로필</a></li>
  </ul>
{/if}

<!-- 로딩 상태 -->
<div aria-busy={isLoading} aria-live="polite">
  {#if isLoading}
    <p>데이터를 불러오는 중...</p>
  {:else}
    <p>데이터 로드 완료</p>
  {/if}
</div>

포커스 관리

SVELTE
<script>
  import { tick } from 'svelte';

  let showModal = $state(false);
  let modalRef = $state(null);
  let triggerRef = $state(null);

  async function openModal() {
    showModal = true;
    await tick();
    modalRef?.focus();
  }

  function closeModal() {
    showModal = false;
    triggerRef?.focus(); // 트리거 요소로 포커스 복귀
  }

  function trapFocus(e) {
    if (e.key === 'Escape') closeModal();
    if (e.key !== 'Tab') return;

    const focusable = modalRef?.querySelectorAll(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );
    const first = focusable?.[0];
    const last = focusable?.[focusable.length - 1];

    if (e.shiftKey && document.activeElement === first) {
      e.preventDefault();
      last?.focus();
    } else if (!e.shiftKey && document.activeElement === last) {
      e.preventDefault();
      first?.focus();
    }
  }
</script>

<button bind:this={triggerRef} onclick={openModal}>모달 열기</button>

{#if showModal}
  <div class="backdrop" onclick={closeModal}>
    <div
      bind:this={modalRef}
      class="modal"
      role="dialog"
      aria-modal="true"
      aria-labelledby="modal-title"
      tabindex="-1"
      onclick={(e) => e.stopPropagation()}
      onkeydown={trapFocus}
    >
      <h2 id="modal-title">모달 제목</h2>
      <p>모달 내용</p>
      <button onclick={closeModal}>닫기</button>
    </div>
  </div>
{/if}

면접 포인트

  • "Svelte의 a11y 경고가 다른 프레임워크와 다른 점은?": React나 Vue는 별도 ESLint 플러그인(jsx-a11y 등)이 필요하지만, Svelte는 컴파일러에 a11y 검사가 내장되어 있어 추가 설정 없이 자동으로 경고합니다.
  • "접근성이 비즈니스적으로 중요한 이유는?": 법적 요구사항(장애인차별금지법), SEO 향상(검색 엔진도 시맨틱 HTML 선호), 사용자 확대(전체 인구의 15-20%가 접근성 관련 어려움을 겪음)의 세 가지입니다.

정리

Svelte의 접근성 지원은 "컴파일러가 챙겨주는 기본"과 "개발자가 신경 써야 하는 심화"로 나뉩니다. alt 속성, 키보드 이벤트 같은 기본은 컴파일러가 잡아주고, 포커스 관리, ARIA 속성 같은 심화는 개발자의 몫입니다.

댓글 로딩 중...