WeniVooks

검색

아는 만큼 보이는 웹접근성 WCAG 2.2

가이드라인 3.2 예측 가능성

웹을 사용하다 보면 다양한 상호작용을 경험할 수 있습니다. 버튼을 클릭하여 메뉴를 열고, 제출을 눌러 페이지를 이동하는 등 다양한 기능을 사용할 수 있습니다. 하지만 이런 변화가 예기치 못하게 일어난다면 어떨까요? 버튼을 클릭하지 않았는데 메뉴가 열리고, 제출을 하지 않았는데 페이지가 이동한다면 사용자들은 혼란스러울 수 있습니다. 또한 모든 사용자가 이런 변화에 손쉽게 대응하지는 못합니다.

우리의 웹 페이지는 예측할 수 있어야 합니다. 사용자의 예상과 일치하도록 구조를 만들고, 페이지를 작동하게 해야 합니다. 이는 디자인의 통일성을 넘어서, 일관된 패턴을 사용하여 사용자가 웹 사이트를 쉽게 이해할 수 있도록 하는 모든 접근법을 의미합니다.

1. 성공 기준 3.2.1 포커스

(수준 A)

사용자 인터페이스 요소가 포커스를 받았을 때, 예상치 못한 컨텍스트의 변경이 발생하지 않아야 합니다. 링크에 포커스가 되었을 때 페이지가 이동되거나, 제출 버튼에 포커스 되었을 때 제출이 되는 등의 변경이 발생하지 않아야 합니다.

컨텍스트 변경

웹 페이지에서 사용자의 환경이나 상황이 변경되는 것을 의미합니다. 현재 창, 포커스, 콘텐츠, 사용자 언어 등이 변경되는 주요한 변화를 나타냅니다.

포커스가 되었더라도 기능이 동작하지 않아야 합니다.

특히 이 성공 기준은 포커스를 이동하며 웹을 탐색하는 키보드 사용자나 스크린 리더 사용자에게 중요한 역할을 합니다. 사용자가 의도적인 상호작용(ex. 클릭, Enter 키 누름)을 할 때만 변화가 일어나야 합니다.

<!-- html -->
<div class="dropdown">
  <button id="dropbtn">드롭다운</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#home">홈</a>
    <a href="#about">소개</a>
    <a href="#contact">연락처</a>
  </div>
</div>
 
<script>
  const dropbtn = document.getElementById('dropbtn');
  const dropdown = document.getElementById('myDropdown');
 
  // 포커스 시 드롭다운 메뉴 자동 열기 (문제가 되는 부분)
  dropbtn.addEventListener('focus', function () {
    dropdown.classList.add('show');
  });
 
  dropbtn.addEventListener('blur', function () {
    dropdown.classList.remove('show');
  });
</script>
<!-- html -->
<div class="dropdown">
  <button id="dropbtn">드롭다운</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#home">홈</a>
    <a href="#about">소개</a>
    <a href="#contact">연락처</a>
  </div>
</div>
 
<script>
  const dropbtn = document.getElementById('dropbtn');
  const dropdown = document.getElementById('myDropdown');
 
  // 포커스 시 드롭다운 메뉴 자동 열기 (문제가 되는 부분)
  dropbtn.addEventListener('focus', function () {
    dropdown.classList.add('show');
  });
 
  dropbtn.addEventListener('blur', function () {
    dropdown.classList.remove('show');
  });
</script>
/* css */
.dropdown {
  position: relative;
  display: inline-block;
}
 
#dropbtn {
  background-color: #3075ff;
  color: white;
  padding: 6px 12px;
  border: none;
  cursor: pointer;
  border-radius: 4px;
}
 
.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f9f9f9;
  min-width: 120px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
  border-radius: 4px;
  transform: translateY(10px);
  font-size: 14px;
}
 
.dropdown-content a {
  color: #333;
  padding: 6px 12px;
  text-decoration: none;
  display: block;
}
 
.dropdown-content a:hover {
  background-color: #f1f1f1;
}
 
/* show 클래스가 추가되면 드롭다운 표시 */
.show {
  display: block;
}
/* css */
.dropdown {
  position: relative;
  display: inline-block;
}
 
#dropbtn {
  background-color: #3075ff;
  color: white;
  padding: 6px 12px;
  border: none;
  cursor: pointer;
  border-radius: 4px;
}
 
.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f9f9f9;
  min-width: 120px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
  border-radius: 4px;
  transform: translateY(10px);
  font-size: 14px;
}
 
.dropdown-content a {
  color: #333;
  padding: 6px 12px;
  text-decoration: none;
  display: block;
}
 
.dropdown-content a:hover {
  background-color: #f1f1f1;
}
 
/* show 클래스가 추가되면 드롭다운 표시 */
.show {
  display: block;
}

클릭이 발생하거나, 엔터가 눌리는 사용자의 명시적인 상호작용이 있을 때, 메뉴가 열리도록 코드를 수정해야 합니다. 또한 ARIA 속성과 role을 추가하여 각 요소의 상태와 의미를 명확히 할 수 있습니다.

<div class="dropdown">
  <button id="dropbtn" aria-haspopup="true" aria-expanded="false">
    드롭다운
  </button>
  <div id="myDropdown" class="dropdown-content" role="menu">
    <a href="#home" role="menuitem">홈</a>
    <a href="#about" role="menuitem">소개</a>
    <a href="#contact" role="menuitem">연락처</a>
  </div>
</div>
 
<script>
  const dropbtn = document.getElementById('dropbtn');
  const dropdown = document.getElementById('myDropdown');
 
  function toggleDropdown() {
    const expanded = dropbtn.getAttribute('aria-expanded') === 'true';
    dropbtn.setAttribute('aria-expanded', !expanded);
    dropdown.classList.toggle('show');
  }
 
  dropbtn.addEventListener('click', toggleDropdown);
 
  dropbtn.addEventListener('keydown', function (e) {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      toggleDropdown();
    }
  });
</script>
<div class="dropdown">
  <button id="dropbtn" aria-haspopup="true" aria-expanded="false">
    드롭다운
  </button>
  <div id="myDropdown" class="dropdown-content" role="menu">
    <a href="#home" role="menuitem">홈</a>
    <a href="#about" role="menuitem">소개</a>
    <a href="#contact" role="menuitem">연락처</a>
  </div>
</div>
 
<script>
  const dropbtn = document.getElementById('dropbtn');
  const dropdown = document.getElementById('myDropdown');
 
  function toggleDropdown() {
    const expanded = dropbtn.getAttribute('aria-expanded') === 'true';
    dropbtn.setAttribute('aria-expanded', !expanded);
    dropdown.classList.toggle('show');
  }
 
  dropbtn.addEventListener('click', toggleDropdown);
 
  dropbtn.addEventListener('keydown', function (e) {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      toggleDropdown();
    }
  });
</script>

시맨틱한 마크업은 대부분 접근성을 준수하므로 기능에 맞는 요소를 사용하는 것을 권장합니다.

<nav>
  <select id="navMenu" aria-label="navMenu">
    <option value="">드롭다운 메뉴</option>
    <option value="#home">홈</option>
    <option value="#about">소개</option>
    <option value="#contact">연락처</option>
  </select>
</nav>
<nav>
  <select id="navMenu" aria-label="navMenu">
    <option value="">드롭다운 메뉴</option>
    <option value="#home">홈</option>
    <option value="#about">소개</option>
    <option value="#contact">연락처</option>
  </select>
</nav>

2. 성공 기준 3.2.2 입력

(수준 A)

사용자 인터페이스 요소의 입력값이 변경되었을 때, 예상치 못한 변화가 발생하지 않아야 합니다. 또한 변경이 일어나기 전에는 사용자에게 알려야 합니다. 특히 폼 요소의 입력값이 변경되었을 때, 자동으로 제출되거나 페이지의 새로고침이 발생하지 않도록 해야 합니다. 사용자의 명시적인 상호작용이 있을 경우에만 변경되어야 합니다.

다음은 기준을 준수하지 않는 드롭다운 예시입니다. <select>의 변경이 있을 때, 폼을 제출합니다. 사용자가 옵션을 선택하면 <select>의 변경이 발생하고, 따라서 자동으로 폼이 제출됩니다. 옵션을 잘못 선택했을 때도 폼을 제출하기 때문에 원하지 않은 결과를 야기할 수 있습니다.

<form id="languageForm">
  <select id="languageSelect" onchange="this.form.submit()">
    <option value="">언어를 선택하세요</option>
    <option value="ko">한국어</option>
    <option value="en">English</option>
    <option value="ja">日本語</option>
  </select>
</form>
<form id="languageForm">
  <select id="languageSelect" onchange="this.form.submit()">
    <option value="">언어를 선택하세요</option>
    <option value="ko">한국어</option>
    <option value="en">English</option>
    <option value="ja">日本語</option>
  </select>
</form>

여러 <input>에 대하여 값, 선택 요소 등의 입력과 폼 제출은 별개로 동작해야 합니다. 입력이 일어났을 때 변경이 발생되는 것이 미리 고지되었을 경우, 자동 변경이 허용될 수 있습니다. 하지만 해당 경우에도 사용자에게 명확한 안내가 필요하며, 사용자가 손쉽게 선택을 취소할 수 있는 기능을 제공해야 합니다.

<form id="languageForm">
  <select id="languageSelect">
    <option value="">언어를 선택하세요</option>
    <option value="ko">한국어</option>
    <option value="en">English</option>
    <option value="ja">日本語</option>
  </select>
 
  <!-- 명시적인 제출 요청 -->
  <button onsubmit="this.form.submit()">제출하기</button>
</form>
<form id="languageForm">
  <select id="languageSelect">
    <option value="">언어를 선택하세요</option>
    <option value="ko">한국어</option>
    <option value="en">English</option>
    <option value="ja">日本語</option>
  </select>
 
  <!-- 명시적인 제출 요청 -->
  <button onsubmit="this.form.submit()">제출하기</button>
</form>

3. 성공 기준 3.2.3 일관된 탐색

(수준 AA)

웹 페이지 내에서 탐색은 일관된 순서로 발생해야 합니다. 웹 사이트 내에서 네비게이션 메뉴의 순서와 위치가 일관되게 유지되어야 합니다. 다음과 같은 네비게이션은 사이트 내 각각의 페이지에서(ex. 메인 페이지, 상세 페이지 등) 동일하게 사용되어야 합니다.

<header>
  <nav>
    <ul>
      <li><a href="index.html">홈</a></li>
      <li><a href="about.html">소개</a></li>
      <li><a href="products.html">제품</a></li>
      <li><a href="contact.html">연락처</a></li>
    </ul>
  </nav>
</header>
<header>
  <nav>
    <ul>
      <li><a href="index.html">홈</a></li>
      <li><a href="about.html">소개</a></li>
      <li><a href="products.html">제품</a></li>
      <li><a href="contact.html">연락처</a></li>
    </ul>
  </nav>
</header>

이처럼 일관된 탐색 구조를 유지하면 모든 사용자, 특히 보조 기술을 사용하는 사람들이 웹사이트를 더 쉽게 이해하고 사용할 수 있습니다.

사용자가 탐색의 순서를 변경하는 기능을 제공할 수 있습니다. 사용자의 명시적인 요청에 따라 탐색 순서가 바뀌지 않는다면, 일관된 순서를 유지해야 합니다.

4. 성공 기준 3.2.4 일관된 식별

(수준 AA)

웹 페이지 내에서 동일한 기능을 가진 컴포넌트는 일관되게 식별되어야 합니다. 동일한 기능의 버튼에 동일한 아이콘을 사용하고, 동일한 링크로 이동하는 경우에도 일관성을 유지하여, 사용자가 기능을 쉽게 예측할 수 있습니다.

같은 링크로 이동
동일한 형태의 컴포넌트

디자인 일관성 뿐만 아니라, 페이지 구조(헤더, 메인, 푸터)나 폼 요소의 라벨과 버튼에 작성된 텍스트 등을 동일하게 구성하여 사용자 인터페이스와 보조 기술에서도 일관된 식별이 가능하게 합니다.

5. 성공 기준 3.2.5 요청에 의한 변경

(수준 AAA)

컨텍스트의 변경은 사용자의 요청이 있을 때만 발생해야 합니다. 즉, 사용자가 명시적으로 상호작용하지 않는 한, 페이지의 주요 변경이 발생하지 않아야 합니다. 사용자에게 웹 페이지가 변경되는 것을 미리 알렸거나, 핵심 기능을 위해 필수적인 경우에는 허용됩니다. 자동 변경을 완전히 피하는 것이 불가한 경우에는 변경을 취소할 수 있는 방법을 제공하여 사용자에게 웹 페이지 동작에 대한 제어권을 제공해야 합니다.

다음과 같이 사용자가 명시적으로 ‘언어 변경’을 클릭(하거나 키보드로 입력)해야만 변경이 적용됩니다. 페이지가 새로고침에 대한 설명을 추가하여 스크린 리더 사용자에게 변경 결과를 미리 알려줄 수 있습니다.

<form action="/change-language" method="post">
  <fieldset>
    <legend>웹사이트 언어 선택</legend>
    <div>
      <input type="radio" id="lang-ko" name="language" value="ko" />
      <label for="lang-ko">한국어</label>
    </div>
    <div>
      <input type="radio" id="lang-en" name="language" value="en" />
      <label for="lang-en">English</label>
    </div>
    <div>
      <input type="radio" id="lang-ja" name="language" value="ja" />
      <label for="lang-ja">日本語</label>
    </div>
    <div>
      **<button type="submit">
        언어 변경
        <span class="visually-hidden"
          >선택한 언어로 페이지를 다시 로드합니다</span
        ></button
      >**
    </div>
  </fieldset>
</form>
<form action="/change-language" method="post">
  <fieldset>
    <legend>웹사이트 언어 선택</legend>
    <div>
      <input type="radio" id="lang-ko" name="language" value="ko" />
      <label for="lang-ko">한국어</label>
    </div>
    <div>
      <input type="radio" id="lang-en" name="language" value="en" />
      <label for="lang-en">English</label>
    </div>
    <div>
      <input type="radio" id="lang-ja" name="language" value="ja" />
      <label for="lang-ja">日本語</label>
    </div>
    <div>
      **<button type="submit">
        언어 변경
        <span class="visually-hidden"
          >선택한 언어로 페이지를 다시 로드합니다</span
        ></button
      >**
    </div>
  </fieldset>
</form>

6. 성공 기준 3.2.6 일관된 도움말

(수준 A) [신규]

일관된 도움말은 WCAG 2.2에 새롭게 추가된 성공 기준으로, 도움말 기능이 일관된 순서로 일관된 위치에서 제공되어야 하는 것을 뜻합니다. 도움말 기능은 웹 사이트에서 사용자를 지원하고 안내하는 요소를 나타냅니다. 도움말 기능에는 다음과 같이 사용자에게 도움을 주는 다양한 형태의 지원을 포함합니다.

  1. 문서: FAQ, 사용자 가이드 또는 매뉴얼

    https://www.studyin.co.kr/
  2. 실시간 지원: 챗봇, 전화, 이메일

    https://www.studyin.co.kr/
  3. 컨텍스트 도움말: 툴팁, 인라인 도움말

    https://world.weniv.co.kr
    https://make-re.weniv.co.kr/write/1

이러한 도움말은 웹 사이트의 각 페이지에서 일관된 순서, 일관된 위치에서 제공하여 사용자가 쉽게 접근할 수 있도록 해야 합니다.

<h2><a href="/">Studyin 정보</a></h2>
<ul>
  <li>
    <h3>위니브</h3>
    <ul>
      <li><a href="#">회사 소개</a></li>
      <li><a href="#">제주코딩베이스캠프</a></li>
    </ul>
  </li>
  <li>
    <h3>스터디인</h3>
    <ul>
      <li><a href="#">스터디인 이용 가이드</a></li>
    </ul>
  </li>
  <li>
    <h3>정책</h3>
    <ul>
      <li><a href="#">이용약관</a></li>
      <li><a href="#">개인정보처리방침</a></li>
    </ul>
  </li>
</ul>
<h2><a href="/">Studyin 정보</a></h2>
<ul>
  <li>
    <h3>위니브</h3>
    <ul>
      <li><a href="#">회사 소개</a></li>
      <li><a href="#">제주코딩베이스캠프</a></li>
    </ul>
  </li>
  <li>
    <h3>스터디인</h3>
    <ul>
      <li><a href="#">스터디인 이용 가이드</a></li>
    </ul>
  </li>
  <li>
    <h3>정책</h3>
    <ul>
      <li><a href="#">이용약관</a></li>
      <li><a href="#">개인정보처리방침</a></li>
    </ul>
  </li>
</ul>
4.2 가이드라인 3.1 가독성4.4 가이드라인 3.3 입력 지원