Ver3.0 ๐ ์น ์ ๊ทผ์ฑ๊ณผ WCAG ๊ฐ์ด๋๋ผ์ธ ์๋ฒฝ ์ ๋ณต! ๋ชจ๋๋ฅผ ์ํ ํฌ์ฉ์ ์น ์๋น์ค ๋ง๋ค๊ธฐ

๐ ์น ์ ๊ทผ์ฑ๊ณผ WCAG ๊ฐ์ด๋๋ผ์ธ ์๋ฒฝ ์ ๋ณต! ๋ชจ๋๋ฅผ ์ํ ํฌ์ฉ์ ์น ์๋น์ค ๋ง๋ค๊ธฐ
๋๊ตฌ๋ ์ฝ๊ณ ํธํ๊ฒ ์ฌ์ฉํ ์ ์๋ ์น, ๊ทธ ๋น๋ฐ์ ํํค์ณ๋ณด์! ๐
๐ฏ ์น ์ ๊ทผ์ฑ, ์ ์ด๋ ๊ฒ ์ค์ํ ๊ฑธ๊น?
์, ์น๊ตฌ์ผ! ์ค๋์ ์น ๊ฐ๋ฐ์๋ผ๋ฉด ์ ๋ ๋นผ๋์ ์ ์๋ ์ฃผ์ ์ ๋ํด ์ด์ผ๊ธฐํด๋ณด๋ ค๊ณ ํด. ๋ฐ๋ก ์น ์ ๊ทผ์ฑ์ด์ผ! ๐
ํน์ ์ด๋ฐ ์๊ฐ ํด๋ณธ ์ ์์ด? "๋ด๊ฐ ๋ง๋ ์น์ฌ์ดํธ๋ฅผ ์๊ฐ์ฅ์ ์ธ์ ์ด๋ป๊ฒ ์ฌ์ฉํ ๊น?", "ํค๋ณด๋๋ง์ผ๋ก๋ ๋ชจ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์๊น?", "์๋งน์ธ ์ฌ์ฉ์๋ ๋ด ๋์์ธ์ ์ ๋๋ก ๋ณผ ์ ์์๊น?" ์ด๋ฐ ์ง๋ฌธ๋ค์ด ๋ฐ๋ก ์น ์ ๊ทผ์ฑ์ ํต์ฌ์ด์ผ.
์น ์ ๊ทผ์ฑ(Web Accessibility)์ ๋จ์ํ "์ฅ์ ์ธ์ ์ํ ๋ฐฐ๋ ค"๊ฐ ์๋์ผ. ์ด๊ฑด ๋ชจ๋ ์ฌ๋์ด ์น์ ๋๋ฑํ๊ฒ ์ฌ์ฉํ ์ ์๋ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ฅํ๋ ๊ฑฐ์ง. ๋
ธ์ธ, ์ผ์์ ์ฅ์ ๋ฅผ ๊ฐ์ง ์ฌ๋, ๋๋ฆฐ ์ธํฐ๋ท ํ๊ฒฝ์ ์ฌ์ฉ์๊น์ง ๋ชจ๋ ํฌํจํ๋ ๊ฐ๋
์ด์ผ. ๐ค
์ ์ธ๊ณ ์ธ๊ตฌ์ ์ฝ 15%๊ฐ ์ด๋ค ํํ๋ก๋ ์ฅ์ ๋ฅผ ๊ฐ์ง๊ณ ์์ด. ์ด๊ฑด ์ฝ 10์ต ๋ช ์ด ๋๋ ์ซ์์ผ! ์น ์ ๊ทผ์ฑ์ ๊ณ ๋ คํ์ง ์๋๋ค๋ ๊ฑด, ์ด ๊ฑฐ๋ํ ์ฌ์ฉ์ ๊ทธ๋ฃน์ ์ธ๋ฉดํ๋ ๊ฑฐ๋ ๋ง์ฐฌ๊ฐ์ง์ง. ๐ฎ
๐ ์น ์ ๊ทผ์ฑ์ ์ค์ ์ํฅ๋ ฅ
์น ์ ๊ทผ์ฑ์ด ์ ์ค์ํ์ง ๊ตฌ์ฒด์ ์ธ ์์๋ฅผ ๋ค์ด๋ณผ๊ฒ:
1. ์๊ฐ ์ฅ์ ์ธ์ ๊ฒฝ์ฐ
์คํฌ๋ฆฐ ๋ฆฌ๋(Screen Reader)๋ผ๋ ํ๋ก๊ทธ๋จ์ ์ฌ์ฉํด์ ์น์ฌ์ดํธ์ ๋ด์ฉ์ ์์ฑ์ผ๋ก ๋ค์ด. ๋ง์ฝ ์ด๋ฏธ์ง์ ๋์ฒด ํ
์คํธ(alt text)๊ฐ ์๋ค๋ฉด? ๊ทธ๋ฅ "์ด๋ฏธ์ง"๋ผ๊ณ ๋ง ์ฝํ๊ฒ ์ง. ๋ฌด์จ ๋ด์ฉ์ธ์ง ์ ํ ์ ์ ์์ด. ๐ข
2. ์ฒญ๊ฐ ์ฅ์ ์ธ์ ๊ฒฝ์ฐ
๋์์ ์ฝํ
์ธ ์ ์๋ง์ด๋ ์ํ ํต์ญ์ด ์๋ค๋ฉด? ์๋ฌด๋ฆฌ ์ข์ ์ฝํ
์ธ ๋ผ๋ ์ ๊ทผํ ์ ์๊ฒ ๋ผ.
3. ์ด๋ ์ฅ์ ์ธ์ ๊ฒฝ์ฐ
๋ง์ฐ์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ์ด๋ ค์ด ์ฌ๋๋ค์ ํค๋ณด๋๋ง์ผ๋ก ์น์ฌ์ดํธ๋ฅผ ํ์ํด์ผ ํด. ๋ง์ฝ ํค๋ณด๋ ๋ค๋น๊ฒ์ด์
์ด ์ ๋๋ก ๊ตฌํ๋์ง ์์๋ค๋ฉด? ํน์ ๊ธฐ๋ฅ์ ์์ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ ๊ฑฐ์ผ. ๐น
4. ์ธ์ง ์ฅ์ ์ธ์ ๊ฒฝ์ฐ
๋ณต์กํ ์ธํฐํ์ด์ค๋ ์ผ๊ด์ฑ ์๋ ๋์์ธ์ ์ดํดํ๊ธฐ ์ด๋ ค์ธ ์ ์์ด. ๋ช
ํํ๊ณ ๋จ์ํ ๊ตฌ์กฐ๊ฐ ํ์์ ์ด์ง.
์น ์ ๊ทผ์ฑ์ ๋จ์ํ ์ค๋ฆฌ์ ๋ฌธ์ ๊ฐ ์๋์ผ. SEO(๊ฒ์ ์์ง ์ต์ ํ)์๋ ๊ธ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น๊ณ , ๋ฒ์ ๋ฆฌ์คํฌ๋ฅผ ์ค์ด๋ฉฐ, ๋ ๋์ ์ฌ์ฉ์์ธต์๊ฒ ๋๋ฌํ ์ ์๊ฒ ํด์ค. ์ค์ ๋ก ๋ง์ ๊ตญ๊ฐ์์ ์น ์ ๊ทผ์ฑ์ ๋ฒ์ผ๋ก ์๋ฌดํํ๊ณ ์์ด! ๐
๐ WCAG, ์น ์ ๊ทผ์ฑ์ ๋ฐ์ด๋ธ์ ๋ง๋๋ณด์!
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก WCAG(Web Content Accessibility Guidelines)์ ๋ํด ์์๋ณผ ์๊ฐ์ด์ผ! ์ด๊ฑด W3C(World Wide Web Consortium)์์ ๋ง๋ ์น ์ ๊ทผ์ฑ ๊ตญ์ ํ์ค ๊ฐ์ด๋๋ผ์ธ์ด์ผ. ๐
WCAG๋ ํ์ฌ 2.1 ๋ฒ์ ์ด ๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋๊ณ ์๊ณ , 2.2 ๋ฒ์ ๋ ์ต๊ทผ์ ๋ฐํ๋์์ด. ๊ทธ๋ฆฌ๊ณ WCAG 3.0๋ ๊ฐ๋ฐ ์ค์ด์ผ! ํ์ง๋ง ์ค๋์ ๊ฐ์ฅ ์ค์ฉ์ ์ธ WCAG 2.1์ ์ค์ฌ์ผ๋ก ์ค๋ช
ํ ๊ฒ.
๐จ WCAG์ 4๊ฐ์ง ํต์ฌ ์์น: POUR
WCAG๋ 4๊ฐ์ง ํต์ฌ ์์น์ ๊ธฐ๋ฐ์ผ๋ก ํด. ์ด๊ฑธ ์์ด ์ฒซ ๊ธ์๋ฅผ ๋ฐ์ POUR๋ผ๊ณ ๋ถ๋ฌ. ํ๋์ฉ ์์ธํ ์ดํด๋ณด์! ๐ค
1๏ธโฃ Perceivable (์ธ์ ๊ฐ๋ฅ์ฑ) ๐๏ธ
"์ฌ์ฉ์๊ฐ ์ฝํ
์ธ ๋ฅผ ์ธ์ํ ์ ์์ด์ผ ํ๋ค"
์ ๋ณด์ ์ฌ์ฉ์ ์ธํฐํ์ด์ค ์์๋ ์ฌ์ฉ์๊ฐ ์ธ์ํ ์ ์๋ ๋ฐฉ์์ผ๋ก ์ ๊ณต๋์ด์ผ ํด. ์ฆ, ํ ๊ฐ์ง ๊ฐ๊ฐ์ผ๋ก๋ง ์ ๋ณด๋ฅผ ์ ๋ฌํ๋ฉด ์ ๋๋ค๋ ๊ฑฐ์ผ.
๊ตฌ์ฒด์ ์ธ ์์:
โข ๋ชจ๋ ์ด๋ฏธ์ง์ ๋์ฒด ํ
์คํธ ์ ๊ณต
โข ๋์์์ ์๋ง๊ณผ ์์ฑ ์ค๋ช
์ ๊ณต
โข ์์๋ง์ผ๋ก ์ ๋ณด๋ฅผ ์ ๋ฌํ์ง ์๊ธฐ (์: "๋นจ๊ฐ์ ๋ฒํผ์ ํด๋ฆญํ์ธ์" โ)
โข ์ถฉ๋ถํ ๋ช
์๋น ํ๋ณด (ํ
์คํธ์ ๋ฐฐ๊ฒฝ์ ๋๋น)
2๏ธโฃ Operable (์ด์ฉ ๊ฐ๋ฅ์ฑ) โจ๏ธ
"์ฌ์ฉ์๊ฐ ์ธํฐํ์ด์ค๋ฅผ ์กฐ์ํ ์ ์์ด์ผ ํ๋ค"
๋ชจ๋ ๊ธฐ๋ฅ์ ๋ค์ํ ์
๋ ฅ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ ์ ์์ด์ผ ํด. ๋ง์ฐ์ค๋ง ์ฌ์ฉ ๊ฐ๋ฅํ ๊ธฐ๋ฅ์ ์ ๋ผ!
๊ตฌ์ฒด์ ์ธ ์์:
โข ํค๋ณด๋๋ง์ผ๋ก ๋ชจ๋ ๊ธฐ๋ฅ ์ฌ์ฉ ๊ฐ๋ฅ
โข ์ถฉ๋ถํ ์๊ฐ ์ ๊ณต (์๋์ผ๋ก ๋์ด๊ฐ๋ ์ฝํ
์ธ ์ ์ผ์์ ์ง ๊ธฐ๋ฅ)
โข ๋ฐ์์ ์ผ์ผํฌ ์ ์๋ ๊น๋นก์ ํจ๊ณผ ๊ธ์ง
โข ๋ช
ํํ ๋ค๋น๊ฒ์ด์
๊ตฌ์กฐ
โข ํฌ์ปค์ค ํ์๊ฐ ๋ช
ํํด์ผ ํจ
3๏ธโฃ Understandable (์ดํด ๊ฐ๋ฅ์ฑ) ๐ง
"์ ๋ณด์ ์ฌ์ฉ์ ์ธํฐํ์ด์ค ์กฐ์์ด ์ดํด ๊ฐ๋ฅํด์ผ ํ๋ค"
์ฝํ
์ธ ๋ ๋ช
ํํ๊ณ ์์ธก ๊ฐ๋ฅํด์ผ ํด. ์ฌ์ฉ์๊ฐ ํผ๋์ค๋ฌ์ํ๋ฉด ์ ๋ผ!
๊ตฌ์ฒด์ ์ธ ์์:
โข ๋ช
ํํ๊ณ ๊ฐ๋จํ ์ธ์ด ์ฌ์ฉ
โข ์ผ๊ด๋ ๋ค๋น๊ฒ์ด์
๊ณผ ์๋ณ
โข ์์ธก ๊ฐ๋ฅํ ๋์ (๊ฐ์๊ธฐ ์ ์ฐฝ์ด ์ด๋ฆฌ๋ฉด ์ ๋ผ)
โข ์
๋ ฅ ์ค๋ฅ ๋ฐฉ์ง ๋ฐ ์์ ๊ธฐํ ์ ๊ณต
โข ๋ช
ํํ ๋ ์ด๋ธ๊ณผ ์ง์์ฌํญ
4๏ธโฃ Robust (๊ฒฌ๊ณ ์ฑ) ๐ช
"์ฝํ
์ธ ๋ ๋ค์ํ ์ฌ์ฉ์ ์์ด์ ํธ์์ ํด์๋ ์ ์์ด์ผ ํ๋ค"
ํ์ฌ์ ๋ฏธ๋์ ๋ค์ํ ๊ธฐ์ (๋ธ๋ผ์ฐ์ , ๋ณด์กฐ ๊ธฐ์ ๋ฑ)์์ ์๋ํด์ผ ํด.
๊ตฌ์ฒด์ ์ธ ์์:
โข ์ ํจํ HTML/CSS ์ฝ๋ ์์ฑ
โข ์ ์ ํ ARIA(Accessible Rich Internet Applications) ์์ฑ ์ฌ์ฉ
โข ํ์ค ์น ๊ธฐ์ ์ค์
โข ๋ค์ํ ๋ธ๋ผ์ฐ์ ์ ๋ณด์กฐ ๊ธฐ์ ๊ณผ์ ํธํ์ฑ
๐ WCAG ์ค์ ๋ ๋ฒจ: A, AA, AAA
WCAG๋ 3๊ฐ์ง ์ค์ ๋ ๋ฒจ์ ์ ๊ณตํด. ๊ฐ ๋ ๋ฒจ์ ์ ๊ทผ์ฑ์ ์ ๋๋ฅผ ๋ํ๋ด์ง. ๐ฏ
| ๋ ๋ฒจ | ์ค๋ช | ๋์ด๋ | ๊ถ์ฅ ์ฌํญ |
|---|---|---|---|
| Level A | ์ต์ํ์ ์ ๊ทผ์ฑ ์๊ตฌ์ฌํญ. ์ด๊ฒ๋ ์ถฉ์กฑํ์ง ๋ชปํ๋ฉด ์ผ๋ถ ์ฌ์ฉ์๋ ์ฝํ ์ธ ์ ์ ํ ์ ๊ทผํ ์ ์์ | ๊ธฐ๋ณธ | ํ์ ์ค์ |
| Level AA | ๋๋ถ๋ถ์ ์ฅ์ ๋ฅผ ๊ฐ์ง ์ฌ์ฉ์๊ฐ ์ฝํ ์ธ ์ ์ ๊ทผ ๊ฐ๋ฅ. ๋ฒ์ ์๊ตฌ์ฌํญ์ผ๋ก ๊ฐ์ฅ ๋ง์ด ์ฑํ๋จ | ์ค๊ฐ | ๋ชฉํ ๋ ๋ฒจ |
| Level AAA | ์ต๊ณ ์์ค์ ์ ๊ทผ์ฑ. ๋ชจ๋ ์ฝํ ์ธ ์ ์ ์ฉํ๊ธฐ๋ ์ด๋ ค์ธ ์ ์์ | ๊ณ ๊ธ | ์ด์์ ๋ชฉํ |
๋๋ถ๋ถ์ ์กฐ์ง์ Level AA๋ฅผ ๋ชฉํ๋ก ํด. ์ด๊ฒ ๋ฒ์ ์๊ตฌ์ฌํญ์ ์ถฉ์กฑํ๋ฉด์๋ ์คํ ๊ฐ๋ฅํ ์์ค์ด๊ฑฐ๋ . Level AAA๋ ํน์ ์ฝํ ์ธ ๋ ์น์ ์๋ง ์ ์ฉํ๋ ๊ฒ ํ์ค์ ์ด์ผ! ๐ผ
๐ ๏ธ ์ค์ ! WCAG ๊ฐ์ด๋๋ผ์ธ ๊ตฌ์ฒด์ ์ผ๋ก ์ ์ฉํ๊ธฐ
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋, ์ด์ ์ค์ ๋ก ์ด๋ป๊ฒ ์ ์ฉํ๋์ง ์์๋ณด์! ๊ฐ ์์น๋ณ๋ก ๊ตฌ์ฒด์ ์ธ ๊ตฌํ ๋ฐฉ๋ฒ์ ์ดํด๋ณผ๊ฒ. ์ฝ๋ ์์ ๋ ํจ๊ป ์ ๊ณตํ ํ ๋ ๋ฐ๋ก ์ ์ฉํด๋ณผ ์ ์์ด! ๐ป
๐๏ธ Perceivable: ์ธ์ ๊ฐ๋ฅ์ฑ ๊ตฌํํ๊ธฐ
1. ๋์ฒด ํ ์คํธ(Alternative Text) ์ ๊ณต
๋ชจ๋ ๋นํ ์คํธ ์ฝํ ์ธ ์๋ ๋์ฒด ํ ์คํธ๋ฅผ ์ ๊ณตํด์ผ ํด. ์ด๊ฑด ์น ์ ๊ทผ์ฑ์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ด์ ํต์ฌ์ด์ผ!
<!-- โ ๋์ ์ -->
<img src="product.jpg">
<!-- โ
์ข์ ์ -->
<img src="product.jpg" alt="ํ๋์ ๋ฌด์ ๋ง์ฐ์ค, ์ธ์ฒด๊ณตํ์ ๋์์ธ">
<!-- ์ฅ์์ฉ ์ด๋ฏธ์ง์ ๊ฒฝ์ฐ -->
<img src="decoration.jpg" alt="" role="presentation">
<!-- ๋ณต์กํ ์ด๋ฏธ์ง์ ๊ฒฝ์ฐ -->
<img src="chart.jpg" alt="2023๋
๋งค์ถ ์ถ์ด ๊ทธ๋ํ"
longdesc="chart-description.html">
โข ์ด๋ฏธ์ง์ ๋ชฉ์ ๊ณผ ์๋ฏธ๋ฅผ ์ค๋ช ํด์ผ ํด
โข "์ด๋ฏธ์ง", "์ฌ์ง" ๊ฐ์ ๋ถํ์ํ ๋จ์ด๋ ๋นผ
โข ์ฅ์์ฉ ์ด๋ฏธ์ง๋ ๋น alt ์์ฑ ์ฌ์ฉ (alt="")
โข ๋ณต์กํ ์ ๋ณด๋ longdesc๋ ๋ณ๋ ์ค๋ช ํ์ด์ง ์ ๊ณต
โข 150์ ์ด๋ด๋ก ๊ฐ๊ฒฐํ๊ฒ!
2. ์์ ๋๋น(Color Contrast) ํ๋ณด
ํ ์คํธ์ ๋ฐฐ๊ฒฝ ์ฌ์ด์ ๋ช ์๋น๋ ๋งค์ฐ ์ค์ํด. WCAG 2.1 ๊ธฐ์ค์ ์ด๋:
| ์ฝํ ์ธ ์ ํ | Level AA | Level AAA |
|---|---|---|
| ์ผ๋ฐ ํ ์คํธ (18pt ๋ฏธ๋ง) | 4.5:1 ์ด์ | 7:1 ์ด์ |
| ํฐ ํ ์คํธ (18pt ์ด์ ๋๋ 14pt bold) | 3:1 ์ด์ | 4.5:1 ์ด์ |
| UI ์ปดํฌ๋ํธ ๋ฐ ๊ทธ๋ํฝ | 3:1 ์ด์ | - |
/* โ ๋์ ์ - ๋๋น๊ฐ ๋ถ์กฑํจ */
.text {
color: #999999;
background-color: #ffffff;
/* ๋๋น์จ: 2.85:1 (๋ถ์ถฉ๋ถ) */
}
/* โ
์ข์ ์ - ์ถฉ๋ถํ ๋๋น */
.text {
color: #595959;
background-color: #ffffff;
/* ๋๋น์จ: 7.0:1 (AAA ๋ ๋ฒจ) */
}
/* ์์๋ง์ผ๋ก ์ ๋ณด ์ ๋ฌ ๊ธ์ง */
/* โ ๋์ ์ */
.error { color: red; }
/* โ
์ข์ ์ - ์์ด์ฝ๊ณผ ํ
์คํธ ์ถ๊ฐ */
.error {
color: #d32f2f;
font-weight: bold;
}
.error::before {
content: "โ ๏ธ ";
}
โข WebAIM Contrast Checker: ์์ ๋๋น ํ์ธ
โข Colour Contrast Analyser: ๋ฐ์คํฌํฑ ์ฑ
โข Chrome DevTools: ๋ด์ฅ ๋๋น ๊ฒ์ฌ ๊ธฐ๋ฅ
โข Stark: Figma/Sketch ํ๋ฌ๊ทธ์ธ
3. ์๋ง๊ณผ ์์ฑ ์ค๋ช ์ ๊ณต
๋ฉํฐ๋ฏธ๋์ด ์ฝํ ์ธ ์๋ ๋ฐ๋์ ๋์ฒด ์๋จ์ ์ ๊ณตํด์ผ ํด!
<!-- ์๋ง์ด ์๋ ๋น๋์ค -->
<video controls>
<source src="video.mp4" type="video/mp4">
<track kind="captions" src="captions-ko.vtt"
srclang="ko" label="ํ๊ตญ์ด">
<track kind="captions" src="captions-en.vtt"
srclang="en" label="English">
<track kind="descriptions" src="descriptions.vtt"
srclang="ko" label="์์ฑ ์ค๋ช
">
</video>
<!-- ์ค๋์ค ์ฝํ
์ธ ์ ๋๋ณธ ์ ๊ณต -->
<audio controls>
<source src="podcast.mp3" type="audio/mpeg">
</audio>
<details>
<summary>ํ์บ์คํธ ๋๋ณธ ๋ณด๊ธฐ</summary>
<p>[๋๋ณธ ๋ด์ฉ]</p>
</details>
โจ๏ธ Operable: ์ด์ฉ ๊ฐ๋ฅ์ฑ ๊ตฌํํ๊ธฐ
1. ํค๋ณด๋ ์ ๊ทผ์ฑ ๋ณด์ฅ
๋ชจ๋ ๊ธฐ๋ฅ์ ํค๋ณด๋๋ง์ผ๋ก๋ ์ฌ์ฉํ ์ ์์ด์ผ ํด. ์ด๊ฑด ์ ๋ง ์ค์ํด! ๐น
<!-- โ ๋์ ์ - ๋ง์ฐ์ค ์ด๋ฒคํธ๋ง ์ฌ์ฉ -->
<div onclick="doSomething()">ํด๋ฆญํ์ธ์</div>
<!-- โ
์ข์ ์ - ํค๋ณด๋ ์ ๊ทผ ๊ฐ๋ฅ -->
<button onclick="doSomething()"
onkeypress="handleKeyPress(event)">
ํด๋ฆญํ์ธ์
</button>
<!-- ์ปค์คํ
์ธํฐ๋ํฐ๋ธ ์์ -->
<div role="button"
tabindex="0"
onclick="doSomething()"
onkeypress="handleKeyPress(event)"
aria-label="์์
์คํ">
ํด๋ฆญํ์ธ์
</div>
<script>
function handleKeyPress(event) {
// Enter(13) ๋๋ Space(32) ํค ์ฒ๋ฆฌ
if (event.keyCode === 13 || event.keyCode === 32) {
event.preventDefault();
doSomething();
}
}
</script>
2. ํฌ์ปค์ค ๊ด๋ฆฌ
ํฌ์ปค์ค๋ ์ฌ์ฉ์๊ฐ ํ์ฌ ์ด๋์ ์๋์ง ์๋ ค์ฃผ๋ ์ค์ํ ์๊ฐ์ ๋จ์์ผ!
/* โ ์ ๋ ํ์ง ๋ง์์ผ ํ ๊ฒ! */
*:focus {
outline: none; /* ํฌ์ปค์ค ํ์ ์ ๊ฑฐ ๊ธ์ง! */
}
/* โ
์ข์ ์ - ๋ช
ํํ ํฌ์ปค์ค ํ์ */
a:focus,
button:focus,
input:focus {
outline: 3px solid #667eea;
outline-offset: 2px;
}
/* ๋ ๋์ ๋ฐฉ๋ฒ - :focus-visible ์ฌ์ฉ */
*:focus-visible {
outline: 3px solid #667eea;
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.2);
}
/* ์คํต ๋งํฌ ๊ตฌํ */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #667eea;
color: white;
padding: 8px;
text-decoration: none;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
<!-- ์คํต ๋งํฌ ์์ -->
<a href="#main-content" class="skip-link">
๋ณธ๋ฌธ์ผ๋ก ๋ฐ๋ก๊ฐ๊ธฐ
</a>
<nav>
<!-- ๋ค๋น๊ฒ์ด์
๋ฉ๋ด -->
</nav>
<main id="main-content">
<!-- ์ฃผ์ ์ฝํ
์ธ -->
</main>
3. ์ถฉ๋ถํ ์๊ฐ ์ ๊ณต
์๋์ผ๋ก ์งํ๋๋ ์ฝํ ์ธ ๋ ์ฌ์ฉ์๊ฐ ์ ์ดํ ์ ์์ด์ผ ํด!
<!-- ์๋ ์ฌ๋ผ์ด๋์ ์ปจํธ๋กค ์ ๊ณต -->
<div class="carousel" role="region" aria-label="์ด๋ฏธ์ง ์ฌ๋ผ์ด๋">
<div class="carousel-controls">
<button aria-label="์ด์ ์ฌ๋ผ์ด๋">โ</button>
<button aria-label="์๋ ์ฌ์ ์ผ์์ ์ง"
id="pause-btn">โธ</button>
<button aria-label="๋ค์ ์ฌ๋ผ์ด๋">โถ</button>
</div>
<div class="carousel-slides">
<!-- ์ฌ๋ผ์ด๋ ๋ด์ฉ -->
</div>
</div>
<!-- ์ธ์
ํ์์์ ๊ฒฝ๊ณ -->
<div role="alert" aria-live="assertive" id="timeout-warning" hidden>
์ธ์
์ด 2๋ถ ํ ๋ง๋ฃ๋ฉ๋๋ค. ๊ณ์ํ์๊ฒ ์ต๋๊น?
<button>์ธ์
์ฐ์ฅ</button>
</div>
๐ง Understandable: ์ดํด ๊ฐ๋ฅ์ฑ ๊ตฌํํ๊ธฐ
1. ๋ช ํํ ์ธ์ด์ ๋ ์ด๋ธ
<!-- โ ๋์ ์ -->
<input type="text" placeholder="์
๋ ฅ">
<!-- โ
์ข์ ์ -->
<label for="username">์ฌ์ฉ์ ์ด๋ฆ</label>
<input type="text"
id="username"
name="username"
aria-describedby="username-help"
required>
<span id="username-help" class="help-text">
4-20์์ ์๋ฌธ, ์ซ์๋ง ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค
</span>
<!-- ํผ ๊ทธ๋ฃนํ -->
<fieldset>
<legend>๋ฐฐ์ก ์ ๋ณด</legend>
<label for="address">์ฃผ์</label>
<input type="text" id="address">
<label for="city">๋์</label>
<input type="text" id="city">
</fieldset>
2. ์ค๋ฅ ์ฒ๋ฆฌ์ ๋์๋ง
<form>
<div class="form-group">
<label for="email">์ด๋ฉ์ผ ์ฃผ์ *</label>
<input type="email"
id="email"
aria-required="true"
aria-invalid="false"
aria-describedby="email-error">
<span id="email-error"
class="error-message"
role="alert"
hidden>
์ฌ๋ฐ๋ฅธ ์ด๋ฉ์ผ ํ์์ด ์๋๋๋ค
</span>
</div>
</form>
<script>
function validateEmail(input) {
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.value);
const errorMsg = document.getElementById('email-error');
if (!isValid) {
input.setAttribute('aria-invalid', 'true');
errorMsg.hidden = false;
} else {
input.setAttribute('aria-invalid', 'false');
errorMsg.hidden = true;
}
}
</script>
โข ๋ฌด์์ด ์๋ชป๋์๋์ง ๋ช ํํ ์ค๋ช
โข ์ด๋ป๊ฒ ์์ ํด์ผ ํ๋์ง ์๋ด
โข ๊ธ์ ์ ์ด๊ณ ๋์์ด ๋๋ ํค ์ฌ์ฉ
โข ์ค๋ฅ ์์น๋ฅผ ์๊ฐ์ ์ผ๋ก ํ์
โข ์คํฌ๋ฆฐ ๋ฆฌ๋๊ฐ ์ฝ์ ์ ์๋๋ก role="alert" ์ฌ์ฉ
3. ์ผ๊ด์ฑ ์๋ ๋ค๋น๊ฒ์ด์
<!-- ์ผ๊ด๋ ํค๋ ๊ตฌ์กฐ -->
<header role="banner">
<nav role="navigation" aria-label="์ฃผ ๋ฉ๋ด">
<ul>
<li><a href="/" aria-current="page">ํ</a></li>
<li><a href="/about">์๊ฐ</a></li>
<li><a href="/services">์๋น์ค</a></li>
<li><a href="/contact">์ฐ๋ฝ์ฒ</a></li>
</ul>
</nav>
</header>
<!-- ๋นต๋ถ์ค๋ฌ๊ธฐ ๋ค๋น๊ฒ์ด์
-->
<nav aria-label="๋นต๋ถ์ค๋ฌ๊ธฐ">
<ol>
<li><a href="/">ํ</a></li>
<li><a href="/products">์ ํ</a></li>
<li aria-current="page">๋
ธํธ๋ถ</li>
</ol>
</nav>
๐ช Robust: ๊ฒฌ๊ณ ์ฑ ๊ตฌํํ๊ธฐ
1. ์๋งจํฑ HTML ์ฌ์ฉ
<!-- โ ๋์ ์ - ์๋ฏธ ์๋ div ๋จ์ฉ -->
<div class="header">
<div class="nav">...</div>
</div>
<div class="main">
<div class="article">...</div>
</div>
<!-- โ
์ข์ ์ - ์๋งจํฑ HTML -->
<header>
<nav>...</nav>
</header>
<main>
<article>
<h1>์ ๋ชฉ</h1>
<section>
<h2>์์ ๋ชฉ</h2>
<p>๋ด์ฉ...</p>
</section>
</article>
<aside>
<h2>๊ด๋ จ ์ ๋ณด</h2>
</aside>
</main>
<footer>...</footer>
2. ARIA ์์ฑ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๊ธฐ
ARIA(Accessible Rich Internet Applications)๋ HTML๋ง์ผ๋ก ํํํ๊ธฐ ์ด๋ ค์ด ๋์ ์ฝํ ์ธ ์ ์ ๊ทผ์ฑ์ ํฅ์์์ผ์ค. ํ์ง๋ง ์๋ชป ์ฌ์ฉํ๋ฉด ์คํ๋ ค ํด๊ฐ ๋ ์ ์์ด! โ ๏ธ
<!-- ARIA ์ญํ (role) -->
<div role="button" tabindex="0">ํด๋ฆญ</div>
<div role="alert">์ค์ํ ์๋ฆผ</div>
<div role="dialog" aria-labelledby="dialog-title">
<h2 id="dialog-title">ํ์ธ</h2>
</div>
<!-- ARIA ์ํ(state) -->
<button aria-pressed="false">ํ ๊ธ</button>
<div aria-expanded="false">์ ์ ์ ์๋ ๋ด์ฉ</div>
<input aria-invalid="true">
<!-- ARIA ์์ฑ(property) -->
<button aria-label="๋ซ๊ธฐ">ร</button>
<div aria-describedby="help-text">...</div>
<nav aria-label="์ฃผ ๋ฉ๋ด">...</nav>
<!-- ๋ผ์ด๋ธ ๋ฆฌ์ (Live Region) -->
<div aria-live="polite" aria-atomic="true">
์
๋ฐ์ดํธ๋ ๋ด์ฉ์ด ์ฌ๊ธฐ ํ์๋ฉ๋๋ค
</div>
<div aria-live="assertive" role="alert">
๊ธด๊ธ ์๋ฆผ!
</div>
์ฒซ ๋ฒ์งธ ๊ท์น: ARIA๋ฅผ ์ฌ์ฉํ์ง ๋ง์ธ์!
๋ค์ดํฐ๋ธ HTML ์์๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ฉด ๊ทธ๊ฑธ ์ฌ์ฉํด. ARIA๋ HTML๋ก ํด๊ฒฐํ ์ ์์ ๋๋ง ์ฌ์ฉํ๋ ๊ฑฐ์ผ.
๋ ๋ฒ์งธ ๊ท์น: ์ญํ ์ ๋ณ๊ฒฝํ์ง ๋ง์ธ์!
<button role="heading"> ๊ฐ์ ๊ฑด ์ ๋ ์ ๋ผ!
์ธ ๋ฒ์งธ ๊ท์น: ๋ชจ๋ ์ธํฐ๋ํฐ๋ธ ์์๋ ํค๋ณด๋๋ก ์ ๊ทผ ๊ฐ๋ฅํด์ผ ํด!
role="button"์ ์ฌ์ฉํ๋ค๋ฉด ๋ฐ๋์ tabindex์ ํค๋ณด๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ถ๊ฐํด์ผ ํด.
3. ๋ณต์กํ ์์ ฏ ๊ตฌํ ์์
<!-- ์ ๊ทผ ๊ฐ๋ฅํ ํญ ํจ๋ -->
<div class="tabs">
<div role="tablist" aria-label="์ฝํ
์ธ ํญ">
<button role="tab"
aria-selected="true"
aria-controls="panel-1"
id="tab-1"
tabindex="0">
ํญ 1
</button>
<button role="tab"
aria-selected="false"
aria-controls="panel-2"
id="tab-2"
tabindex="-1">
ํญ 2
</button>
<button role="tab"
aria-selected="false"
aria-controls="panel-3"
id="tab-3"
tabindex="-1">
ํญ 3
</button>
</div>
<div role="tabpanel"
id="panel-1"
aria-labelledby="tab-1">
ํญ 1์ ๋ด์ฉ
</div>
<div role="tabpanel"
id="panel-2"
aria-labelledby="tab-2"
hidden>
ํญ 2์ ๋ด์ฉ
</div>
<div role="tabpanel"
id="panel-3"
aria-labelledby="tab-3"
hidden>
ํญ 3์ ๋ด์ฉ
</div>
</div>
<script>
// ํญ ํค๋ณด๋ ๋ค๋น๊ฒ์ด์
๊ตฌํ
const tabs = document.querySelectorAll('[role="tab"]');
const tabList = document.querySelector('[role="tablist"]');
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => changeTabs(tab));
tab.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight') {
const nextTab = tabs[(index + 1) % tabs.length];
changeTabs(nextTab);
nextTab.focus();
} else if (e.key === 'ArrowLeft') {
const prevTab = tabs[(index - 1 + tabs.length) % tabs.length];
changeTabs(prevTab);
prevTab.focus();
}
});
});
function changeTabs(selectedTab) {
tabs.forEach(tab => {
tab.setAttribute('aria-selected', 'false');
tab.setAttribute('tabindex', '-1');
const panel = document.getElementById(
tab.getAttribute('aria-controls')
);
panel.hidden = true;
});
selectedTab.setAttribute('aria-selected', 'true');
selectedTab.setAttribute('tabindex', '0');
const selectedPanel = document.getElementById(
selectedTab.getAttribute('aria-controls')
);
selectedPanel.hidden = false;
}
</script>
๐งช ์น ์ ๊ทผ์ฑ ํ ์คํธ์ ๊ฒ์ฆ ๋ฐฉ๋ฒ
์, ์ด์ ์น์ฌ์ดํธ๋ฅผ ๋ง๋ค์๋ค๋ฉด ์ ๋๋ก ์ ๊ทผ ๊ฐ๋ฅํ์ง ํ ์คํธํด์ผ๊ฒ ์ง? ๋ค์ํ ํ ์คํธ ๋ฐฉ๋ฒ๊ณผ ๋๊ตฌ๋ฅผ ์์๋ณด์! ๐
๐ ๏ธ ์๋ํ ํ ์คํธ ๋๊ตฌ
1. ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ
โข WAVE (Web Accessibility Evaluation Tool)
์๊ฐ์ ์ผ๋ก ์ ๊ทผ์ฑ ๋ฌธ์ ๋ฅผ ํ์ํด์ค. ์ด๋ณด์์๊ฒ ํนํ ์ข์!
โข axe DevTools
๊ฐ๋ฐ์ ๋๊ตฌ์ ํตํฉ๋์ด ์ฌ์ฉํ๊ธฐ ํธํด. ๋งค์ฐ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํด.
โข Lighthouse
Chrome DevTools์ ๋ด์ฅ๋์ด ์์ด. ์ ๊ทผ์ฑ๋ฟ๋ง ์๋๋ผ ์ฑ๋ฅ, SEO๋ ํจ๊ป ์ฒดํฌํด์ค.
โข IBM Equal Access Accessibility Checker
IBM์์ ๋ง๋ ๊ฐ๋ ฅํ ๋๊ตฌ. ์์ธํ ๊ฐ์ด๋๋ฅผ ์ ๊ณตํด.
2. ๋ช ๋ น์ค ๋๊ตฌ
# axe-core CLI ์ค์น
npm install -g @axe-core/cli
# ์น์ฌ์ดํธ ํ
์คํธ
axe https://example.com
# Pa11y ์ค์น ๋ฐ ์ฌ์ฉ
npm install -g pa11y
pa11y https://example.com
# ์ฌ๋ฌ ํ์ด์ง ํ
์คํธ
pa11y-ci --sitemap https://example.com/sitemap.xml
3. ์จ๋ผ์ธ ๊ฒ์ฆ ๋๊ตฌ
โข WAVE: wave.webaim.org
โข AChecker: achecker.achecks.ca
โข HTML Validator: validator.w3.org
โข Color Contrast Checker: webaim.org/resources/contrastchecker
โข ํ๊ตญํ ์น ์ฝํ ์ธ ์ ๊ทผ์ฑ ์ง์นจ ๊ฒ์ฌ: accessibility.or.kr
๐จโ๐ฆฏ ์๋ ํ ์คํธ ๋ฐฉ๋ฒ
์๋ํ ๋๊ตฌ๋ ์ ์ฒด ์ ๊ทผ์ฑ ๋ฌธ์ ์ ์ฝ 30-40%๋ง ์ฐพ์๋ผ ์ ์์ด. ๋๋จธ์ง๋ ์๋์ผ๋ก ํ ์คํธํด์ผ ํด! ๐ช
โก ๋ง์ฐ์ค๋ฅผ ์ฌ์ฉํ์ง ์๊ณ Tab ํค๋ง์ผ๋ก ๋ชจ๋ ๊ธฐ๋ฅ ํ ์คํธ
โก ํฌ์ปค์ค ์์๊ฐ ๋ ผ๋ฆฌ์ ์ธ์ง ํ์ธ
โก ํฌ์ปค์ค ํ์๊ฐ ๋ช ํํ์ง ํ์ธ
โก ํค๋ณด๋ ํธ๋ฉ์ด ์๋์ง ํ์ธ
โก NVDA (Windows, ๋ฌด๋ฃ) ๋๋ JAWS (Windows, ์ ๋ฃ) ์ฌ์ฉ
โก VoiceOver (Mac/iOS, ๋ด์ฅ) ์ฌ์ฉ
โก TalkBack (Android, ๋ด์ฅ) ์ฌ์ฉ
โก ๋ชจ๋ ์ฝํ ์ธ ๊ฐ ์๋ฏธ ์๊ฒ ์ฝํ๋์ง ํ์ธ
โก ๋๋๋งํฌ์ ํค๋ฉ์ผ๋ก ์ฝ๊ฒ ํ์ ๊ฐ๋ฅํ์ง ํ์ธ
โก 200% ํ๋ ์ ๋ชจ๋ ์ฝํ ์ธ ์ ๊ทผ ๊ฐ๋ฅ
โก ๊ฐ๋ก ์คํฌ๋กค์ด ๋ฐ์ํ์ง ์์
โก ํ ์คํธ๊ฐ ์๋ฆฌ๊ฑฐ๋ ๊ฒน์น์ง ์์
โก ์๋งน ์๋ฎฌ๋ ์ดํฐ๋ก ํ์ธ
โก ๊ทธ๋ ์ด์ค์ผ์ผ๋ก ๋ณํํด์ ํ์ธ
โก ์์๋ง์ผ๋ก ์ ๋ณด๋ฅผ ์ ๋ฌํ์ง ์๋์ง ํ์ธ
โก ๋ชจ๋ ์ด๋ฏธ์ง์ ์ ์ ํ ๋์ฒด ํ ์คํธ
โก ๋งํฌ ํ ์คํธ๊ฐ ๋ช ํํจ ("์ฌ๊ธฐ ํด๋ฆญ" ๊ธ์ง)
โก ํค๋ฉ ๊ตฌ์กฐ๊ฐ ๋ ผ๋ฆฌ์
โก ์ธ์ด๊ฐ ๋ช ํํ๊ณ ์ดํดํ๊ธฐ ์ฌ์
๐ฏ ์คํฌ๋ฆฐ ๋ฆฌ๋ ์ฌ์ฉ๋ฒ ๊ฐ๋จ ๊ฐ์ด๋
| ์คํฌ๋ฆฐ ๋ฆฌ๋ | ํ๋ซํผ | ์ฃผ์ ๋จ์ถํค |
|---|---|---|
| NVDA | Windows (๋ฌด๋ฃ) |
Ctrl+Alt+N: ์์/์ข
๋ฃ Insert+Down: ์ฝ๊ธฐ ์์ H: ๋ค์ ํค๋ฉ์ผ๋ก K: ๋ค์ ๋งํฌ๋ก |
| JAWS | Windows (์ ๋ฃ) |
Insert+Down: ์ฝ๊ธฐ ์์ Insert+F7: ๋งํฌ ๋ชฉ๋ก Insert+F6: ํค๋ฉ ๋ชฉ๋ก T: ๋ค์ ํ๋ก |
| VoiceOver | Mac/iOS |
Cmd+F5: ์ผ๊ธฐ/๋๊ธฐ VO+A: ์ฝ๊ธฐ ์์ VO+U: ๋กํฐ ์ด๊ธฐ VO+Right: ๋ค์ ํญ๋ชฉ |
| TalkBack | Android |
๋ณผ๋ฅจ Up+Down: ์ผ๊ธฐ/๋๊ธฐ ์ค์์ดํ: ํ์ ๋๋ธ ํญ: ํ์ฑํ |
์ฒ์์๋ ์ด์ํ๊ฒ ์ง๋ง, ์ค์ ์ฌ์ฉ์๊ฐ ์ด๋ป๊ฒ ๊ฒฝํํ๋์ง ์ดํดํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ด์ผ. ์ต์ํ ์ฃผ์ ์ฌ์ฉ์ ํ๋ก์ฐ๋ ์คํฌ๋ฆฐ ๋ฆฌ๋๋ก ํ ์คํธํด๋ณด๋ ๊ฑธ ๊ฐ๋ ฅ ์ถ์ฒํด! ๐ง
๐ข ์ค๋ฌด์์์ ์น ์ ๊ทผ์ฑ ๊ตฌํ ์ ๋ต
์ด๋ก ๊ณผ ๊ธฐ์ ์ ๋ฐฐ์ ์ผ๋, ์ด์ ์ค์ ํ๋ก์ ํธ์์ ์ด๋ป๊ฒ ์ ์ฉํ ์ง ์์๋ณด์! ์ค๋ฌด ๊ฒฝํ์ ๋ฐํ์ผ๋ก ํ ์ค์ฉ์ ์ธ ํ๋ค์ ๊ณต์ ํ ๊ฒ. ๐ผ
๐ ํ๋ก์ ํธ ์ด๊ธฐ ๋จ๊ณ๋ถํฐ ์ ๊ทผ์ฑ ๊ณ ๋ คํ๊ธฐ
1. ๊ธฐํ ๋จ๊ณ
โข ์ ๊ทผ์ฑ ์๊ตฌ์ฌํญ ์ ์
๋ชฉํ ์ค์ ๋ ๋ฒจ ๊ฒฐ์ (๋ณดํต WCAG 2.1 Level AA)
๋ฒ์ ์๊ตฌ์ฌํญ ํ์ธ (ํ๊ตญ์ ๊ฒฝ์ฐ ์ฅ์ ์ธ์ฐจ๋ณ๊ธ์ง๋ฒ)
์์ฐ๊ณผ ์ผ์ ์ ์ ๊ทผ์ฑ ํ
์คํธ ์๊ฐ ํฌํจ
โข ์ฌ์ฉ์ ๋ฆฌ์์น
๋ค์ํ ์ฅ์ ๋ฅผ ๊ฐ์ง ์ฌ์ฉ์ ์ธํฐ๋ทฐ
๋ณด์กฐ ๊ธฐ์ ์ฌ์ฉ ํจํด ์กฐ์ฌ
ํ๋ฅด์๋์ ์ ๊ทผ์ฑ ๋์ฆ ํฌํจ
2. ๋์์ธ ๋จ๊ณ
โข ์์ ๋๋น ํ๋ณด
๋์์ธ ์์คํ
์ ์ ๊ทผ ๊ฐ๋ฅํ ์์ ํ๋ ํธ ์ ์
Figma/Sketch ํ๋ฌ๊ทธ์ธ์ผ๋ก ์ค์๊ฐ ๋๋น ์ฒดํฌ
โข ๋ช
ํํ ์ธํฐ๋์
๋์์ธ
์ถฉ๋ถํ ํฐ์น ํ๊ฒ ํฌ๊ธฐ (์ต์ 44x44px)
๋ช
ํํ ํฌ์ปค์ค ์ํ ๋์์ธ
์ผ๊ด๋ UI ํจํด ์ฌ์ฉ
โข ๋ฐ์ํ ๋์์ธ
๋ค์ํ ํ๋ฉด ํฌ๊ธฐ์ ํ๋ ์์ค ๊ณ ๋ ค
ํ
์คํธ ํฌ๊ธฐ ์กฐ์ ๊ฐ๋ฅํ๋๋ก ์ค๊ณ
3. ๊ฐ๋ฐ ๋จ๊ณ
โข ์๋งจํฑ HTML ์ฐ์
์๋ฏธ ์๋ HTML ์์ ์ฌ์ฉ
์ ์ ํ ํค๋ฉ ๊ตฌ์กฐ ์ ์ง
ํผ ์์์ ๋ ์ด๋ธ ์ฐ๊ฒฐ
โข ์ ์ง์ ํฅ์(Progressive Enhancement)
๊ธฐ๋ณธ HTML๋ก ์๋ํ๋ ๊ธฐ๋ฅ ๊ตฌํ
CSS์ JavaScript๋ก ๊ฒฝํ ํฅ์
JavaScript ๋นํ์ฑํ ์์๋ ๊ธฐ๋ณธ ๊ธฐ๋ฅ ์๋
โข ์๋ํ ํ
์คํธ ํตํฉ
CI/CD ํ์ดํ๋ผ์ธ์ ์ ๊ทผ์ฑ ํ
์คํธ ํฌํจ
PR๋ง๋ค ์๋ ๊ฒ์ฌ ์คํ
๋ฆฐํธ ๊ท์น์ ์ ๊ทผ์ฑ ์ฒดํฌ ์ถ๊ฐ
๐ ์ง์์ ์ธ ๊ฐ์ ํ๋ก์ธ์ค
// package.json์ ์ ๊ทผ์ฑ ํ
์คํธ ์คํฌ๋ฆฝํธ ์ถ๊ฐ
{
"scripts": {
"test:a11y": "pa11y-ci",
"lint:a11y": "eslint --plugin jsx-a11y",
"audit": "lighthouse --only-categories=accessibility"
},
"devDependencies": {
"pa11y-ci": "^3.0.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"lighthouse": "^10.0.0"
}
}
// .pa11yci ์ค์ ํ์ผ
{
"defaults": {
"standard": "WCAG2AA",
"timeout": 10000,
"wait": 1000
},
"urls": [
"http://localhost:3000",
"http://localhost:3000/about",
"http://localhost:3000/contact"
]
}
๐ฅ ํ ํ์ ๊ณผ ๊ต์ก
1. ์ ๊ธฐ์ ์ธ ๊ต์ก ์ธ์
โข ์ 1ํ ์ ๊ทผ์ฑ ์ํฌ์ต ๊ฐ์ต
โข ์ค์ ์ฌ์ฉ์ ์ด์ฒญ ์ธ์
โข ์ต์ ๊ฐ์ด๋๋ผ์ธ ์ ๋ฐ์ดํธ ๊ณต์
2. ์ ๊ทผ์ฑ ์ฑํผ์ธ ์ง์
โข ๊ฐ ํ์ ์ ๊ทผ์ฑ ์ ๋ฌธ๊ฐ ๋ฐฐ์น
โข ์ฝ๋ ๋ฆฌ๋ทฐ ์ ์ ๊ทผ์ฑ ์ฒดํฌ
โข ์ง๋ฌธ๊ณผ ์ด์ ํด๊ฒฐ ์ง์
3. ๋ฌธ์ํ์ ๊ฐ์ด๋๋ผ์ธ
โข ์ฌ๋ด ์ ๊ทผ์ฑ ๊ฐ์ด๋ ์์ฑ
โข ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ๊ทผ์ฑ ์์ ํฌํจ
โข ์ฒดํฌ๋ฆฌ์คํธ์ ํ ํ๋ฆฟ ์ ๊ณต
๐ ์ ๊ทผ์ฑ ์ฑ์๋ ๋ชจ๋ธ
| ๋ ๋ฒจ | ์ค๋ช | ํน์ง |
|---|---|---|
| Level 1 ์ด๊ธฐ |
์ ๊ทผ์ฑ์ ๋ํ ์ธ์ ๋ถ์กฑ |
โข ์ ๊ทผ์ฑ ๊ณ ๋ ค ์์ โข ์๋ํ ๋๊ตฌ ๋ฏธ์ฌ์ฉ โข ํ ์คํธ ์์ |
| Level 2 ๋ฐ์์ |
๋ฌธ์ ๋ฐ์ ์ ๋์ |
โข ๋ถ๋ง ์ ์ ํ ์์ โข ๊ธฐ๋ณธ์ ์ธ ์๋ํ ํ ์คํธ โข ์ผ๋ถ ๊ฐ๋ฐ์๋ง ์ธ์ |
| Level 3 ์ฒด๊ณ์ |
ํ๋ก์ธ์ค์ ํตํฉ |
โข ๊ฐ๋ฐ ํ๋ก์ธ์ค์ ํฌํจ โข ์ ๊ธฐ์ ์ธ ํ ์คํธ โข ํ ์ ์ฒด ๊ต์ก |
| Level 4 ์ ๋์ |
์กฐ์ง ๋ฌธํ๋ก ์ ์ฐฉ |
โข ๋์์ธ๋ถํฐ ์ ๊ทผ์ฑ ๊ณ ๋ ค โข ์๋ํ๋ CI/CD ํตํฉ โข ์ง์์ ์ธ ๊ฐ์ |
| Level 5 ํ์ ์ |
์ ๊ณ ๋ฆฌ๋ |
โข ์๋ก์ด ํ์ค ์ ์ โข ์ปค๋ฎค๋ํฐ ๊ธฐ์ฌ โข ์์ ํ ํฌ์ฉ์ ๋์์ธ |
๐ ํ๊ตญ์ ์น ์ ๊ทผ์ฑ ๋ฒ๊ท์ ์ธ์ฆ
ํ๊ตญ์์ ์น ๊ฐ๋ฐ์ ํ๋ค๋ฉด ๊ผญ ์์์ผ ํ ๋ฒ์ ์๊ตฌ์ฌํญ๊ณผ ์ธ์ฆ ์ ๋์ ๋ํด ์์๋ณด์! ๐ฐ๐ท
โ๏ธ ๊ด๋ จ ๋ฒ๊ท
1. ์ฅ์ ์ธ์ฐจ๋ณ๊ธ์ง ๋ฐ ๊ถ๋ฆฌ๊ตฌ์ ๋ฑ์ ๊ดํ ๋ฒ๋ฅ
์ 21์กฐ(์ ๋ณด์ ๊ทผ์์์ ์ฐจ๋ณ๊ธ์ง)
โข ์ฅ์ ์ธ์ด ์ ์์ ๋ณด์ ๋น์ ์์ ๋ณด๋ฅผ ์ด์ฉํ๊ณ ๊ทธ์ ์ ๊ทผํจ์ ์์ด์ ์ฅ์ ๋ฅผ ์ด์ ๋ก ์ ํยท๋ฐฐ์ ยท๋ถ๋ฆฌยท๊ฑฐ๋ถ ๋ฑ ์ฐจ๋ณํด์๋ ์ ๋จ
โข ์น์ฌ์ดํธ ๋ฐ ๋ชจ๋ฐ์ผ ์ ํ๋ฆฌ์ผ์ด์
๋ฑ์ ํตํด ์ ๋ณด๋ฅผ ์ ๊ณตํ ๋ ์ ๊ทผ์ฑ์ด ๋ณด์ฅ๋์ด์ผ ํจ
์ ์ฉ ๋์ (๋จ๊ณ์ ์ ์ฉ)
โข 2009๋
: ๊ณต๊ณต๊ธฐ๊ด
โข 2013๋
: ๋ฒ์ธ (์์๊ทผ๋ก์ 30์ธ ์ด์)
โข 2015๋
: ๋ฒ์ธ (์์๊ทผ๋ก์ 30์ธ ๋ฏธ๋ง)
์๋ฐ ์ ์ ์ฌ
โข ์์ ๋ช
๋ น ๋ถ์ดํ ์ 3์ฒ๋ง์ ์ดํ ๊ณผํ๋ฃ
โข ์ํด๋ฐฐ์ ์ฒญ๊ตฌ ๊ฐ๋ฅ
2. ๊ตญ๊ฐ์ ๋ณดํ ๊ธฐ๋ณธ๋ฒ
์ 32์กฐ(์ฅ์ ์ธยท๊ณ ๋ น์ ๋ฑ์ ์ ๋ณด ์ ๊ทผ ๋ฐ ์ด์ฉ ๋ณด์ฅ)
โข ๊ตญ๊ฐ๊ธฐ๊ด ๋ฑ์ ์ ๋ณดํต์ ๋ง์ ํตํด ์ ๋ณด๋ ์๋น์ค๋ฅผ ์ ๊ณตํ ๋ ์ฅ์ ์ธยท๊ณ ๋ น์ ๋ฑ์ด ์ฝ๊ฒ ์ ๊ทผํ๊ณ ์ด์ฉํ ์ ์๋๋ก ํด์ผ ํจ
โข ํ๊ตญํ ์น ์ฝํ
์ธ ์ ๊ทผ์ฑ ์ง์นจ(KWCAG) ์ค์ ์๋ฌด
๐ ํ๊ตญํ ์น ์ฝํ ์ธ ์ ๊ทผ์ฑ ์ง์นจ (KWCAG)
KWCAG๋ WCAG๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๊ตญ ์ค์ ์ ๋ง๊ฒ ์ ์ ๋ ์ง์นจ์ด์ผ. ํ์ฌ KWCAG 2.2๊ฐ ์ต์ ๋ฒ์ ์ด์ผ. ๐
KWCAG 2.2์ 4๊ฐ์ง ์์น๊ณผ 13๊ฐ ์ง์นจ
1. ์ธ์์ ์ฉ์ด์ฑ (Perceivable)โข 1.1 ๋์ฒด ํ ์คํธ
โข 1.2 ๋ฉํฐ๋ฏธ๋์ด ๋์ฒด ์๋จ
โข 1.3 ๋ช ๋ฃ์ฑ
2. ์ด์ฉ์ ์ฉ์ด์ฑ (Operable)
โข 2.1 ์ ๋ ฅ์ฅ์น ์ ๊ทผ์ฑ
โข 2.2 ์ถฉ๋ถํ ์๊ฐ ์ ๊ณต
โข 2.3 ๊ด๊ณผ๋ฏผ์ฑ ๋ฐ์ ์๋ฐฉ
โข 2.4 ์ฌ์ด ๋ด๋น๊ฒ์ด์
3. ์ดํด์ ์ฉ์ด์ฑ (Understandable)
โข 3.1 ๊ฐ๋ ์ฑ
โข 3.2 ์์ธก ๊ฐ๋ฅ์ฑ
โข 3.3 ์ฝํ ์ธ ์ ๋ ผ๋ฆฌ์ฑ
โข 3.4 ์ ๋ ฅ ๋์
4. ๊ฒฌ๊ณ ์ฑ (Robust)
โข 4.1 ๋ฌธ๋ฒ ์ค์
โข 4.2 ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ทผ์ฑ
๐ ์น ์ ๊ทผ์ฑ ํ์ง์ธ์ฆ ๋งํฌ
ํ๊ตญ์น์ ๊ทผ์ฑ์ธ์ฆํ๊ฐ์์์ ๋ฐ๊ธํ๋ ์ธ์ฆ ๋งํฌ์ผ. ์น์ฌ์ดํธ๊ฐ KWCAG๋ฅผ ์ค์ํ๋ค๋ ๊ฒ์ ๊ณต์์ ์ผ๋ก ์ธ์ ๋ฐ๋ ๊ฑฐ์ง! ๐๏ธ
์ธ์ฆ ์ ์ฐจ
1๋จ๊ณ: ์ ์ฒญ
โข ์น ์ ๊ทผ์ฑ ํ์ง์ธ์ฆ ์ ์ฒญ์ ์ ์ถ
โข ๋์ ์น์ฌ์ดํธ URL ์ ๊ณต
2๋จ๊ณ: ์์ฒด ์ ๊ฒ
โข ์๋ํ ๋๊ตฌ๋ก ์ฌ์ ์ ๊ฒ
โข ์ฒดํฌ๋ฆฌ์คํธ ๊ธฐ๋ฐ ์๊ฐ ์ง๋จ
3๋จ๊ณ: ์ ๋ฌธ๊ฐ ์ฌ์ฌ
โข ์ ๊ทผ์ฑ ์ ๋ฌธ๊ฐ์ ์๋ ํ๊ฐ
โข ๋ณด์กฐ ๊ธฐ์ ์ ์ด์ฉํ ์ค์ฌ์ฉ ํ
์คํธ
โข ์์ธํ ํ๊ฐ ๋ณด๊ณ ์ ์์ฑ
4๋จ๊ณ: ์ธ์ฆ ๋ฐ๊ธ
โข ๊ธฐ์ค ์ถฉ์กฑ ์ ์ธ์ฆ ๋งํฌ ๋ฐ๊ธ
โข ์ ํจ๊ธฐ๊ฐ: 2๋
โข ์น์ฌ์ดํธ์ ์ธ์ฆ ๋งํฌ ๊ฒ์ ๊ฐ๋ฅ
โข ์ธ์ฆ ์ ์ฒญ ์ ์ ์ถฉ๋ถํ ์ฌ์ ์ ๊ฒ ํ์
โข ์ฃผ์ ํ์ด์ง๋ฟ๋ง ์๋๋ผ ์ ์ฒด ์ฌ์ดํธ ์ ๊ฒ
โข ๊ฐ๋ฐํ๊ณผ ๋์์ธํ์ ํ์ ํ์
โข ์ธ์ฆ ํ์๋ ์ง์์ ์ธ ๊ด๋ฆฌ ์ค์ (๊ฐฑ์ ๋๋น)
โข ๋น์ฉ: ์ฝ 200๋ง์~500๋ง์ (์ฌ์ดํธ ๊ท๋ชจ์ ๋ฐ๋ผ ๋ค๋ฆ)
๐ก ์ค์ ์ฌ๋ก๋ก ๋ฐฐ์ฐ๋ ์น ์ ๊ทผ์ฑ
์ด๋ก ๋ง์ผ๋ก๋ ๋ถ์กฑํ์ง! ์ค์ ์น์ฌ์ดํธ๋ค์ ์ข์ ์์ ๋์ ์๋ฅผ ํตํด ๋ฐฐ์๋ณด์. ๐
โ ์ข์ ์ฌ๋ก๋ค
1. BBC (์๊ตญ ๊ณต์๋ฐฉ์ก)
์ฐ์ํ ์ :
โข ๋ชจ๋ ๋์์์ ์๋ง๊ณผ ์์ฑ ์ค๋ช
์ ๊ณต
โข ๋ช
ํํ ํค๋ฉ ๊ตฌ์กฐ์ ๋๋๋งํฌ
โข ํค๋ณด๋ ๋ค๋น๊ฒ์ด์
์๋ฒฝ ์ง์
โข ๋ค์ํ ํ
์คํธ ํฌ๊ธฐ ์ต์
โข ๊ณ ๋๋น ๋ชจ๋ ์ ๊ณต
๋ฐฐ์ธ ์ :
์ฌ์ฉ์ ์ค์ ์ ์ ์ฅํ๊ณ ๋ชจ๋ ํ์ด์ง์ ์ผ๊ด๋๊ฒ ์ ์ฉํ๋ ์์คํ
์ ๊ตฌ์ถํ์ด. ์ด๊ฑด ์ฌ์ฉ์ ๊ฒฝํ์ ํฌ๊ฒ ํฅ์์ํค์ง! ๐ฏ
2. GOV.UK (์๊ตญ ์ ๋ถ ์น์ฌ์ดํธ)
์ฐ์ํ ์ :
โข ๊ทน๋๋ก ๋จ์ํ๊ณ ๋ช
ํํ ๋์์ธ
โข ํ์ดํ ์ธ์ด ์ฌ์ฉ (Plain English)
โข ๋ชจ๋ฐ์ผ ์ฐ์ ๋ฐ์ํ ๋์์ธ
โข ๋น ๋ฅธ ๋ก๋ฉ ์๋
โข ์คํ์์ค ๋์์ธ ์์คํ
์ ๊ณต
๋ฐฐ์ธ ์ :
"์ฌ์ฉ์๊ฐ ํ์๋ก ํ๋ ๊ฒ๋ง ์ ๊ณตํ๋ค"๋ ์ฒ ํ์ผ๋ก, ๋ถํ์ํ ์์๋ฅผ ๋ชจ๋ ์ ๊ฑฐํ์ด. ๊ฒฐ๊ณผ์ ์ผ๋ก ์ ๊ทผ์ฑ๊ณผ ์ฌ์ฉ์ฑ์ด ๋ชจ๋ ํฅ์๋์์ง! ๐จ
3. ๋ค์ด๋ฒ (ํ๊ตญ)
์ฐ์ํ ์ :
โข ์คํฌ๋ฆฐ ๋ฆฌ๋ ์ฌ์ฉ์๋ฅผ ์ํ ๋ณ๋ ๋ค๋น๊ฒ์ด์
โข ์ฃผ์ ์๋น์ค์ ํค๋ณด๋ ๋จ์ถํค ์ ๊ณต
โข ์ด๋ฏธ์ง ๊ฒ์ ๊ฒฐ๊ณผ์ ์์ธํ ๋์ฒด ํ
์คํธ
โข ์์ฑ ๊ฒ์ ๊ธฐ๋ฅ
๋ฐฐ์ธ ์ :
๋ณต์กํ ํฌํธ ์ฌ์ดํธ์์๋ ๋ถ๊ตฌํ๊ณ ์ ๊ทผ์ฑ์ ์ ์งํ๊ธฐ ์ํด ์ง์์ ์ผ๋ก ๊ฐ์ ํ๊ณ ์์ด. ํนํ ๋ชจ๋ฐ์ผ ์ ๊ทผ์ฑ์ ๋ง์ ๋
ธ๋ ฅ์ ๊ธฐ์ธ์ด๊ณ ์์ง! ๐ฑ
โ ๊ฐ์ ์ด ํ์ํ ์ฌ๋ก๋ค
ํํ ์ ๊ทผ์ฑ ๋ฌธ์ ๋ค
1. ์ด๋ฏธ์ง ์บก์ฐจ(CAPTCHA)
๋ฌธ์ ์ : ์๊ฐ์ฅ์ ์ธ์ ์ด๋ฏธ์ง ๊ธฐ๋ฐ ์บก์ฐจ๋ฅผ ์ ํ ์ฌ์ฉํ ์ ์์ด.
ํด๊ฒฐ์ฑ
: ์์ฑ ์บก์ฐจ ๋์ ์ ๊ณต, ๋๋ reCAPTCHA v3 ๊ฐ์ ๋ณด์ด์ง ์๋ ์บก์ฐจ ์ฌ์ฉ
<!-- โ ๋์ ์ -->
<img src="captcha.jpg" alt="๋ณด์ ๋ฌธ์">
<!-- โ
์ข์ ์ -->
<div class="captcha-container">
<img src="captcha.jpg" alt="๋ณด์ ๋ฌธ์ ์ด๋ฏธ์ง">
<button type="button" onclick="playCaptchaAudio()">
๐ ์์ฑ์ผ๋ก ๋ฃ๊ธฐ
</button>
<button type="button" onclick="refreshCaptcha()">
๐ ์๋ก๊ณ ์นจ
</button>
</div>
2. ์๋ ์ฌ์ ๋์์
๋ฌธ์ ์ : ์คํฌ๋ฆฐ ๋ฆฌ๋ ์ฌ์ฉ์๊ฐ ์ฝํ
์ธ ๋ฅผ ๋ฃ๋ ๋ฐ ๋ฐฉํด๊ฐ ๋๊ณ , ๋ฐ์์ ์ ๋ฐํ ์ ์์ด.
ํด๊ฒฐ์ฑ
: ์๋ ์ฌ์ ๊ธ์ง, ๋๋ ์์๊ฑฐ ์ํ๋ก ์ฌ์ํ๊ณ ๋ช
ํํ ์ปจํธ๋กค ์ ๊ณต
<!-- โ ๋์ ์ -->
<video autoplay>
<source src="video.mp4">
</video>
<!-- โ
์ข์ ์ -->
<video controls preload="metadata">
<source src="video.mp4">
<track kind="captions" src="captions.vtt">
</video>
3. ๋ชจ๋ฌ ๋ค์ด์ผ๋ก๊ทธ์ ํฌ์ปค์ค ํธ๋ฉ ๋๋ฝ
๋ฌธ์ ์ : ๋ชจ๋ฌ์ด ์ด๋ ธ์ ๋ ํฌ์ปค์ค๊ฐ ๋ชจ๋ฌ ๋ฐ์ผ๋ก ๋๊ฐ๋ฉด ์ฌ์ฉ์๊ฐ ํผ๋์ค๋ฌ์ํด.
ํด๊ฒฐ์ฑ
: ํฌ์ปค์ค๋ฅผ ๋ชจ๋ฌ ๋ด๋ถ์ ๊ฐ๋๊ณ , ESC ํค๋ก ๋ซ์ ์ ์๊ฒ ํด
// ํฌ์ปค์ค ํธ๋ฉ ๊ตฌํ
function trapFocus(element) {
const focusableElements = element.querySelectorAll(
'a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])'
);
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];
element.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey) {
if (document.activeElement === firstFocusable) {
lastFocusable.focus();
e.preventDefault();
}
} else {
if (document.activeElement === lastFocusable) {
firstFocusable.focus();
e.preventDefault();
}
}
}
if (e.key === 'Escape') {
closeModal();
}
});
firstFocusable.focus();
}
๐ ์ต์ ํธ๋ ๋์ ๋ฏธ๋์ ์น ์ ๊ทผ์ฑ
์น ์ ๊ทผ์ฑ์ ๊ณ์ ์งํํ๊ณ ์์ด! ์ต์ ํธ๋ ๋์ ์์ผ๋ก์ ๋ฐฉํฅ์ ์์๋ณด์. ๐ฎ
๐ค AI์ ๋จธ์ ๋ฌ๋์ ํ์ฉ
1. ์๋ ๋์ฒด ํ ์คํธ ์์ฑ
AI๊ฐ ์ด๋ฏธ์ง๋ฅผ ๋ถ์ํด์ ์๋์ผ๋ก ๋์ฒด ํ
์คํธ๋ฅผ ์์ฑํด์ค. Microsoft์ Seeing AI, Google์ Cloud Vision API ๊ฐ์ ์๋น์ค๋ค์ด ์์ด.
์ฅ์ :
โข ๋๋์ ์ด๋ฏธ์ง๋ฅผ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌ
โข ์ผ๊ด๋ ํ์ง์ ์ค๋ช
์ ๊ณต
โข ๊ฐ๋ฐ์์ ๋ถ๋ด ๊ฐ์
ํ๊ณ:
โข ๋งฅ๋ฝ์ ์์ ํ ์ดํดํ์ง ๋ชปํจ
โข ์ค์ํ ์ธ๋ถ์ฌํญ์ ๋์น ์ ์์
โข ์ฌ์ ํ ์ฌ๋์ ๊ฒํ ๊ฐ ํ์
2. ์์ฑ ์ธํฐํ์ด์ค์ ๋ํํ AI
Alexa, Siri, Google Assistant ๊ฐ์ ์์ฑ ๋น์๊ฐ ์น ์ ๊ทผ์ฑ์ ์๋ก์ด ํจ๋ฌ๋ค์์ ๋ง๋ค๊ณ ์์ด.
์น ๊ฐ๋ฐ์๊ฐ ๊ณ ๋ คํด์ผ ํ ์ :
โข ์์ฑ ๊ฒ์ ์ต์ ํ (Voice Search Optimization)
โข ์์ฐ์ด ์ฒ๋ฆฌ๋ฅผ ๊ณ ๋ คํ ์ฝํ
์ธ ๊ตฌ์กฐ
โข ์์ฑ ๋ช
๋ น์ผ๋ก ์กฐ์ ๊ฐ๋ฅํ ์ธํฐํ์ด์ค
โข Schema.org ๋งํฌ์
์ผ๋ก ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ ์ ๊ณต
๐ฑ ๋ชจ๋ฐ์ผ๊ณผ ํฐ์น ์ธํฐํ์ด์ค
๋ชจ๋ฐ์ผ ์ ๊ทผ์ฑ ์ฒดํฌํฌ์ธํธ
โข ์ถฉ๋ถํ ํฐ์น ํ๊ฒ ํฌ๊ธฐ
์ต์ 44x44 CSS ํฝ์
(iOS), 48x48dp (Android)
โข ์ ์ค์ฒ ๋์ ์ ๊ณต
์ค์์ดํ, ํ์น ๊ฐ์ ๋ณต์กํ ์ ์ค์ฒ์ ๋ํ ๋์ ์ ๊ณต
โข ํ๋ฉด ๋ฐฉํฅ ์ง์
์ธ๋ก/๊ฐ๋ก ๋ชจ๋ ๋ชจ๋ ์ง์
โข ๋ชจ๋ฐ์ผ ์คํฌ๋ฆฐ ๋ฆฌ๋ ์ต์ ํ
VoiceOver(iOS), TalkBack(Android) ํ
์คํธ ํ์
/* ํฐ์น ํ๊ฒ ํฌ๊ธฐ ๋ณด์ฅ */
button,
a,
input[type="checkbox"],
input[type="radio"] {
min-width: 44px;
min-height: 44px;
/* ๋๋ padding์ผ๋ก ํฌ๊ธฐ ํ๋ณด */
}
/* ํฐ์น ์์ญ ํ์ฅ (์๊ฐ์ ํฌ๊ธฐ๋ ์ ์ง) */
.small-icon {
position: relative;
}
.small-icon::after {
content: '';
position: absolute;
top: -12px;
left: -12px;
right: -12px;
bottom: -12px;
}
/* ์ ์ค์ฒ ๋์ ์ ๊ณต */
@media (hover: none) and (pointer: coarse) {
/* ํฐ์น ๋๋ฐ์ด์ค ์ ์ฉ ์คํ์ผ */
.swipeable-item {
/* ์ค์์ดํ ๋์ ๋ฒํผ ํ์ */
}
}
๐ WCAG 3.0์ ๋ณํ
WCAG 3.0 (W3C Accessibility Guidelines, ์ด์ ๋ช ์นญ: Silver)์ด ๊ฐ๋ฐ ์ค์ด์ผ. ์ฃผ์ ๋ณํ๋ฅผ ์ดํด๋ณด์! ๐
| ํญ๋ชฉ | WCAG 2.x | WCAG 3.0 |
|---|---|---|
| ์ค์ ๋ ๋ฒจ | A, AA, AAA (3๋จ๊ณ) | Bronze, Silver, Gold (์ ์ ๊ธฐ๋ฐ) |
| ํ๊ฐ ๋ฐฉ์ | Pass/Fail (ํต๊ณผ/์คํจ) | ์ ์ ์์คํ (0-100) |
| ์ ์ฉ ๋ฒ์ | ์น ์ฝํ ์ธ ์ค์ฌ | ์น, ๋ชจ๋ฐ์ผ, IoT, AR/VR ๋ฑ ๋ชจ๋ ๋์งํธ ์ ํ |
| ํ ์คํธ | ๊ธฐ์ ์ ํ ์คํธ ์ค์ฌ | ์ฌ์ฉ์ ๊ฒฝํ ํ ์คํธ ํฌํจ |
| ์ธ์ด | ๊ธฐ์ ์ ์ฉ์ด | ํ์ดํ ์ธ์ด (Plain Language) |
1. ๋ ํฌ๊ด์ ์ธ ๋ฒ์
์น๋ฟ๋ง ์๋๋ผ ๋ชจ๋ฐ์ผ ์ฑ, ๊ฐ์ํ์ค, ์ฆ๊ฐํ์ค, IoT ๊ธฐ๊ธฐ๊น์ง ํฌํจํด.
2. ์ฌ์ฉ์ ์ค์ฌ ํ๊ฐ
์ค์ ์ฅ์ ์ธ ์ฌ์ฉ์์ ๊ฒฝํ์ ๋ ์ค์ํ๊ฒ ๊ณ ๋ คํด.
3. ์ ์ฐํ ์ค์ ๋ชจ๋ธ
๋ชจ๋ ๊ธฐ์ค์ 100% ์ถฉ์กฑํ์ง ๋ชปํด๋ ์ ์ฒด์ ์ธ ์ ๊ทผ์ฑ ์์ค์ ํ๊ฐํ ์ ์์ด.
4. ๋ ๋ช ํํ ๊ฐ์ด๋
๊ฐ๋ฐ์, ๋์์ด๋, ์ฝํ ์ธ ์ ์์ ๋ฑ ์ญํ ๋ณ๋ก ๋ง์ถคํ๋ ๊ฐ์ด๋๋ฅผ ์ ๊ณตํด.
๐จ ํฌ์ฉ์ ๋์์ธ(Inclusive Design)
์น ์ ๊ทผ์ฑ์ ๋์ด์ ํฌ์ฉ์ ๋์์ธ์ด ์ค์ํด์ง๊ณ ์์ด. ์ด๊ฑด ๋จ์ํ ์ฅ์ ์ธ๋ง์ ์ํ ๊ฒ ์๋๋ผ, ๋ชจ๋ ์ฌ๋์ ๋ค์์ฑ์ ์กด์คํ๋ ๋์์ธ์ด์ผ. ๐
ํฌ์ฉ์ ๋์์ธ์ ์์น
1. ๋ค์์ฑ ์ธ์ โข ์๊ตฌ์ , ์ผ์์ , ์ํฉ์ ์ฅ์ ๋ชจ๋ ๊ณ ๋ ค
โข ๋ฌธํ์ , ์ธ์ด์ ๋ค์์ฑ ์กด์ค
โข ๋ค์ํ ๊ธฐ๊ธฐ์ ํ๊ฒฝ ์ง์
2. ์ ์ฐ์ฑ ์ ๊ณต
โข ์ฌ์ฉ์๊ฐ ์์ ์๊ฒ ๋ง๊ฒ ์ปค์คํฐ๋ง์ด์ง ๊ฐ๋ฅ
โข ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ์ ๋ชฉํ ๋ฌ์ฑ ๊ฐ๋ฅ
โข ๊ฐ์ธ์ ์ ํธ๋ ์กด์ค
3. ๋จ์ํ๊ณ ์ง๊ด์
โข ๋ถํ์ํ ๋ณต์ก์ฑ ์ ๊ฑฐ
โข ๋ช ํํ ์ ๋ณด ๊ตฌ์กฐ
โข ์ผ๊ด๋ ํจํด ์ฌ์ฉ
4. ์ธ์ง ๋ถํ ์ต์ํ
โข ํ ๋ฒ์ ํ๋์ ์์ ์ ์ง์ค
โข ๋ช ํํ ํผ๋๋ฐฑ ์ ๊ณต
โข ์ค๋ฅ ๋ฐฉ์ง์ ์ฌ์ด ๋ณต๊ตฌ
๐ ํ์ต ๋ฆฌ์์ค์ ์ปค๋ฎค๋ํฐ
์น ์ ๊ทผ์ฑ์ ๊ณ์ ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด? ์ ์ฉํ ๋ฆฌ์์ค๋ค์ ์๊ฐํ ๊ฒ! ๐
๐ ๊ณต์ ๋ฌธ์์ ๊ฐ์ด๋
โข WCAG 2.1: w3.org/WAI/WCAG21/quickref
โข WAI-ARIA: w3.org/WAI/ARIA
โข WCAG 3.0 Draft: w3.org/TR/wcag-3.0
ํ๊ตญ ํ์ค
โข KWCAG 2.2: www.wah.or.kr
โข ํ๊ตญ์น์ ๊ทผ์ฑ์ธ์ฆํ๊ฐ์: www.wa.or.kr
โข ์น์ ๊ทผ์ฑ์ฐ๊ตฌ์: www.accessibility.or.kr
๐ ๏ธ ์ ์ฉํ ๋๊ตฌ ๋ชจ์
| ์นดํ ๊ณ ๋ฆฌ | ๋๊ตฌ | ์ฉ๋ |
|---|---|---|
| ์๋ํ ํ ์คํธ |
axe DevTools WAVE Lighthouse Pa11y |
์๋ ์ ๊ทผ์ฑ ๊ฒ์ฌ ์๊ฐ์ ํผ๋๋ฐฑ ์ข ํฉ ๊ฐ์ฌ CI/CD ํตํฉ |
| ์์ ๋๊ตฌ |
WebAIM Contrast Checker Colorblind Web Page Filter Stark |
๋๋น ํ์ธ ์๋งน ์๋ฎฌ๋ ์ด์ ๋์์ธ ๋๊ตฌ ํตํฉ |
| ์คํฌ๋ฆฐ ๋ฆฌ๋ |
NVDA JAWS VoiceOver TalkBack |
Windows (๋ฌด๋ฃ) Windows (์ ๋ฃ) Mac/iOS Android |
| ๊ฐ๋ฐ ๋๊ตฌ |
eslint-plugin-jsx-a11y react-axe cypress-axe |
๋ฆฐํ
React ํ ์คํธ E2E ํ ์คํธ |
๐ฅ ์ปค๋ฎค๋ํฐ์ ๋คํธ์ํฌ
โข WebAIM Discussion List: ํ๋ฐํ ์ด๋ฉ์ผ ๋ฆฌ์คํธ
โข A11y Slack: web-a11y.slack.com
โข Reddit r/accessibility: ๋ค์ํ ํ ๋ก
โข Twitter #a11y: ์ต์ ๋ด์ค์ ํ
๐ฐ๐ท ํ๊ตญ ์ปค๋ฎค๋ํฐ
โข ํ๊ตญ์น์ ๊ทผ์ฑ๊ทธ๋ฃน: ์ ๊ธฐ ์ธ๋ฏธ๋์ ์ํฌ์ต
โข NAVER Accessibility: ๋ค์ด๋ฒ์ ์ ๊ทผ์ฑ ๋ธ๋ก๊ทธ
โข Kakao Accessibility: ์นด์นด์ค์ ์ ๊ทผ์ฑ ๊ฐ์ด๋
๐ ์ถ์ฒ ๋์
1. "Inclusive Design Patterns" by Heydon Pickering
์ค์ฉ์ ์ธ ์ ๊ทผ์ฑ ํจํด๊ณผ ์ฝ๋ ์์
2. "A Web for Everyone" by Sarah Horton & Whitney Quesenbery
ํฌ์ฉ์ ๋์์ธ์ ๊ธฐ์ด
3. "Accessibility for Everyone" by Laura Kalbag
์ด๋ณด์๋ฅผ ์ํ ์น์ ํ ๊ฐ์ด๋
4. "Form Design Patterns" by Adam Silver
์ ๊ทผ ๊ฐ๋ฅํ ํผ ๋์์ธ์ ๋ชจ๋ ๊ฒ
๐ฅ ์จ๋ผ์ธ ๊ฐ์ข
โข Web Accessibility by Google (Udacity): ๋ฌด๋ฃ, ์์ด
โข Introduction to Web Accessibility (W3Cx): edX, ๋ฌด๋ฃ
โข Digital Accessibility (University of Southampton): FutureLearn
์ ๋ฃ ๊ฐ์ข
โข Accessibility in JavaScript Applications (Frontend Masters)
โข Web Accessibility (Pluralsight)
โข Practical Accessibility (Egghead.io)
๐ผ ์ฌ๋ฅ๋ท์์ ์น ์ ๊ทผ์ฑ ์ ๋ฌธ๊ฐ ์ฐพ๊ธฐ
์น ์ ๊ทผ์ฑ ๊ตฌํ์ด ์ด๋ ต๊ฒ ๋๊ปด์ง๋ค๋ฉด? ์ฌ๋ฅ๋ท์์ ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ์ ์ ์์ด! ๐ค
์ฌ๋ฅ๋ท(jaenung.net)์ ๋ค์ํ ๋ถ์ผ์ ์ ๋ฌธ๊ฐ๋ค์ด ๋ชจ์ฌ์๋ ์ฌ๋ฅ ๊ณต์ ํ๋ซํผ์ด์ผ. ์น ์ ๊ทผ์ฑ ์ปจ์คํ
, ์ฝ๋ ๋ฆฌ๋ทฐ, ๊ต์ก ๋ฑ ํ์ํ ์๋น์ค๋ฅผ ์ฐพ์ ์ ์์ง.
์ฌ๋ฅ๋ท์์ ์ฐพ์ ์ ์๋ ์๋น์ค:
โข ์น ์ ๊ทผ์ฑ ์ง๋จ ๋ฐ ๊ฐ์ ์ปจ์คํ
โข WCAG/KWCAG ์ค์ ์ฝ๋ ๋ฆฌ๋ทฐ
โข ์ ๊ทผ์ฑ ํ
์คํธ ๋ฐ ์ธ์ฆ ์ค๋น ์ง์
โข ํ ๊ต์ก ๋ฐ ์ํฌ์ต
โข ์ ๊ทผ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ ๊ฐ๋ฐ
ํผ์ ๊ณ ๋ฏผํ์ง ๋ง๊ณ , ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ์ ๋ ๋น ๋ฅด๊ณ ์ ํํ๊ฒ ์ ๊ทผ์ฑ์ ๊ตฌํํด๋ณด์! ๐ช
๐ฏ ๋ง๋ฌด๋ฆฌ: ์น ์ ๊ทผ์ฑ์ ์ ํ์ด ์๋ ํ์!
์, ์ฌ๊ธฐ๊น์ง ์น ์ ๊ทผ์ฑ๊ณผ WCAG ๊ฐ์ด๋๋ผ์ธ์ ๋ํด ๊น์ด ์๊ฒ ์์๋ดค์ด! ๊ธด ์ฌ์ ์ด์์ง? ๐
ํต์ฌ์ ๋ค์ ํ๋ฒ ์ ๋ฆฌํด๋ณผ๊ฒ:
๐ ๊ธฐ์ตํด์ผ ํ ํต์ฌ ํฌ์ธํธ
1. ์น ์ ๊ทผ์ฑ์ ๋ชจ๋๋ฅผ ์ํ ๊ฒ์ฅ์ ์ธ๋ฟ๋ง ์๋๋ผ ๋ ธ์ธ, ์ผ์์ ์ฅ์ ๋ฅผ ๊ฐ์ง ์ฌ๋, ๋ค์ํ ํ๊ฒฝ์ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ํํ์ ์ค.
2. POUR ์์น์ ๊ธฐ์ตํ์
โข Perceivable (์ธ์ ๊ฐ๋ฅ)
โข Operable (์ด์ฉ ๊ฐ๋ฅ)
โข Understandable (์ดํด ๊ฐ๋ฅ)
โข Robust (๊ฒฌ๊ณ ํจ)
3. ์ฒ์๋ถํฐ ๊ณ ๋ คํ๋ ๊ฒ ์ค์ํด
๋์ค์ ์ถ๊ฐํ๋ ๊ฒ๋ณด๋ค ์ฒ์๋ถํฐ ์ ๊ทผ์ฑ์ ๊ณ ๋ คํ๋ ๊ฒ ํจ์ฌ ํจ์จ์ ์ด์ผ.
4. ์๋ํ ๋๊ตฌ + ์๋ ํ ์คํธ
์๋ํ ๋๊ตฌ๋ ์์์ ์ผ ๋ฟ, ์ค์ ์ฌ์ฉ์ ๊ด์ ์ ์๋ ํ ์คํธ๊ฐ ํ์์ผ.
5. ์ง์์ ์ธ ํ์ต๊ณผ ๊ฐ์
์น ์ ๊ทผ์ฑ์ ํ ๋ฒ ํ๊ณ ๋๋๋ ๊ฒ ์๋์ผ. ๊ณ์ ๋ฐฐ์ฐ๊ณ ๊ฐ์ ํด์ผ ํด.
6. ๋ฒ์ ์๋ฌด์ด์ ์ค๋ฆฌ์ ์ฑ ์
ํ๊ตญ์์๋ ๋ฒ์ผ๋ก ์๋ฌดํ๋์ด ์๊ณ , ๋ฌด์๋ณด๋ค ๋ชจ๋ ์ฌ๋์ ๊ถ๋ฆฌ๋ฅผ ์กด์คํ๋ ์ผ์ด์ผ.
๐ ์ง๊ธ ๋ฐ๋ก ์์ํ ์ ์๋ ๊ฒ๋ค
์ค๋๋ถํฐ ์ค์ฒํ๊ธฐ:โก ๋ชจ๋ ์ด๋ฏธ์ง์ ์๋ฏธ ์๋ alt ํ ์คํธ ์ถ๊ฐ
โก ์๋งจํฑ HTML ํ๊ทธ ์ฌ์ฉํ๊ธฐ
โก ํค๋ณด๋๋ง์ผ๋ก ์ฌ์ดํธ ํ์ํด๋ณด๊ธฐ
โก ์์ ๋๋น ์ฒดํฌํ๊ธฐ
โก ์๋ํ ๋๊ตฌ๋ก ์ฌ์ดํธ ๊ฒ์ฌํ๊ธฐ
์ด๋ฒ ์ฃผ ๋ชฉํ:
โก ์คํฌ๋ฆฐ ๋ฆฌ๋ ์ค์นํ๊ณ ์ฌ์ฉํด๋ณด๊ธฐ
โก WCAG 2.1 ํต ๋ ํผ๋ฐ์ค ๋ถ๋งํฌํ๊ธฐ
โก ํ์๋ค๊ณผ ์ ๊ทผ์ฑ ์ค์์ฑ ๊ณต์ ํ๊ธฐ
โก ํ ํ์ด์ง๋ผ๋ ์๋ฒฝํ๊ฒ ์ ๊ทผ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค๊ธฐ
์ด๋ฒ ๋ฌ ๋ชฉํ:
โก ์ ์ฒด ์ฌ์ดํธ ์ ๊ทผ์ฑ ๊ฐ์ฌ ์ค์
โก ๊ฐ์ ๊ณํ ์๋ฆฝ
โก ์ ๊ทผ์ฑ ๊ฐ์ด๋๋ผ์ธ ๋ฌธ์ํ
โก CI/CD์ ์๋ํ ํ ์คํธ ํตํฉ
์น ์ ๊ทผ์ฑ์ ์ด๋ ต๊ณ ๋ณต์กํด ๋ณด์ผ ์ ์์ง๋ง, ํ ๊ฑธ์์ฉ ๋์๊ฐ๋ค ๋ณด๋ฉด ์ด๋์ ์์ฐ์ค๋ฌ์ด ์ต๊ด์ด ๋ ๊ฑฐ์ผ. ๊ทธ๋ฆฌ๊ณ ๊ทธ ๊ณผ์ ์์ ๋น์ ์ ๋ ๋์ ๊ฐ๋ฐ์๊ฐ ๋์ด ์์ ๊ฑฐ๊ณ ! ๐ปโจ
๋ชจ๋ ์ฌ๋์ด ์น์ ์์ ๋กญ๊ฒ ์ฌ์ฉํ ์ ์๋ ๊ทธ๋ ๊น์ง, ์ฐ๋ฆฌ ํจ๊ป ๋
ธ๋ ฅํ์! ๐โค๏ธ
๊ถ๊ธํ ์ ์ด ์๊ฑฐ๋ ๋์์ด ํ์ํ๋ค๋ฉด, ์ฌ๋ฅ๋ท์์ ์ ๋ฌธ๊ฐ๋ฅผ ์ฐพ์๋ณด๊ฑฐ๋ ์จ๋ผ์ธ ์ปค๋ฎค๋ํฐ์ ์ง๋ฌธํด๋ด. ์น ์ ๊ทผ์ฑ ์ปค๋ฎค๋ํฐ๋ ๋งค์ฐ ์น์ ํ๊ณ ๋์์ ์ฃผ๋ ค๋ ์ฌ๋๋ค์ด ๋ง์! ๐ค
์, ์ด์ ๋น์ ์ ์น์ฌ์ดํธ๋ฅผ ๋ชจ๋๊ฐ ์ฌ์ฉํ ์ ์๋ ํฌ์ฉ์ ์ธ ๊ณต๊ฐ์ผ๋ก ๋ง๋ค์ด๋ณด์! ํ์ดํ
! ๐
๐ Remember:
"The power of the Web is in its universality.
Access by everyone regardless of disability is an essential aspect."
- Tim Berners-Lee, W3C Director and inventor of the World Wide Web
๊ด๋ จ ํค์๋
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.

๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.