WCAG 성공 기준 · Level AAA

WCAG 2.5.6: 동시 입력 메커니즘

WCAG 2.5.6은 플랫폼에서 여러 입력 메커니즘을 사용할 수 있을 때 웹 콘텐츠가 사용자를 단일 입력 방식으로 제한하지 않도록 요구하며, 사람들이 터치, 키보드, 마우스, 음성 및 기타 입력 방법 사이를 자유롭게 전환하더라도 기능에 대한 접근을 잃지 않도록 보장합니다.

  • Level AAA

이 규칙의 의미

\n

WCAG 2.5.6 — Concurrent Input Mechanisms는 WCAG 2.2의 AAA 레벨 성공 기준입니다. 핵심 요구 사항은 간단합니다. 웹 콘텐츠는 사용자가 여러 입력 메커니즘을 동시에 또는 번갈아 사용할 수 있는 능력을 제한하거나 방해해서는 안 됩니다. 실질적으로 이는 웹 페이지나 애플리케이션이 사용자가 현재 어떤 입력 장치를 사용하고 있는지 프로그래밍 방식으로 감지한 뒤, 그 단일 방식에만 사용자를 묶어 두고 다른 사용 가능한 입력 방법에 대한 접근을 차단해서는 안 된다는 뜻입니다.

\n

현대의 기기들은 물리적 키보드, 마우스와 트랙패드, 터치스크린, 스타일러스, 스위치 제어, 음성 입력, 시선 추적 등 다양한 입력 메커니즘을 지원합니다. 많은 사용자는 이들 중 둘 이상을 동시에 사용합니다. 예를 들어, 터치스크린이 있는 노트북 사용자는 터치패드와 손가락 터치 인터페이스를 자연스럽게 오가며 사용할 수 있습니다. 숙련된 사용자는 폼을 키보드로 탐색하면서 마우스로 스크롤할 수 있습니다. 운동 장애가 있는 사람은 머리 포인터와 스위치 장치를 조합해 사용할 수 있습니다. 이 기준은 이러한 모든 작업 흐름을 보호합니다.

\n

실패는 웹사이트가 JavaScript를 사용해 사용 중인 입력 유형을 감지한 다음, 다른 입력 유형에 대한 기능을 제거하거나 비활성화할 때 발생합니다. 예를 들어, 사이트가 터치 이벤트를 감지한 후 키보드 포커스 표시를 제거하거나 키보드 내비게이션을 비활성화한다면 이는 직접적인 위반입니다. 마찬가지로 키보드 사용을 감지한 뒤 포인터 입력을 차단하거나, 플랫폼 API를 사용해 인위적으로 입력을 단일 방식으로 제한하는 것 역시 모두 실패에 해당합니다.

\n

통과는 사용자가 상호작용하는 동안 언제든지 사용 가능한 모든 입력 메커니즘을 사용할 수 있을 때 발생합니다. 콘텐츠는 사용자가 어느 시점에 어떤 입력 메커니즘을 선택하든, 페이지 새로고침이나 모드 전환, 입력 유형을 다시 활성화하기 위한 추가 사용자 조작 없이 올바르게 반응해야 합니다.

\n

이 기준에는 WCAG에서 정의한 공식적인 예외가 하나 있습니다. 본질적일 때는 제한이 허용됩니다. 즉, 특정 입력 방식이 기능상 필수적인 경우입니다. 고전적인 예로는 필기 인식 애플리케이션이 있습니다. 여기서는 터치나 스타일러스 입력이 기능의 핵심입니다. 또 다른 예로는 특정 포인터 입력이 필요한 디지털 서명 캡처 필드를 들 수 있습니다. 이 경우에도 예외는 좁게 해석해야 하며, 작성자는 가능한 한 작업을 완료할 수 있는 대체 수단을 제공해야 합니다.

\n

이 기준이 저자에게 기기가 갖고 있지 않은 입력 메커니즘에 대한 지원을 추가하라고 요구하는 것은 아니라는 점이 중요합니다. 이 기준은 기기와 플랫폼이 이미 지원하는 메커니즘에 대해 가해지는 제한을 규율합니다. 기기에 터치스크린이 없다면 제한할 것이 없습니다.

\n\n

왜 중요한가

\n

동시 또는 교차 사용 가능한 입력 메커니즘을 사용할 자유는 단순한 편의 기능이 아니라, 여러 서로 다른 사용자 집단에 직접적인 영향을 미치는 중요한 접근성 요구 사항입니다.

\n

운동 장애가 있는 사용자는 여러 입력 메커니즘을 결합한 보조 기술에 자주 의존합니다. 손 움직임이 제한적인 사람은 화면 키보드와 함께 sip-and-puff 스위치 장치를 사용할 수 있습니다. 떨림이 있는 사람은 처음에는 키보드로 페이지를 탐색하다가 키보드 단축키가 실패하면 마우스나 터치 인터페이스로 전환할 수 있습니다. 웹사이트가 한 가지 입력 유형을 감지하고 다른 입력을 비활성화하면, 이 사용자는 콘텐츠나 기능에 완전히 접근하지 못할 수 있습니다.

\n

인지 또는 학습 장애가 있는 사용자는 작업에 가장 편안하거나 자연스럽게 느껴지는 입력 방법을 선택할 수 있을 때 큰 도움을 받습니다. 단일 방식만 강요하면 이러한 선택권이 사라지고, 특히 사용자가 기기의 기본 입력 방법에 능숙하지 않을 때 불필요한 인지적 부담을 초래할 수 있습니다.

\n

고령자는 연령 관련 운동상의 어려움을 겪을 수 있으며, 터치와 키보드 입력을 모두 지원하는 기기를 점점 더 많이 사용하고 있습니다. 미세 운동 능력이 하루 동안 변동하는 상황에서 이 메커니즘들 사이를 전환할 수 있는 능력은 웹을 지속적으로 독립적으로 사용하는 데 중요합니다.

\n

파워 유저와 다중 모달 기기 사용자 — 예를 들어 Surface Pro나 iPad Pro 사용자 — 는 동일한 기기에서 같은 세션 동안 키보드, 스타일러스, 터치 인터페이스를 정기적으로 함께 사용합니다. 터치 입력을 감지한 뒤 키보드 단축키를 제거하거나 그 반대로 동작하는 웹사이트는, 스스로를 장애가 있다고 생각하지 않을 수 있는 방대한 사용자층의 경험을 저하시킵니다.

\n

다음과 같은 실제 시나리오를 생각해 보십시오. 한 터키 은행의 온라인 포털이 고객이 터치스크린 태블릿을 사용하고 있음을 감지하고, 키보드 내비게이션을 비활성화하는 “모바일 모드”로 전환합니다. Bluetooth 키보드와 함께 태블릿을 사용하는 운동 장애가 있는 고객은 이제 탭 키로 폼 필드를 이동하거나, 화살표 키로 메뉴를 탐색하거나, 키보드 단축키를 사용할 수 없습니다. 이들은 은행 업무를 독립적으로 완료할 수 없습니다. 이는 접근성 실패일 뿐만 아니라 터키 접근성 규정에 따른 잠재적인 법적 위험이기도 합니다.

\n

사용성과 SEO 관점에서, 동시 입력 메커니즘을 존중하는 것은 더 나은 Core Web Vitals 점수, 낮은 이탈률, 다양한 기기 범주에 걸친 높은 사용자 만족도와 상관관계를 가지며, 이는 모두 검색 엔진이 보상하는 신호입니다.

\n\n

관련 Axe-core 규칙

\n

WCAG 2.5.6은 수동 테스트를 요구합니다. 이 기준의 모든 위반을 신뢰성 있게 감지할 수 있는 자동화된 axe-core 규칙은 없습니다. 그 이유는 근본적입니다. 자동화 도구는 정적 DOM과 CSS를 검사할 수 있고 특정 JavaScript 패턴을 감지할 수는 있지만, 실제 사용자 세션 동안 서로 다른 입력 방식에 반응하는 이벤트 리스너의 런타임 동작을 완전히 관찰할 수는 없습니다. 입력 메커니즘을 제한하는 결정은 종종 특정 이벤트에 응답해 실행되는 애플리케이션 로직에 인코딩되어 있어, 정적 분석만으로는 충분하지 않습니다.

\n
    \n
  • 2.5.6에 대한 전용 자동 axe-core 규칙은 존재하지 않습니다. Axe-core는 동시 입력 메커니즘 제한을 구체적으로 검사하는 규칙을 제공하지 않습니다. 위반이 구조적인 HTML이나 ARIA 문제가 아니라 동적인 JavaScript 동작으로 나타나기 때문입니다. 페이지는 모든 자동 axe 검사를 통과하더라도, 이벤트 핸들러가 런타임에 입력 방식을 프로그래밍 방식으로 제거하거나 비활성화한다면 여전히 2.5.6을 위반할 수 있습니다.
  • \n
  • 포인터 이벤트와 터치 이벤트 감지: Axe-core는 제한 자체를 포착할 수 없지만, 수동 감사자는 touchstartpointerdown 이벤트를 수신한 뒤 DOM을 수정하거나, 포커스 관리를 제거하거나, 키보드 동작을 변경하는 플래그를 설정하는 JavaScript를 찾아야 합니다. 마찬가지로, CSS 클래스 변경을 트리거해 터치 타깃을 숨기는 keydown 리스너도 수동으로 점검해야 할 경고 신호입니다.
  • \n
  • 자동화가 부족한 이유: 자동 스캐너는 특정 시점의 문서를 분석합니다. 입력 메커니즘 제한은 조건부이며, 특정 입력 이벤트가 발생한 후에만 활성화됩니다. 사용자 상호작용 이전에 실행되는 스캐너는 touchstart 핸들러가 나중에 document.querySelectorAll('[tabindex]').forEach(el => el.setAttribute('tabindex', '-1'))를 호출해 사실상 키보드 내비게이션을 파괴한다는 점을 볼 수 없습니다. 두 입력 방식을 순차적으로 모두 사용해 보는 사람 테스트만이 이러한 실패를 발견할 수 있습니다.
  • \n
\n\n

테스트 방법

\n
    \n
  1. 자동화된 기본 스캔: 페이지에서 axe DevTools 또는 Lighthouse를 실행해 기본 상태를 파악하고 함께 발생하는 문제를 찾아냅니다. 두 도구 모두 전용 2.5.6 규칙은 없지만, axe DevTools의 모범 사례 검사에서 입력 제한의 징후인 키보드 트랩이나 포커스 관리 문제를 표시할 수 있습니다. 아래의 수동 검사와 함께 수정해야 할 실패 항목을 기록합니다.
  2. \n
  3. JavaScript 소스와 이벤트 리스너 검사: Chrome DevTools를 열고 Elements 패널로 이동한 뒤 Event Listeners 창을 사용해 touchstart, pointerdown, pointermove, MSPointerDown 리스너가 document나 body에 연결되어 있는지 확인합니다. Console에서 페이지의 JavaScript 소스를 검색해 ontouchstart in window, navigator.maxTouchPoints, 'pointer' in navigator와 같은 패턴이 DOM 수정과 결합되어 있는지 찾습니다. 이는 입력 방식을 감지하고 기능을 제한하는 데 자주 사용되는 기법입니다.
  4. \n
  5. 다중 모달 상호작용 테스트(키보드 + 터치): 터치와 키보드 입력을 모두 지원하는 기기(예: Surface, 키보드가 있는 iPad, 터치스크린 노트북)에서 Tab, Shift+Tab, Enter, Space, 화살표 키를 사용해 페이지를 오직 키보드로만 탐색하기 시작합니다. 도달 가능하고 동작하는 인터랙티브 요소를 기록합니다. 그런 다음 페이지를 새로고침하지 않고 터치 내비게이션으로 전환해 링크, 버튼, 폼 컨트롤을 탭합니다. 키보드로 사용 가능한 모든 기능이 터치로도 접근 가능하며, 그 반대도 마찬가지인지 확인합니다. 전환 후 도달할 수 없거나 동작하지 않게 되는 요소가 있다면 기록합니다.
  6. \n
  7. 스크린 리더 결합 입력 테스트: NVDA와 Firefox를 사용해 키보드로 페이지를 탐색해 스크린 리더 모드를 활성화합니다. 그런 다음(가능하다면) 동일한 요소와 상호작용을 시도하기 위해 터치스크린을 사용합니다. 스크린 리더와 페이지가 두 입력 모두에 올바르게 반응하는지 확인합니다. iPad의 Safari에서 VoiceOver를 사용해 터치 제스처와 페어링된 Bluetooth 키보드를 모두 사용해 이 과정을 반복합니다. Chrome에서 JAWS를 사용할 때는 키보드와 마우스 사이를 전환해도 포커스 관리가 깨지거나 인터랙티브 요소가 작동하지 않게 되지 않는지 확인합니다.
  8. \n
  9. 입력 방식 잠금 패턴에 대한 코드 리뷰: 페이지에서 사용 중인 JavaScript 라이브러리나 프레임워크에 내장된 입력 방식 감지 기능이 있는지 수동으로 검토합니다. 특히 오래된 모바일 우선 UI 프레임워크 중 일부는 터치가 감지된 기기에서 마우스나 키보드 이벤트를 비활성화하는 코드를 포함하고 있습니다. 라이브러리 문서와 소스를 확인해 이러한 동작이 있는지 살펴보고, 이를 재정의하거나 비활성화했는지 확인합니다.
  10. \n
  11. 동적 상호작용 후 재테스트: 모달 열기, 단일 페이지 앱 라우트 이동, 폼 제출 등 DOM에 큰 변화를 일으키는 작업을 수행한 뒤, 각 전환 후에 다중 모달 테스트를 다시 실행합니다. 제한은 특정 애플리케이션 상태에서만 도입되는 경우가 있습니다.
  12. \n
\n\n

수정 방법

\n

터치를 감지해 키보드 내비게이션을 비활성화 — 잘못된 예

\n
<!-- JavaScript가 터치를 감지하고 모든 tabindex 값을 제거하여,\n     입력 방식을 전환하는 사용자의 키보드 내비게이션을 깨뜨림 -->\n<script>\n  window.addEventListener('touchstart', function() {\n    document.querySelectorAll('a, button, input, [tabindex]').forEach(function(el) {\n      el.setAttribute('tabindex', '-1');\n    });\n  }, { once: true });\n</script>
\n

터치를 감지해 키보드 내비게이션을 비활성화 — 올바른 예

\n
<!-- 터치 감지를 기반으로 키보드 접근성을 제한하지 마십시오.\n     두 입력 방식을 동시에 사용할 수 있도록 허용하십시오.\n     미관을 위해 포커스 스타일을 관리해야 한다면 tabindex를 제거하는 대신\n     :focus-visible CSS 의사 클래스를 사용하십시오. -->\n<style>\n  /* 키보드 내비게이션에 대해서만 포커스 링을 표시하고,\n     마우스 클릭에 대해서는 표시하지 않되, 키보드 접근 자체는 유지 */\n  :focus:not(:focus-visible) {\n    outline: none;\n  }\n  :focus-visible {\n    outline: 3px solid #005fcc;\n    outline-offset: 2px;\n  }\n</style>\n<!-- JavaScript 입력 방식 감지는 필요 없음 -->
\n\n

포인터 이벤트를 사용해 키보드 이벤트를 억제 — 잘못된 예

\n
<!-- 포인터 입력을 받은 후 키보드 화살표 키에 대한 반응을 중단해,\n     사용자를 포인터 전용 상호작용에 가두는 커스텀 슬라이더 -->\n<div id='slider' role='slider' aria-valuenow='50' aria-valuemin='0'\n     aria-valuemax='100' tabindex='0'></div>\n<script>\n  var slider = document.getElementById('slider');\n  var pointerUsed = false;\n  slider.addEventListener('pointerdown', function() {\n    pointerUsed = true;\n  });\n  slider.addEventListener('keydown', function(e) {\n    if (pointerUsed) return; // 포인터 상호작용 이후 키보드 비활성화\n    if (e.key === 'ArrowRight') { /* increment */ }\n    if (e.key === 'ArrowLeft') { /* decrement */ }\n  });\n</script>
\n

포인터 이벤트를 사용해 키보드 이벤트를 억제 — 올바른 예

\n
<!-- 포인터와 키보드 상호작용을 각각 독립적으로 처리합니다.\n     한 입력 방식 사용 후 다른 방식을 막는 플래그를 설정하지 않습니다. -->\n<div id='slider' role='slider' aria-valuenow='50' aria-valuemin='0'\n     aria-valuemax='100' tabindex='0'></div>\n<script>\n  var slider = document.getElementById('slider');\n  var value = 50;\n\n  function updateSlider(newValue) {\n    value = Math.max(0, Math.min(100, newValue));\n    slider.setAttribute('aria-valuenow', value);\n  }\n\n  // 포인터 핸들러 — 항상 활성화\n  slider.addEventListener('pointermove', function(e) {\n    if (e.buttons === 1) {\n      // 포인터 위치로부터 새 값을 계산\n    }\n  });\n\n  // 키보드 핸들러 — 항상 활성화, 포인터 사용으로 비활성화되지 않음\n  slider.addEventListener('keydown', function(e) {\n    if (e.key === 'ArrowRight') updateSlider(value + 1);\n    if (e.key === 'ArrowLeft') updateSlider(value - 1);\n  });\n</script>
\n\n

모바일 프레임워크가 자동으로 마우스 이벤트를 비활성화 — 잘못된 예

\n\n

(토큰 한도 때문에 콘텐츠가 잘렸습니다 — 이 글을 다시 시도해 주세요.)