From 92dd82ea6aaee39645a76b61c8d05f9c35317b68 Mon Sep 17 00:00:00 2001 From: pakxe Date: Sun, 22 Sep 2024 23:59:41 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20head=20=ED=83=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=98=20lang=20=EC=86=8D=EC=84=B1=EC=9D=84=20ko=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/index.html | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/a11y/index.html b/a11y/index.html index 12fa3e7..e525729 100644 --- a/a11y/index.html +++ b/a11y/index.html @@ -1,16 +1,14 @@ - - - - - - - - Accessibility - - - -
- - + + + + + + + Accessibility + + +
+ + From 643018699d2f36ce50b4efe8b38c605287a6c808 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 00:12:29 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20main,=20section=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/src/App.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/a11y/src/App.tsx b/a11y/src/App.tsx index a8159f9..986a4fc 100644 --- a/a11y/src/App.tsx +++ b/a11y/src/App.tsx @@ -1,16 +1,16 @@ -import "./Typography.css"; -import "./App.css"; +import './Typography.css'; +import './App.css'; -import FlightBooking from "./components/FlightBooking"; +import FlightBooking from './components/FlightBooking'; function App() { return ( -
-
-
+
+
+
-
-
+ +
); } From 9046e328c0368f8b15d50e84c0c4a4eea3b98e63 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 03:41:45 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20section=20=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/src/App.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/a11y/src/App.tsx b/a11y/src/App.tsx index 986a4fc..dd938e0 100644 --- a/a11y/src/App.tsx +++ b/a11y/src/App.tsx @@ -6,11 +6,11 @@ import FlightBooking from './components/FlightBooking'; function App() { return (
-
+
-
+
); } From dc06e8ba2015453e8b46fa08586706bf322015f4 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 03:43:21 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20main=20=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/src/App.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/a11y/src/App.tsx b/a11y/src/App.tsx index dd938e0..986a4fc 100644 --- a/a11y/src/App.tsx +++ b/a11y/src/App.tsx @@ -6,11 +6,11 @@ import FlightBooking from './components/FlightBooking'; function App() { return (
-
+
-
+
); } From 3e357daf461e359caf3cbebb2b43eb2b4169a4ae Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 03:55:48 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=EC=A6=9D=EA=B0=90=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=EC=97=90=20aria-label=EC=86=8D=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EC=99=80=20=ED=98=84=EC=9E=AC=20=EC=9D=B8=EC=9B=90?= =?UTF-8?q?=EC=88=98=EB=8F=84=20=EC=8B=A4=EC=8B=9C=EA=B0=84=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=BD=EB=8F=84=EB=A1=9D=20aria-live=20=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/src/components/FlightBooking.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/a11y/src/components/FlightBooking.tsx b/a11y/src/components/FlightBooking.tsx index 313cab3..77ca1eb 100644 --- a/a11y/src/components/FlightBooking.tsx +++ b/a11y/src/components/FlightBooking.tsx @@ -16,21 +16,21 @@ const FlightBooking = () => { }; return ( -
-

항공권 예매

-
- 성인 -
- - {adultCount} -
- +
); }; From 602379cd26d23fc3e653c4f2485ed1bf514196ec Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 03:57:29 +0900 Subject: [PATCH 06/11] =?UTF-8?q?fix:=20aria-label=EC=97=90=20=EC=A6=9D?= =?UTF-8?q?=EA=B0=80=20=EA=B0=90=EC=86=8C=EA=B0=80=20=EB=B0=98=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=81=ED=9E=8C=20=EA=B2=83=EC=9D=84=20=EC=98=AC?= =?UTF-8?q?=EB=B0=94=EB=A5=B4=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/src/components/FlightBooking.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/a11y/src/components/FlightBooking.tsx b/a11y/src/components/FlightBooking.tsx index 77ca1eb..0a7f299 100644 --- a/a11y/src/components/FlightBooking.tsx +++ b/a11y/src/components/FlightBooking.tsx @@ -1,6 +1,6 @@ -import { useState } from "react"; +import { useState } from 'react'; -import "./FlightBooking.css"; +import './FlightBooking.css'; const MAX_PASSENGERS = 3; @@ -21,11 +21,11 @@ const FlightBooking = () => {
성인
- {adultCount} -
From 94af3737abc44c849878c110f0af442f97e40ab1 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 04:27:43 +0900 Subject: [PATCH 07/11] =?UTF-8?q?design:=20visually-hidden=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EC=9D=98=20css=EB=A5=BC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/src/components/FlightBooking.css | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/a11y/src/components/FlightBooking.css b/a11y/src/components/FlightBooking.css index d9d6083..db5fc09 100644 --- a/a11y/src/components/FlightBooking.css +++ b/a11y/src/components/FlightBooking.css @@ -34,7 +34,7 @@ width: 30px; height: 30px; border-radius: 16px; - border: 1px solid #C0C0C0; + border: 1px solid #c0c0c0; background-color: #fff; cursor: pointer; display: flex; @@ -61,3 +61,15 @@ border-radius: 4px; cursor: pointer; } + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + border: 0; + padding: 0; + + clip: rect(0 0 0 0); + overflow: hidden; +} From a0a6c93d1c241f83d3fb0237690df89947753b0c Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 04:39:27 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=203=EB=AA=85=EC=9D=84=20=EC=B4=88?= =?UTF-8?q?=EA=B3=BC=ED=95=98=EC=97=AC=20=EC=B6=94=EA=B0=80=ED=95=98?= =?UTF-8?q?=EB=A0=A4=EA=B3=A0=ED=95=98=EB=A9=B4=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=97=90=EB=8A=94=20=EC=95=88=EB=B3=B4=EC=9D=B4=EB=8A=94=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=84=B8=EC=A7=80=EA=B0=80=20?= =?UTF-8?q?=EB=9C=A8=EB=8F=84=EB=A1=9D=20=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/src/components/FlightBooking.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/a11y/src/components/FlightBooking.tsx b/a11y/src/components/FlightBooking.tsx index 0a7f299..f036c95 100644 --- a/a11y/src/components/FlightBooking.tsx +++ b/a11y/src/components/FlightBooking.tsx @@ -6,9 +6,15 @@ const MAX_PASSENGERS = 3; const FlightBooking = () => { const [adultCount, setAdultCount] = useState(1); + const [statusMessage, setStatusMessage] = useState(''); // 스크린 리더가 읽을 메시지 const incrementCount = () => { - setAdultCount((prev) => Math.min(MAX_PASSENGERS, prev + 1)); + if (adultCount >= MAX_PASSENGERS) { + setStatusMessage('최대 승객 수에 도달했습니다.'); + } else { + setStatusMessage(''); + setAdultCount((prev) => Math.min(MAX_PASSENGERS, prev + 1)); + } }; const decrementCount = () => { @@ -21,15 +27,22 @@ const FlightBooking = () => {
성인
- {adultCount} -
+
+ {statusMessage} +
); From 271cd8abb0f75075748d1cea793e91e0d95c5fda Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 04:39:58 +0900 Subject: [PATCH 09/11] =?UTF-8?q?design:=20=EC=8B=9C=EA=B0=81=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=EB=93=A4=EC=9D=84=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94=20css?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/src/components/FlightBooking.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/a11y/src/components/FlightBooking.css b/a11y/src/components/FlightBooking.css index db5fc09..65f4fd2 100644 --- a/a11y/src/components/FlightBooking.css +++ b/a11y/src/components/FlightBooking.css @@ -42,6 +42,12 @@ align-items: center; } +.button-text.disabled { + background-color: #cccccc; + color: #cccccc; + cursor: not-allowed; +} + .counter span { font-size: 18px; text-align: center; From 94dcd2344d01a461b2229c5c13911d3f6e7a2515 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 23 Sep 2024 04:44:54 +0900 Subject: [PATCH 10/11] =?UTF-8?q?docs:=20=EB=A6=AC=EB=93=9C=EB=AF=B8?= =?UTF-8?q?=EC=97=90=20=EA=B2=B0=EA=B3=BC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a11y/README.md | 54 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/a11y/README.md b/a11y/README.md index e749a28..60cfbc3 100644 --- a/a11y/README.md +++ b/a11y/README.md @@ -1,60 +1,100 @@ # 접근성을 고려한 React 컴포넌트 만들기 ## 학습 목표 -접근성 대응을 효율적으로 하기 위해서는 최소한의 코드 수정으로도 최대한의 접근성 향상을 이끌어낼 수 있는 능력이 필요합니다. -앞으로 접근성 개선 작업을 진행하면서, 아래와 같은 원칙을 함께 연습해볼 예정입니다. + +접근성 대응을 효율적으로 하기 위해서는 최소한의 코드 수정으로도 최대한의 접근성 향상을 이끌어낼 수 있는 능력이 필요합니다. +앞으로 접근성 개선 작업을 진행하면서, 아래와 같은 원칙을 함께 연습해볼 예정입니다. + #### 최소한의 마크업으로 최대한의 접근성 확보하기 + - 최소한의 마크업을 사용해 불필요한 요소를 줄이고, HTML의 기본 기능을 최대한 활용합니다. - 시맨틱 태그를 사용해 웹 페이지의 구조를 명확히 하고, 의미를 직관적으로 전달합니다. - ARIA 속성은 꼭 필요한 경우에만 사용하여 추가적인 정보를 제공합니다. - 시각적 표현과 접근성을 모두 만족시키는 방법을 함께 고민합니다. - + ## Step 1: 언어 설정하기 시각 사용자는 UI에 있는 텍스트들만으로 이 문서가 한국어로 된 문서인지 바로 알 수 있지만 스크린 리더는 알 수 없습니다. 스크린 리더가 문서의 언어를 올바르게 인식할 수 있도록 `index.html`에 `lang` 속성을 설정합니다. ### 키워드 + - `lang` 속성 +### 결과 + +모바일 낭독기에서 "heading level 2" -> "머리말 레벨 2"로 읽어줌 + ## Step 2: 시맨틱 태그 사용하기 웹 접근성의 첫걸음은 의미 있는 HTML을 작성하는 것입니다. 웹 표준을 준수하며, 시맨틱 태그를 적극적으로 활용하여 UI의 의미를 명확하게 전달해 주세요. ### 키워드 + - [시맨틱 태그](https://developer.mozilla.org/ko/docs/Learn/Accessibility/HTML) - `App.tsx` 대상으로만 고민해 보세요 +### 결과 + +[스크린 리더의 HTML5 섹션 요소 지원](https://www.accessibilityoz.com/2020/02/html5-sectioning-elements-and-screen-readers/) 글을 참고함. + +| Element | JAWS phrase | NVDA phrase | Narrator phrase | TalkBack phrase (spoken only on Chrome) | VoiceOver phrase | +| ------- | ------------------------- | ------------------------ | ------------------------------ | --------------------------------------- | ------------------------- | +| Header | banner | "banner landmark" | "header banner landmark" | "banner" | "banner, landmark" | +| Nav | navigation region | "navigation landmark" | "navigation landmark" | "navigation" | "navigation, landmark" | +| Aside | complementary information | "complementary landmark" | "aside complementary landmark" | "complementary" | "complementary, landmark" | +| Main | main region | "main landmark" | "main landmark" | "main" | "main, landmark" | + +처음에는 section태그만 사용했는데 랜드마크가 적용되지 않음. 위 글을 보고 main 태그를 사용해야 "메인, 랜드마크"라고 음성 안내를 해줌을 알게됨. + ## Step 3: 버튼 접근성 향상시키기 -기본적으로 웹 표준을 준수하는 태그를 사용하는 것만으로도 네이티브 HTML이 지원해주는 접근성 기능을 활용할 수 있습니다. 예를 들어, 클릭할 수 있는 버튼 UI이라면 다른 태그를 사용하고 클릭 이벤트를 추가하는 것보다 `