WeniVooks

검색

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

가이드라인 3.3 입력 지원

웹 사이트를 이용하다 보면 다양한 형태의 입력 폼을 마주합니다. 검색, 로그인, 회원가입, 설문 조사 등 다양한 형태와 구성의 폼에 정보를 입력하게 됩니다. 입력 지원 가이드라인은 사용자가 값을 입력하여 제출하고 결과를 반영하는 과정에서 마주할 수 있는 오류를 피하고 수정할 수 있도록 돕는 것을 뜻합니다.

1. 성공 기준 3.3.1 오류 식별

(수준 A)

회원가입 form 입력 오류

입력 오류가 자동으로 감지되었을 때, 오류가 발생한 항목은 사용자에게 텍스트로 명확히 식별되어야 합니다. 오류 정보를 텍스트로 제공하여 화면에 표시하고, 보조 기술이 텍스트를 감지하여 사용자가 오류 정보를 인식할 수 있어야 합니다. 이러한 오류는 입력 형식이 올바르지 않은 경우나 필수 입력 필드가 비어있는 경우에 발생합니다.

다음과 같이 사용자의 입력값에 대한 유효성을 확인하고 오류 메시지를 표시합니다.

<form class="form-group">
  <label for="password">비밀번호</label>
  <input
    type="password"
    id="password"
    aria-describedby="password-error"
    aria-required="true"
  />
  <p id="password-error" class="error-message" role="alert" hidden></p>
</form>
<form class="form-group">
  <label for="password">비밀번호</label>
  <input
    type="password"
    id="password"
    aria-describedby="password-error"
    aria-required="true"
  />
  <p id="password-error" class="error-message" role="alert" hidden></p>
</form>
document.getElementById('password').addEventListener('blur', function () {
  const errorDisplay = document.getElementById('password-error');
 
  if (this.value.length < 8) {
    // 기본적인 오류 표시
    this.setAttribute('aria-invalid', 'true');
    errorDisplay.hidden = false;
    errorDisplay.textContent = '비밀번호 오류가 발생했습니다.';
  } else {
    this.setAttribute('aria-invalid', 'false');
    errorDisplay.hidden = true;
    errorDisplay.textContent = '';
  }
});
document.getElementById('password').addEventListener('blur', function () {
  const errorDisplay = document.getElementById('password-error');
 
  if (this.value.length < 8) {
    // 기본적인 오류 표시
    this.setAttribute('aria-invalid', 'true');
    errorDisplay.hidden = false;
    errorDisplay.textContent = '비밀번호 오류가 발생했습니다.';
  } else {
    this.setAttribute('aria-invalid', 'false');
    errorDisplay.hidden = true;
    errorDisplay.textContent = '';
  }
});
.form-group input[aria-invalid='true'] {
  border-color: red;
}
 
.error-message {
  color: red;
  margin-top: 0.5rem;
}
.form-group input[aria-invalid='true'] {
  border-color: red;
}
 
.error-message {
  color: red;
  margin-top: 0.5rem;
}

입력 폼에서 여러개의 오류가 발생하는 경우는 각각의 필드에 오류를 표시하며, 모든 오류를 나열하는 요소를 추가해 사용자가 오류 정보를 인식할 수 있도록 합니다. 또는 가장 중요한 오류부터 순차적으로 수정할 수 있도록 단계별로 오류 정보를 제공할 수 있습니다.

2. 성공 기준 3.3.2 레이블 또는 설명

(수준 A)

입력 항목에 대하여 어떤 입력 항목인지 설명을 제공해야 합니다. 사용자가 각 입력 항목의 목적과 필요한 값의 형태를 명확히 이해할 수 있도록 해야 합니다. <label> 태그를 사용하여 입력 항목의 설명을 작성하고, placeholder 속성을 이용하여 설명을 추가할 수 있습니다.

<label for="username">사용자 이름:</label>
<input type="text" id="username" name="username" />
<label for="username">사용자 이름:</label>
<input type="text" id="username" name="username" />

하지만 placeholder를 단독으로 사용하는 것은 해당 성공 기준을 준수하지 않습니다. 성공 기준을 만족하기 위해서는 <label> 태그를 명시하여 사용해야 합니다.

검색창 input의 돋보기 모양 아이콘

아이콘이나 이미지를 이용하여 입력 레이블을 나타내는 경우에도 스크린 리더 사용자를 위하여 레이블 정보를 제공해야 합니다. 스타일 속성을 제어하여 시각적으로 숨기거나, ARIA의 속성을 이용하여 정보를 제공하기도 합니다. 이처럼 콘텐츠에 접근하는 기기에 관계없이 입력 항목에 대해 쉽게 이해하고 유효한 값을 입력할 수 있습니다.

<!-- 시각적으로는 보이지 않지만, 스크린 리더에서 "검색" 텍스트를 읽음 -->
<label for="search" class="visually-hidden">검색</span>
<input type="search" id="search">
<!-- 시각적으로는 보이지 않지만, 스크린 리더에서 "검색" 텍스트를 읽음 -->
<label for="search" class="visually-hidden">검색</span>
<input type="search" id="search">

3. 성공 기준 3.3.3 오류 제안

(수준 AA)

입력 오류를 자동으로 감지하고, 가능한 경우 오류를 수정할 수 있는 제안을 제공합니다. 이 때, 보안이나 목적을 해치지 않는 범위 내에서 수정 제안사항을 제공해야 합니다.

오류 정보에 대해 제공이 되었을 때 보안 상의 위험이 발생할 수 있습니다. 상세한 오류 메시지의 경우 시스템 구조나 데이터베이스의 정보를 노출할 수 있습니다. 로그인을 할 때, “이 이메일 주소는 존재하지 않습니다.”와 같이 구체적인 오류 메시지는 보안에 문제가 발생할 수 있으므로, “이메일 또는 비밀번호가 유효하지 않습니다.”와 같이 오류에 대한 정보를 제공해야 합니다.

입력 오류 "유효하지 않은 사용자 이메일 또는 비밀번호입니다"
<form class="form-group">
  <label for="password">비밀번호</label>
  <input
    type="password"
    id="password"
    aria-describedby="password-requirements password-error"
    aria-required="true"
  />
 
  <!-- 비밀번호 요구사항 -->
  <div id="password-requirements" class="requirements">
    <ul>
      <li id="length-check">최소 8자 이상</li>
      <li id="uppercase-check">대문자 1자 이상</li>
      <li id="number-check">숫자 1자 이상</li>
    </ul>
  </div>
 
  <!-- 상세 오류 메시지 -->
  <p
    id="password-error"
    class="error-message"
    role="alert"
    aria-live="polite"
    hidden
  ></p>
</form>
<form class="form-group">
  <label for="password">비밀번호</label>
  <input
    type="password"
    id="password"
    aria-describedby="password-requirements password-error"
    aria-required="true"
  />
 
  <!-- 비밀번호 요구사항 -->
  <div id="password-requirements" class="requirements">
    <ul>
      <li id="length-check">최소 8자 이상</li>
      <li id="uppercase-check">대문자 1자 이상</li>
      <li id="number-check">숫자 1자 이상</li>
    </ul>
  </div>
 
  <!-- 상세 오류 메시지 -->
  <p
    id="password-error"
    class="error-message"
    role="alert"
    aria-live="polite"
    hidden
  ></p>
</form>
document.getElementById('password').addEventListener('blur', function () {
  const password = this.value;
  const errorDisplay = document.getElementById('password-error');
  const errors = [];
 
  // 상세한 오류 검사
  if (password.length < 8) {
    errors.push('비밀번호는 최소 8자 이상이어야 합니다.');
  }
  if (!/[A-Z]/.test(password)) {
    errors.push('대문자를 하나 이상 포함해주세요.');
  }
  if (!/[0-9]/.test(password)) {
    errors.push('숫자를 하나 이상 포함해주세요.');
  }
 
  // 오류 표시
  if (errors.length > 0) {
    this.setAttribute('aria-invalid', 'true');
    errorDisplay.hidden = false;
    errorDisplay.textContent = errors.join(' ');
  } else {
    this.setAttribute('aria-invalid', 'false');
    errorDisplay.hidden = true;
    errorDisplay.textContent = '';
  }
});
document.getElementById('password').addEventListener('blur', function () {
  const password = this.value;
  const errorDisplay = document.getElementById('password-error');
  const errors = [];
 
  // 상세한 오류 검사
  if (password.length < 8) {
    errors.push('비밀번호는 최소 8자 이상이어야 합니다.');
  }
  if (!/[A-Z]/.test(password)) {
    errors.push('대문자를 하나 이상 포함해주세요.');
  }
  if (!/[0-9]/.test(password)) {
    errors.push('숫자를 하나 이상 포함해주세요.');
  }
 
  // 오류 표시
  if (errors.length > 0) {
    this.setAttribute('aria-invalid', 'true');
    errorDisplay.hidden = false;
    errorDisplay.textContent = errors.join(' ');
  } else {
    this.setAttribute('aria-invalid', 'false');
    errorDisplay.hidden = true;
    errorDisplay.textContent = '';
  }
});

오류 메시지는 실시간으로 제공하는 것도 가능하지만, 사용자의 입력을 방해하지 않도록 주의해야 합니다. 이 성공 기준의 목적은 사용자가 입력 오류에 대하여 보다 쉽게 수정하고, 필요한 정보를 정확하게 입력할 수 있도록 돕는 것에 있으므로, 보안에 벗어나지 않은 범위에서 정확한 오류 메시지를 제공해야 합니다.

4. 성공 기준 3.3.4 오류 방지 (법률, 금융, 데이터)

(수준 AA)

이 성공 기준은 법률, 금융, 데이터와 관련된 도메인에서 중요하게 준수해야 합니다. 사용자에게 법적 책임이 있거나, 금융 거래가 일어나는 경우, 사용자는 데이터를 수정 또는 삭제하거나, 응답을 제출하는 경우 다음 중 하나 이상을 만족해야 합니다.

toss
  1. 되돌리기: 제출을 취소할 수 있습니다.
  2. 확인: 사용자가 입력한 데이터의 입력 오류를 확인하고 수정할 수 있습니다.
  3. 검토: 제출을 완료하기 전 검토, 확인 및 수정이 가능해야 합니다.

사용자의 입력에 대하여 취소를 할 수 있어야 합니다. 취소 버튼을 제공하여 작업을 중단할 수 있도록 합니다.

<form id="paymentForm">
  <!-- 결제 정보 입력 필드들 -->
  <button type="submit">결제하기</button>
  <button type="button" onclick="cancelPayment()">취소</button>
</form>
 
<script>
  function cancelPayment() {
    if (confirm('결제를 취소하시겠습니까?')) {
      window.location.href = 'cancel-page.html';
    }
  }
</script>
<form id="paymentForm">
  <!-- 결제 정보 입력 필드들 -->
  <button type="submit">결제하기</button>
  <button type="button" onclick="cancelPayment()">취소</button>
</form>
 
<script>
  function cancelPayment() {
    if (confirm('결제를 취소하시겠습니까?')) {
      window.location.href = 'cancel-page.html';
    }
  }
</script>

사용자의 입력한 데이터에 대하여 입력 오류를 확인하고 수정할 기회를 제공합니다. 사용자가 올바른 입력을 했는지 확인하여 특히 민감한 법률, 금융과 관련된 정보를 올바르게 입력하도록 합니다.

<form id="dataForm" onsubmit="return validateForm()">
  <!-- 데이터 입력 필드들 -->
  <button type="submit">제출</button>
</form>
 
<script>
  function validateForm() {
    let errors = [];
    if (errors.length > 0) {
      alert('다음 오류를 수정해주세요:\n' + errors.join('\n'));
      return false;
    }
    return true;
  }
</script>
<form id="dataForm" onsubmit="return validateForm()">
  <!-- 데이터 입력 필드들 -->
  <button type="submit">제출</button>
</form>
 
<script>
  function validateForm() {
    let errors = [];
    if (errors.length > 0) {
      alert('다음 오류를 수정해주세요:\n' + errors.join('\n'));
      return false;
    }
    return true;
  }
</script>

제출을 완료하기 전에 정보를 검토하고 확인 및 수정할 수 있는 방법을 제공해야 합니다.

<form id="legalForm">
  <!-- 법적 문서 동의 체크박스들 -->
  <button type="button" onclick="reviewSubmission()">검토 및 제출</button>
</form>
 
<div id="reviewModal" style="display: none;">
  <h2>제출 내용 확인</h2>
  <div id="reviewContent"></div>
  <button onclick="confirmSubmission()">확인 및 제출</button>
  <button onclick="editSubmission()">수정하기</button>
</div>
 
<script>
  function reviewSubmission() {
    // 폼 데이터 수집 및 표시
    document.getElementById('reviewContent').innerHTML = '수집된 데이터 표시';
    document.getElementById('reviewModal').style.display = 'block';
  }
 
  function confirmSubmission() {
    document.getElementById('legalForm').submit();
  }
 
  function editSubmission() {
    document.getElementById('reviewModal').style.display = 'none';
  }
</script>
<form id="legalForm">
  <!-- 법적 문서 동의 체크박스들 -->
  <button type="button" onclick="reviewSubmission()">검토 및 제출</button>
</form>
 
<div id="reviewModal" style="display: none;">
  <h2>제출 내용 확인</h2>
  <div id="reviewContent"></div>
  <button onclick="confirmSubmission()">확인 및 제출</button>
  <button onclick="editSubmission()">수정하기</button>
</div>
 
<script>
  function reviewSubmission() {
    // 폼 데이터 수집 및 표시
    document.getElementById('reviewContent').innerHTML = '수집된 데이터 표시';
    document.getElementById('reviewModal').style.display = 'block';
  }
 
  function confirmSubmission() {
    document.getElementById('legalForm').submit();
  }
 
  function editSubmission() {
    document.getElementById('reviewModal').style.display = 'none';
  }
</script>

특히 법적, 금융적 영향이 있는 중요한 결정에 있어서 입력 오류를 방지하여 부정적인 결과를 최소화할 수 있습니다. 하지만 사용자에게 불편함을 주지 않도록 주의해야 합니다. 모든 작업에 대하여 과도한 확인 단계가 요구되거나, 오류가 발생했을 때 입력이 초기화된다면 사용자 경험이 떨어질 수 있습니다. 각 작업의 중요도와 영향을 고려하여 적절한 방법을 선택해야 합니다.

5. 성공 기준 3.3.5 도움말

(수준 AAA)

사용자가 웹 콘텐츠를 이해하고 작업을 완료하는데 필요한 추가 정보를 제공합니다. 특히 복잡한 작업이나 익숙하지 않은 인터페이스에 대한 정보를 제공할 수 있습니다.

도움말 정보는 다양한 형태로 제공될 수 있습니다. 입력 필드에 대한 설명을 인라인으로 제공하거나, 툴팁을 이용하여 입력 값에 대한 정보를 제공할 수 있습니다.

오늘의집

더욱 복잡한 기능에 대하여 챗봇이나, 가이드 문서 또는 영상 튜토리얼을 제공하여 사용자가 작업을 쉽게 진행하도록 도움말 정보를 제공할 수 있습니다.

웹 페이지 사용 가이드

6. 성공 기준 3.3.6 오류 방지 (모두)

(수준 AAA)

이 성공 기준은 3.3.4 오류 방지(법률, 금융, 데이터)를 확장한 기준으로 모든 유형의 사용자 제출에 대하여 오류 방지 기준을 적용합니다. 사용자가 정보를 제출해야 하는 웹 페이지의 경우 다음 중 하나 이상을 만족해야 합니다.

  1. 되돌리기: 제출을 취소할 수 있습니다.
  2. 확인: 사용자가 입력한 데이터의 입력 오류를 확인하고 수정할 수 있습니다.
  3. 검토: 제출을 완료하기 전 검토, 확인 및 수정이 가능해야 합니다.

기존에는 법률, 금융, 데이터에 한정되어 있던 3.3.4 오류 방지(법률, 금융, 데이터) 기준을 모든 종류의 데이터 제출에 적용함으로써 더 안전하고 신뢰할 수 있는 데이터를 처리할 수 있도록 합니다.

7. 성공 기준 3.3.7 중복 입력

(수준 A) [신규]

웹 사이트를 이용하다보면 이전에 입력한 정보와 동일한 정보를 다시 입력해야 하는 경우를 마주합니다. 이 때, 사용자가 이전에 입력한 정보를 다시 입력하지 않도록 기능을 제공해야 합니다.

이전에 입력한 배송지 선택 기능

정보가 자동으로 완성되거나, 사용자가 이전에 입력한 정보를 선택하여 사용할 수 있습니다.

이전에 입력한 이메일 선택 기능
<form>
  <label for="name">
    이름
    <input type="text" name="name" id="name" autocomplete="name" />
  </label>
  <label for="email">
    이메일
    <input type="email" name="email" id="email" autocomplete="email" />
  </label>
</form>
<form>
  <label for="name">
    이름
    <input type="text" name="name" id="name" autocomplete="name" />
  </label>
  <label for="email">
    이메일
    <input type="email" name="email" id="email" autocomplete="email" />
  </label>
</form>

단, 보안 상의 이유로 정보가 필요하거나, 정보를 다시 입력하는 것이 필수적인 경우는 예외로 합니다. 입력이 유효하지 않는 경우에도 사용자가 다시 입력하도록 해야 합니다.

데이터 입력에 대하여 사용자의 불편함과 피로를 줄이고, 데이터 입력 오류를 감소할 수 있습니다. 특히 데이터 입력에 어려움을 겪는 사용자들에게 효율적이고 편리한 경험을 제공할 수 있습니다.

8. 성공 기준 3.3.8 접근 가능한 인증 (최소)

(수준 AA) [신규]

비밀번호를 기억하는 것은 인지 장애가 있는 사람들에게 어려운 요소일 수 있습니다. 비밀번호나 패턴 사용 등 인지 기억 테스트를 사용하는 경우, 대체 방법을 함께 제공해야 합니다. 다음을 포함하는 다양한 형태로 인증을 대체할 수 있습니다.

  1. 텍스트 기반 비밀번호: 비밀번호 힌트를 제공하는 옵션을 추가합니다.

  2. 이메일/SMS 인증: 일회용 코드를 전송하여 인증

    이메일로 인증 코드 전송 | 벨로그
  3. 생체 인식: 지문 인식, 안면 인식, 음성 인식

  4. 하드웨어 기반: USB 보안 키, NFC 태그

  5. 소셜 미디어 계정 연동: 기존 계정을 활용한 로그인

  6. QR 코드 스캔: 모바일 기기로 웹사이트에 표시된 QR을 스캔

    유튜브 - QR 코드 스캔 로그인

웹 뿐만 아니라 모바일, 스마트 TV 등 다양한 기기에서 웹 서비스를 이용하게 되면서 인증 방식이 다양해져 모든 사용자들이 다양한 인증을 경험할 수 있습니다.

9. 성공 기준 3.3.9 접근 가능한 인증 (향상)

(수준 AAA) [신규]

토스 Face ID 로그인

3.3.8 접근 가능한 인증(최소) 기준을 더욱 강화하여 인증 과정의 접근성을 최대한 개선하는 것을 목표로 합니다. 비밀 번호 입력과 같은 인지 기능 테스트를 완전 배제하는 것을 목적으로 합니다. 법적 요구사항이나 보안 상의 이유도 예외로 인정되지 않은 더 높은 수준의 접근성 요구사항을 나타냅니다.

3.3.8에서 제안된 대체 방식을 사용하여 인증을 대체할 수 있습니다. 개인화된 경험을 제공하고, 간편한 인증이 가능하며, 사용자의 기억력이나 문제 해결 능력에 의존하지 않기 때문에 모든 사용자가 디지털 서비스를 동등하게 이용할 수 있게 되었습니다.

4.3 가이드라인 3.2 예측 가능성5장 견고한 콘텐츠 개발