내용으로 건너뛰기 문서 내비게이션으로 건너뛰기
Check
새로운 버전의 Bootstrap을 사용할 수 있습니다!
// Accessibility

접근성 콘텐츠 제작을 위한 Bootstrap의 기능과 제한사항에 대한 간략한 설명입니다.

Bootstrap은 개발자가 시각적으로 매력적이고 기능이 풍부하며 즉시 액세스할 수 있는 웹사이트와 애플리케이션을 만들 수 있도록 사전 제작된 스타일과 레이아웃 도구 및 대화형 구성요소로 이루어진 사용하기 쉬운 프레임워크를 제공합니다.

개요와 한계

Bootstrap으로 개발한 프로젝트의 전반적인 접근성은 작성자가 추가한 마크업, 추가 스타일 및 스크립트에 큰 영향을 받습니다. 이 부분이 올바르게 구현되었다면 WCAG 2.1 (A/AA/AAA), Section 508 및 유사한 접근성 표준 및 요구사항을 충족하는 Bootstrap을 사용하여 웹사이트와 애플리케이션을 만드는 것이 완벽하게 가능해야 합니다.

구조적 마크업

Bootstrap의 스타일과 레이아웃은 다양한 마크업 구조에 적용할 수 있습니다. 이 문서는 개발자에게 잠재적인 접근성 문제를 해결할 수 있는 방법을 포함하여 Bootstrap의 사용방법을 보여주고 적합한 시멘틱 마크업을 설명하는 모범 사례를 제공하는 것에 중점을 두고 있습니다.

상호 작용이 가능한 컴포넌트

Bootstrap의 모달 다이얼로그, 드롭다운 메뉴 및 커스텀 툴팁 같은 상호 작용이 가능한 컴포넌트는 터치, 마우스, 그리고 키보드 사용자들에게 최적화되어 있습니다. 관련 WAI-ARIA 역할 및 속성의 사용을 통해 이러한 컴포넌트는 보조 기술 (예: 화면 리더기)을 사용하여 이해하고 작동할 수 있어야 합니다.

Bootstrap의 구성요소는 상당히 보편적으로 설계되었으므로 작성자는 해당 구성요소의 정확한 특성과 기능을 보다 정확하게 전달하기 위해 추가 ARIA 역할 및 속성 외에 JavaScript 동작을 포함해야 할 수도 있습니다. 이것은 일반적으로 문서에 명시되어 있습니다.

색상 대비

현재 Bootstrap의 단추 변형, 경고 변형, 폼 유효성 검사 표시기 등을 위해 프레임워크 전체에서 사용되는 기본 팔레트를 구성하는 일부 색상조합은 색상 대비가 불충분할 수 있습니다. (WCAG 2.1 글꼴 색상 대비 4.5:1 미만 및 WCAG 2.1 글꼴 외 색상 대비 3:1 미만이 권장됨). 이 부분은 밝은배경에서 더 강하게 발생하기 때문에 작성자는 특정 색상들을 테스트 한 뒤 필요할 경우 이러한 기본색상을 수동으로 수정/확장하여 적절한 색상 대비를 확인하는 것이 좋습니다.

시각적으로 숨겨진 콘텐츠

시각적으로 숨겨야 하지만 화면 리더기와 같은 보조 기술이 계속 접근해야 하는 콘텐츠는 .visually-hidden 클래스를 사용하여 스타일을 지정할 수 있습니다. 이는 추가적인 시각정보 또는 단서 (예: 색상 사용을 통해 표시되는 의마)를 비 시각적 사용자에게도 전달해야 하는 상황에서 유용할 수 있습니다.

<p class="text-danger">
  <span class="visually-hidden">Danger: </span>
  This action is not reversible
</p>

기존의 “건너뛰기” 링크와 같이 시각적으로 숨겨진 대화형 컨트롤의 경우 .visually-hidden-focusable 클래스를 사용합니다. (고대비 키보드 사용자의 경우) 이렇게 초점이 맞춰지면 컨트롤이 표시됩니다. 이전 버전의 .sr-only.sr-only-focusable 클래스와 달리 Bootstrap 5의 .visually-hidden-focusable 은 독립된 클래스이며 .visually-hidden 클래스와 함께 사용해서는 안됩니다.

<a class="visually-hidden-focusable" href="#content">Skip to main content</a>

감소된 모션

Bootstrap에는 prefers-reduced-motion 미디어 기능 지원이 포함되어 있습니다. 사용자가 감소된 모션에 대한 기본 설정을 지정할 수 있는 브라우저/환경에서 Bootstrap의 대부분의 CSS 전환 효과 (예: 모달 다이얼로그 상자가 열리거나 닫힐 때 또는 캐러셀의 슬라이딩 애니메이션)가 비활성화되고 의미 있는 애니메이션 (예: 스피너)의 속도가 느려집니다.

prefers-reduced-motion을 지원하는 브라우저와 사용자가 감소된 모션을 선호한다고 명시적으로 신호를 보내지 않은 경우 (예: prefers-reduced-motion: no-preference) Bootstrap은 scroll-behavior 속성을 사용하여 부드러운 스크롤을 가능하게 합니다.

추가 자료

` const jsSnippetContent = jsSnippet ? '\/\/ NOTICE!!! Initially embedded in our docs this JavaScript\n\/\/ file contains elements that can help you create reproducible\n\/\/ use cases in StackBlitz for instance\.\n\/\/ In a real project please adapt this content to your needs\.\n\/\/ \u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\u002b\n\n\/\*!\n \* JavaScript for Bootstrap\u0027s docs \(https:\/\/getbootstrap\.com\/\)\n \* Copyright 2011\-2022 The Bootstrap Authors\n \* Copyright 2011\-2022 Twitter, Inc\.\n \* Licensed under the Creative Commons Attribution 3\.0 Unported License\.\n \* For details, see https:\/\/creativecommons\.org\/licenses\/by\/3\.0\/\.\n \*\/\n\n\/\* global bootstrap: false \*\/\n\n\(\(\) =\u003e \{\n \u0027use strict\u0027\n\n \/\/ \-\-\-\-\-\-\-\-\n \/\/ Tooltips\n \/\/ \-\-\-\-\-\-\-\-\n \/\/ Instantiate all tooltips in a docs or StackBlitz page\n document\.querySelectorAll\(\u0027\[data\-bs\-toggle=\u0022tooltip\u0022\]\u0027\)\n \.forEach\(tooltip =\u003e \{\n new bootstrap\.Tooltip\(tooltip\)\n \}\)\n\n \/\/ \-\-\-\-\-\-\-\-\n \/\/ Popovers\n \/\/ \-\-\-\-\-\-\-\-\n \/\/ Instantiate all popovers in a docs or StackBlitz page\n document\.querySelectorAll\(\u0027\[data\-bs\-toggle=\u0022popover\u0022\]\u0027\)\n \.forEach\(popover =\u003e \{\n new bootstrap\.Popover\(popover\)\n \}\)\n\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Toasts\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Used by \u0027Placement\u0027 example in docs or StackBlitz\n const toastPlacement = document\.getElementById\(\u0027toastPlacement\u0027\)\n if \(toastPlacement\) \{\n document\.getElementById\(\u0027selectToastPlacement\u0027\)\.addEventListener\(\u0027change\u0027, function \(\) \{\n if \(!toastPlacement\.dataset\.originalClass\) \{\n toastPlacement\.dataset\.originalClass = toastPlacement\.className\n \}\n\n toastPlacement\.className = `\$\{toastPlacement\.dataset\.originalClass\} \$\{this\.value\}`\n \}\)\n \}\n\n \/\/ Instantiate all toasts in a docs page only\n document\.querySelectorAll\(\u0027\.bd\-example \.toast\u0027\)\n \.forEach\(toastNode =\u003e \{\n const toast = new bootstrap\.Toast\(toastNode, \{\n autohide: false\n \}\)\n\n toast\.show\(\)\n \}\)\n\n \/\/ Instantiate all toasts in a docs page only\n const toastTrigger = document\.getElementById\(\u0027liveToastBtn\u0027\)\n const toastLiveExample = document\.getElementById\(\u0027liveToast\u0027\)\n if \(toastTrigger\) \{\n toastTrigger\.addEventListener\(\u0027click\u0027, \(\) =\u003e \{\n const toast = new bootstrap\.Toast\(toastLiveExample\)\n\n toast\.show\(\)\n \}\)\n \}\n\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Alerts\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Used in \u0027Show live toast\u0027 example in docs or StackBlitz\n const alertPlaceholder = document\.getElementById\(\u0027liveAlertPlaceholder\u0027\)\n const alertTrigger = document\.getElementById\(\u0027liveAlertBtn\u0027\)\n\n const appendAlert = \(message, type\) =\u003e \{\n const wrapper = document\.createElement\(\u0027div\u0027\)\n wrapper\.innerHTML = \[\n `\u003cdiv class=\u0022alert alert\-\$\{type\} alert\-dismissible\u0022 role=\u0022alert\u0022\u003e`,\n ` \u003cdiv\u003e\$\{message\}\u003c\/div\u003e`,\n \u0027 \u003cbutton type=\u0022button\u0022 class=\u0022btn\-close\u0022 data\-bs\-dismiss=\u0022alert\u0022 aria\-label=\u0022Close\u0022\u003e\u003c\/button\u003e\u0027,\n \u0027\u003c\/div\u003e\u0027\n \]\.join\(\u0027\u0027\)\n\n alertPlaceholder\.append\(wrapper\)\n \}\n\n if \(alertTrigger\) \{\n alertTrigger\.addEventListener\(\u0027click\u0027, \(\) =\u003e \{\n appendAlert\(\u0027Nice, you triggered this alert message!\u0027, \u0027success\u0027\)\n \}\)\n \}\n\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Checks \u0026 Radios\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Indeterminate checkbox example in docs and StackBlitz\n document\.querySelectorAll\(\u0027\.bd\-example\-indeterminate \[type=\u0022checkbox\u0022\]\u0027\)\n \.forEach\(checkbox =\u003e \{\n if \(checkbox\.id\.includes\(\u0027Indeterminate\u0027\)\) \{\n checkbox\.indeterminate = true\n \}\n \}\)\n\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Links\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Disable empty links in docs examples only\n document\.querySelectorAll\(\u0027\.bd\-content \[href=\u0022#\u0022\]\u0027\)\n \.forEach\(link =\u003e \{\n link\.addEventListener\(\u0027click\u0027, event =\u003e \{\n event\.preventDefault\(\)\n \}\)\n \}\)\n\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Modal\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Modal \u0027Varying modal content\u0027 example in docs and StackBlitz\n const exampleModal = document\.getElementById\(\u0027exampleModal\u0027\)\n if \(exampleModal\) \{\n exampleModal\.addEventListener\(\u0027show\.bs\.modal\u0027, event =\u003e \{\n \/\/ Button that triggered the modal\n const button = event\.relatedTarget\n \/\/ Extract info from data\-bs\-\* attributes\n const recipient = button\.getAttribute\(\u0027data\-bs\-whatever\u0027\)\n\n \/\/ Update the modal\u0027s content\.\n const modalTitle = exampleModal\.querySelector\(\u0027\.modal\-title\u0027\)\n const modalBodyInput = exampleModal\.querySelector\(\u0027\.modal\-body input\u0027\)\n\n modalTitle\.textContent = `New message to \$\{recipient\}`\n modalBodyInput\.value = recipient\n \}\)\n \}\n\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ Offcanvas\n \/\/ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n \/\/ \u0027Offcanvas components\u0027 example in docs only\n const myOffcanvas = document\.querySelectorAll\(\u0027\.bd\-example\-offcanvas \.offcanvas\u0027\)\n if \(myOffcanvas\) \{\n myOffcanvas\.forEach\(offcanvas =\u003e \{\n offcanvas\.addEventListener\(\u0027show\.bs\.offcanvas\u0027, event =\u003e \{\n event\.preventDefault\(\)\n \}, false\)\n \}\)\n \}\n\}\)\(\)\n' : null const project = { files: { 'index.html': markup, 'index.js': jsSnippetContent }, title: 'Bootstrap Example', description: `Official example from ${window.location.href}`, template: jsSnippet ? 'javascript' : 'html', tags: ['bootstrap'] } StackBlitzSDK.openProject(project, { openFile: 'index.html' }) }