1<!DOCTYPE html>
2<html lang="ko">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>์น ์ ๊ทผ์ฑ ์์ - Web Accessibility Examples</title>
7 <link rel="stylesheet" href="style.css">
8</head>
9<body>
10 <!-- Skip Navigation -->
11 <a href="#main-content" class="skip-link">๋ณธ๋ฌธ์ผ๋ก ๊ฑด๋๋ฐ๊ธฐ</a>
12
13 <!-- Header with proper landmarks -->
14 <header role="banner">
15 <nav role="navigation" aria-label="๋ฉ์ธ ๋ค๋น๊ฒ์ด์
">
16 <ul class="nav-list">
17 <li><a href="#semantic" aria-current="page">์๋งจํฑ HTML</a></li>
18 <li><a href="#aria">ARIA</a></li>
19 <li><a href="#forms">ํผ ์ ๊ทผ์ฑ</a></li>
20 <li><a href="#keyboard">ํค๋ณด๋ ๋ด๋น๊ฒ์ด์
</a></li>
21 <li><a href="#focus">ํฌ์ปค์ค ๊ด๋ฆฌ</a></li>
22 </ul>
23 </nav>
24 </header>
25
26 <main id="main-content" role="main">
27 <h1>์น ์ ๊ทผ์ฑ (Web Accessibility) ์์ </h1>
28 <p class="intro">
29 WCAG 2.1 ๊ฐ์ด๋๋ผ์ธ์ ๋ฐ๋ฅด๋ ์ ๊ทผ์ฑ ์๋ ์น ์ปดํฌ๋ํธ ์์ ์
๋๋ค.
30 ์คํฌ๋ฆฐ ๋ฆฌ๋์ ํค๋ณด๋ ๋ค๋น๊ฒ์ด์
์ ํ
์คํธํด ๋ณด์ธ์.
31 </p>
32
33 <!-- Section 1: Semantic HTML -->
34 <section id="semantic" aria-labelledby="semantic-heading">
35 <h2 id="semantic-heading">1. ์๋งจํฑ HTML</h2>
36
37 <article>
38 <h3>์๋งจํฑ ์์ ์ฌ์ฉ</h3>
39 <p>์ ์ ํ HTML ์์๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๊ทผ์ฑ์ด ์๋์ผ๋ก ํฅ์๋ฉ๋๋ค.</p>
40
41 <div class="example-box">
42 <h4>์ฌ๋ฐ๋ฅธ ํค๋ฉ ๊ตฌ์กฐ</h4>
43 <pre><code><h1>ํ์ด์ง ์ ๋ชฉ</h1>
44<h2>์น์
์ ๋ชฉ</h2>
45<h3>ํ์ ์น์
</h3></code></pre>
46 </div>
47
48 <div class="example-box">
49 <h4>๋ฆฌ์คํธ ๊ตฌ์กฐ</h4>
50 <ul>
51 <li>ํญ๋ชฉ 1: ์์ ์๋ ๋ฆฌ์คํธ (ul)</li>
52 <li>ํญ๋ชฉ 2: ์คํฌ๋ฆฐ ๋ฆฌ๋๊ฐ ํญ๋ชฉ ์๋ฅผ ์๋ ค์ค</li>
53 <li>ํญ๋ชฉ 3: ๋ค๋น๊ฒ์ด์
์๋ ํ์ฉ</li>
54 </ul>
55
56 <ol>
57 <li>์ฒซ ๋ฒ์งธ: ์์ ์๋ ๋ฆฌ์คํธ (ol)</li>
58 <li>๋ ๋ฒ์งธ: ์์๊ฐ ์ค์ํ ๋ ์ฌ์ฉ</li>
59 <li>์ธ ๋ฒ์งธ: ๋จ๊ณ๋ณ ์ค๋ช
์ ์ ํฉ</li>
60 </ol>
61
62 <dl>
63 <dt>์ ์ ๋ฆฌ์คํธ (dl)</dt>
64 <dd>์ฉ์ด์ ์ค๋ช
์ ์ง์ง์ ๋ ์ฌ์ฉํฉ๋๋ค.</dd>
65 <dt>์ ๊ทผ์ฑ</dt>
66 <dd>๋ชจ๋ ์ฌ์ฉ์๊ฐ ์น์ ์ด์ฉํ ์ ์๋๋ก ํ๋ ๊ฒ</dd>
67 </dl>
68 </div>
69 </article>
70
71 <article>
72 <h3>์ด๋ฏธ์ง ๋์ฒด ํ
์คํธ</h3>
73 <div class="image-examples">
74 <!-- ์ ๋ณด๋ฅผ ์ ๋ฌํ๋ ์ด๋ฏธ์ง -->
75 <figure>
76 <img src="https://via.placeholder.com/200x150/4CAF50/ffffff?text=Info+Image"
77 alt="์ ๋ณด๋ฅผ ์ ๋ฌํ๋ ์ด๋ฏธ์ง: ์ด๋ก์ ๋ฐฐ๊ฒฝ์ ํฐ์ ํ
์คํธ"
78 width="200" height="150">
79 <figcaption>์ ๋ณด ์ ๋ฌ ์ด๋ฏธ์ง - alt ํ
์คํธ ํ์</figcaption>
80 </figure>
81
82 <!-- ์ฅ์์ฉ ์ด๋ฏธ์ง -->
83 <figure>
84 <img src="https://via.placeholder.com/200x150/cccccc/999999?text=Decorative"
85 alt=""
86 role="presentation"
87 width="200" height="150">
88 <figcaption>์ฅ์์ฉ ์ด๋ฏธ์ง - alt="" ์ฌ์ฉ</figcaption>
89 </figure>
90 </div>
91 </article>
92 </section>
93
94 <!-- Section 2: ARIA -->
95 <section id="aria" aria-labelledby="aria-heading">
96 <h2 id="aria-heading">2. ARIA (Accessible Rich Internet Applications)</h2>
97
98 <article>
99 <h3>ARIA ์ญํ (Roles)</h3>
100 <div class="example-box">
101 <!-- Alert -->
102 <div role="alert" class="alert alert-warning">
103 <strong>๊ฒฝ๊ณ :</strong> ์ด๊ฒ์ role="alert"๋ฅผ ๊ฐ์ง ๋ฉ์์ง์
๋๋ค.
104 ์คํฌ๋ฆฐ ๋ฆฌ๋๊ฐ ์ฆ์ ์ฝ์ด์ค๋๋ค.
105 </div>
106
107 <!-- Status -->
108 <div role="status" aria-live="polite" class="status-message">
109 ํ์ฌ ์ํ: ์ ์ (role="status")
110 </div>
111
112 <!-- Search -->
113 <div role="search">
114 <label for="search-input">๊ฒ์:</label>
115 <input type="search" id="search-input" placeholder="๊ฒ์์ด ์
๋ ฅ">
116 <button type="submit">๊ฒ์</button>
117 </div>
118 </div>
119 </article>
120
121 <article>
122 <h3>ARIA ์ํ์ ์์ฑ</h3>
123 <div class="example-box">
124 <!-- Expandable section -->
125 <button
126 id="accordion-btn"
127 aria-expanded="false"
128 aria-controls="accordion-content"
129 class="accordion-button">
130 <span>์์ฝ๋์ธ ์ด๊ธฐ/๋ซ๊ธฐ</span>
131 <span aria-hidden="true" class="icon">โผ</span>
132 </button>
133 <div
134 id="accordion-content"
135 class="accordion-content"
136 hidden>
137 <p>์ด ๋ด์ฉ์ ์์ฝ๋์ธ์ด ํผ์ณ์ก์ ๋ ํ์๋ฉ๋๋ค.</p>
138 <p>aria-expanded์ aria-controls๋ก ์ํ๋ฅผ ์ ๋ฌํฉ๋๋ค.</p>
139 </div>
140
141 <!-- Progress -->
142 <div class="progress-demo">
143 <label for="progress-demo">์งํ๋ฅ :</label>
144 <div
145 id="progress-demo"
146 role="progressbar"
147 aria-valuenow="60"
148 aria-valuemin="0"
149 aria-valuemax="100"
150 aria-label="ํ์ผ ์
๋ก๋ ์งํ๋ฅ "
151 class="progress-bar">
152 <div class="progress-fill" style="width: 60%">60%</div>
153 </div>
154 </div>
155
156 <!-- Tab panel -->
157 <div class="tabs-demo">
158 <div role="tablist" aria-label="์ํ ํญ">
159 <button
160 role="tab"
161 id="tab1"
162 aria-selected="true"
163 aria-controls="panel1"
164 tabindex="0">
165 ํญ 1
166 </button>
167 <button
168 role="tab"
169 id="tab2"
170 aria-selected="false"
171 aria-controls="panel2"
172 tabindex="-1">
173 ํญ 2
174 </button>
175 <button
176 role="tab"
177 id="tab3"
178 aria-selected="false"
179 aria-controls="panel3"
180 tabindex="-1">
181 ํญ 3
182 </button>
183 </div>
184 <div
185 role="tabpanel"
186 id="panel1"
187 aria-labelledby="tab1"
188 tabindex="0">
189 <p>ํญ 1์ ๋ด์ฉ์
๋๋ค.</p>
190 </div>
191 <div
192 role="tabpanel"
193 id="panel2"
194 aria-labelledby="tab2"
195 tabindex="0"
196 hidden>
197 <p>ํญ 2์ ๋ด์ฉ์
๋๋ค.</p>
198 </div>
199 <div
200 role="tabpanel"
201 id="panel3"
202 aria-labelledby="tab3"
203 tabindex="0"
204 hidden>
205 <p>ํญ 3์ ๋ด์ฉ์
๋๋ค.</p>
206 </div>
207 </div>
208 </div>
209 </article>
210
211 <article>
212 <h3>Live Regions</h3>
213 <div class="example-box">
214 <button id="update-live-btn">์ค์๊ฐ ์
๋ฐ์ดํธ</button>
215 <div
216 id="live-region"
217 aria-live="polite"
218 aria-atomic="true"
219 class="live-region">
220 ์ฌ๊ธฐ์ ์ค์๊ฐ ๋ฉ์์ง๊ฐ ํ์๋ฉ๋๋ค.
221 </div>
222 </div>
223 </article>
224 </section>
225
226 <!-- Section 3: Accessible Forms -->
227 <section id="forms" aria-labelledby="forms-heading">
228 <h2 id="forms-heading">3. ์ ๊ทผ์ฑ ์๋ ํผ</h2>
229
230 <form id="accessible-form" novalidate>
231 <fieldset>
232 <legend>๊ฐ์ธ ์ ๋ณด</legend>
233
234 <!-- Required field with label -->
235 <div class="form-group">
236 <label for="name">
237 ์ด๋ฆ <span class="required" aria-hidden="true">*</span>
238 <span class="sr-only">(ํ์)</span>
239 </label>
240 <input
241 type="text"
242 id="name"
243 name="name"
244 required
245 aria-required="true"
246 aria-describedby="name-hint">
247 <span id="name-hint" class="hint">ํ๊ธ ๋๋ ์๋ฌธ์ผ๋ก ์
๋ ฅ</span>
248 </div>
249
250 <!-- Email with validation -->
251 <div class="form-group">
252 <label for="email">
253 ์ด๋ฉ์ผ <span class="required" aria-hidden="true">*</span>
254 <span class="sr-only">(ํ์)</span>
255 </label>
256 <input
257 type="email"
258 id="email"
259 name="email"
260 required
261 aria-required="true"
262 aria-describedby="email-error"
263 aria-invalid="false">
264 <span id="email-error" class="error" role="alert" hidden></span>
265 </div>
266
267 <!-- Phone with input mask hint -->
268 <div class="form-group">
269 <label for="phone">์ ํ๋ฒํธ</label>
270 <input
271 type="tel"
272 id="phone"
273 name="phone"
274 placeholder="010-1234-5678"
275 pattern="[0-9]{3}-[0-9]{4}-[0-9]{4}"
276 aria-describedby="phone-hint">
277 <span id="phone-hint" class="hint">ํ์: 010-1234-5678</span>
278 </div>
279 </fieldset>
280
281 <fieldset>
282 <legend>์ฐ๋ฝ ์ ํธ ๋ฐฉ๋ฒ</legend>
283
284 <div class="radio-group" role="radiogroup" aria-labelledby="contact-method-label">
285 <span id="contact-method-label" class="sr-only">์ฐ๋ฝ ๋ฐฉ๋ฒ ์ ํ</span>
286
287 <div class="radio-option">
288 <input type="radio" id="contact-email" name="contact" value="email" checked>
289 <label for="contact-email">์ด๋ฉ์ผ</label>
290 </div>
291
292 <div class="radio-option">
293 <input type="radio" id="contact-phone" name="contact" value="phone">
294 <label for="contact-phone">์ ํ</label>
295 </div>
296
297 <div class="radio-option">
298 <input type="radio" id="contact-sms" name="contact" value="sms">
299 <label for="contact-sms">๋ฌธ์</label>
300 </div>
301 </div>
302 </fieldset>
303
304 <fieldset>
305 <legend>๊ด์ฌ ๋ถ์ผ (๋ณต์ ์ ํ ๊ฐ๋ฅ)</legend>
306
307 <div class="checkbox-group">
308 <div class="checkbox-option">
309 <input type="checkbox" id="interest-web" name="interests" value="web">
310 <label for="interest-web">์น ๊ฐ๋ฐ</label>
311 </div>
312
313 <div class="checkbox-option">
314 <input type="checkbox" id="interest-mobile" name="interests" value="mobile">
315 <label for="interest-mobile">๋ชจ๋ฐ์ผ ์ฑ</label>
316 </div>
317
318 <div class="checkbox-option">
319 <input type="checkbox" id="interest-ai" name="interests" value="ai">
320 <label for="interest-ai">์ธ๊ณต์ง๋ฅ</label>
321 </div>
322 </div>
323 </fieldset>
324
325 <fieldset>
326 <legend>์ถ๊ฐ ์ ๋ณด</legend>
327
328 <div class="form-group">
329 <label for="country">๊ตญ๊ฐ</label>
330 <select id="country" name="country">
331 <option value="">์ ํํ์ธ์</option>
332 <option value="kr">๋ํ๋ฏผ๊ตญ</option>
333 <option value="us">๋ฏธ๊ตญ</option>
334 <option value="jp">์ผ๋ณธ</option>
335 <option value="cn">์ค๊ตญ</option>
336 </select>
337 </div>
338
339 <div class="form-group">
340 <label for="message">๋ฉ์์ง</label>
341 <textarea
342 id="message"
343 name="message"
344 rows="4"
345 aria-describedby="message-hint"></textarea>
346 <span id="message-hint" class="hint">์ต๋ 500์</span>
347 </div>
348 </fieldset>
349
350 <div class="form-actions">
351 <button type="submit" class="btn-primary">์ ์ถ</button>
352 <button type="reset" class="btn-secondary">์ด๊ธฐํ</button>
353 </div>
354 </form>
355 </section>
356
357 <!-- Section 4: Keyboard Navigation -->
358 <section id="keyboard" aria-labelledby="keyboard-heading">
359 <h2 id="keyboard-heading">4. ํค๋ณด๋ ๋ด๋น๊ฒ์ด์
</h2>
360
361 <article>
362 <h3>ํค๋ณด๋ ๋จ์ถํค</h3>
363 <table class="keyboard-shortcuts">
364 <caption>์ฃผ์ ํค๋ณด๋ ๋จ์ถํค</caption>
365 <thead>
366 <tr>
367 <th scope="col">ํค</th>
368 <th scope="col">๋์</th>
369 </tr>
370 </thead>
371 <tbody>
372 <tr>
373 <td><kbd>Tab</kbd></td>
374 <td>๋ค์ ํฌ์ปค์ค ๊ฐ๋ฅํ ์์๋ก ์ด๋</td>
375 </tr>
376 <tr>
377 <td><kbd>Shift</kbd> + <kbd>Tab</kbd></td>
378 <td>์ด์ ํฌ์ปค์ค ๊ฐ๋ฅํ ์์๋ก ์ด๋</td>
379 </tr>
380 <tr>
381 <td><kbd>Enter</kbd> / <kbd>Space</kbd></td>
382 <td>๋ฒํผ ํ์ฑํ, ๋งํฌ ํด๋ฆญ</td>
383 </tr>
384 <tr>
385 <td><kbd>โ</kbd> <kbd>โ</kbd></td>
386 <td>๋ผ๋์ค ๋ฒํผ, ๋๋กญ๋ค์ด ์ ํ</td>
387 </tr>
388 <tr>
389 <td><kbd>Esc</kbd></td>
390 <td>๋ชจ๋ฌ ๋ซ๊ธฐ, ๋์ ์ทจ์</td>
391 </tr>
392 </tbody>
393 </table>
394 </article>
395
396 <article>
397 <h3>์ปค์คํ
ํค๋ณด๋ ๋ด๋น๊ฒ์ด์
</h3>
398 <div class="example-box">
399 <p>ํ์ดํ ํค๋ก ํญ๋ชฉ์ ํ์ํ๊ณ Enter๋ก ์ ํํ์ธ์.</p>
400 <ul
401 role="listbox"
402 id="custom-listbox"
403 aria-label="๊ณผ์ผ ์ ํ"
404 tabindex="0"
405 class="custom-listbox">
406 <li role="option" id="option1" aria-selected="true">๐ ์ฌ๊ณผ</li>
407 <li role="option" id="option2" aria-selected="false">๐ ์ค๋ ์ง</li>
408 <li role="option" id="option3" aria-selected="false">๐ ํฌ๋</li>
409 <li role="option" id="option4" aria-selected="false">๐ ๋ธ๊ธฐ</li>
410 <li role="option" id="option5" aria-selected="false">๐ ๋ฐ๋๋</li>
411 </ul>
412 <p id="listbox-output" aria-live="polite">์ ํ๋ ํญ๋ชฉ: ์ฌ๊ณผ</p>
413 </div>
414 </article>
415 </section>
416
417 <!-- Section 5: Focus Management -->
418 <section id="focus" aria-labelledby="focus-heading">
419 <h2 id="focus-heading">5. ํฌ์ปค์ค ๊ด๋ฆฌ</h2>
420
421 <article>
422 <h3>๋ชจ๋ฌ ๋ค์ด์ผ๋ก๊ทธ</h3>
423 <div class="example-box">
424 <button id="open-modal-btn" class="btn-primary">๋ชจ๋ฌ ์ด๊ธฐ</button>
425 </div>
426 </article>
427
428 <article>
429 <h3>ํฌ์ปค์ค ํธ๋ฉ ์์ </h3>
430 <div class="example-box">
431 <p>์๋ ์์ญ ๋ด์์ Tab ํค๋ฅผ ๋๋ฅด๋ฉด ํฌ์ปค์ค๊ฐ ์ํํฉ๋๋ค.</p>
432 <div id="focus-trap-demo" class="focus-trap-area">
433 <button>๋ฒํผ 1</button>
434 <input type="text" placeholder="์
๋ ฅ ํ๋">
435 <button>๋ฒํผ 2</button>
436 <a href="#focus">๋งํฌ</a>
437 </div>
438 </div>
439 </article>
440 </section>
441
442 <!-- Color Contrast Demo -->
443 <section id="contrast" aria-labelledby="contrast-heading">
444 <h2 id="contrast-heading">6. ์์ ๋๋น</h2>
445
446 <div class="contrast-examples">
447 <div class="contrast-good">
448 <h3>์ข์ ๋๋น (4.5:1 ์ด์)</h3>
449 <p>์ด ํ
์คํธ๋ ์ฝ๊ธฐ ์ฝ์ต๋๋ค.</p>
450 </div>
451 <div class="contrast-bad" aria-label="๋์ ๋๋น ์์ - ์ฝ๊ธฐ ์ด๋ ค์">
452 <h3>๋์ ๋๋น (ํผํด์ผ ํจ)</h3>
453 <p>์ด ํ
์คํธ๋ ์ฝ๊ธฐ ์ด๋ ต์ต๋๋ค.</p>
454 </div>
455 </div>
456 </section>
457 </main>
458
459 <!-- Modal Dialog -->
460 <div
461 id="modal"
462 role="dialog"
463 aria-modal="true"
464 aria-labelledby="modal-title"
465 aria-describedby="modal-desc"
466 class="modal"
467 hidden>
468 <div class="modal-content">
469 <h2 id="modal-title">๋ชจ๋ฌ ๋ค์ด์ผ๋ก๊ทธ</h2>
470 <p id="modal-desc">
471 ์ด๊ฒ์ ์ ๊ทผ์ฑ์ ๊ณ ๋ คํ ๋ชจ๋ฌ์
๋๋ค.
472 Esc ํค๋ฅผ ๋๋ฅด๊ฑฐ๋ ๋ซ๊ธฐ ๋ฒํผ์ ํด๋ฆญํ์ฌ ๋ซ์ ์ ์์ต๋๋ค.
473 </p>
474 <div class="modal-actions">
475 <button id="modal-confirm" class="btn-primary">ํ์ธ</button>
476 <button id="modal-close" class="btn-secondary">๋ซ๊ธฐ</button>
477 </div>
478 </div>
479 </div>
480 <div id="modal-overlay" class="modal-overlay" hidden></div>
481
482 <footer role="contentinfo">
483 <p>์น ์ ๊ทผ์ฑ ์์ | WCAG 2.1 ์ค์</p>
484 <p>
485 ์ฐธ๊ณ : <a href="https://www.w3.org/WAI/WCAG21/quickref/">WCAG 2.1 Quick Reference</a>
486 </p>
487 </footer>
488
489 <script src="app.js"></script>
490</body>
491</html>