๐Ÿ’ป ์ ‘๊ทผ์„ฑ(feat. ๋ฆฌ์•กํŠธ ๊ณต์‹๋ฌธ์„œ)

waterglassesยท2022๋…„ 10์›” 3์ผ
1

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
38/50
post-thumbnail

โš ๏ธ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์€ ์˜คํƒ€๋‚˜ ์ž˜๋ชป๋œ ์ •๋ณด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ƒ ์˜ค๋Š˜ ๊ณต๋ถ€ํ•œ ๊ฒƒ

์ ‘๊ทผ์„ฑ์ด ํ•„์š”ํ•œ ์ด์œ 

์›น ์ ‘๊ทผ์„ฑ์€ ๋ชจ๋‘๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์›น์‚ฌ์ดํŠธ๋ฅผ ๋””์ž์ธ, ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

React๋Š” ์ ‘๊ทผ์„ฑ์„ ๊ฐ–์ถ˜ ์›น์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋„๋ก ๋ชจ๋“  ์ง€์›์„ ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ๋Œ€๋ถ€๋ถ„์€ ํ‘œ์ค€ HTML ๊ธฐ์ˆ ์ด ์‚ฌ์šฉ๋œ๋‹ค.

์ ‘๊ทผ์„ฑ์„ ์ค€์ˆ˜ํ•˜๋ฉด ๋ณด์กฐ๊ธฐ๊ธฐ ์‚ฌ์šฉ์ž์˜ ์ ‘๊ทผ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ, SEO๋„ ํ–ฅ์ƒ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

ํ‘œ์ค€ ๋ฐ ์ง€์นจ

WCAC(Web content Accessibility Guidelines)

์ ‘๊ทผ์„ฑ์„ ๊ฐ–์ถ˜ ์›น ์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ํ•„์š”ํ•œ ์ง€์นจ์„ ์ œ๊ณตํ•œ๋‹ค.

WAI-ARAI(Web Accessibility Initiative - Accessible Rich Internet Applications)

์ ‘๊ทผ์„ฑ์„ ๊ฐ–์ถ˜ JavaScript ์œ„์ ฏ์„ ๋งŒ๋“œ๋Š” ๋ฐ ํ•„์š”ํ•œ ๊ธฐ์ˆ ๋“ค์ด ๋‹ด๊ฒจ ์žˆ๋‹ค.

JSX์—์„œ๋Š” ๋ชจ๋“  aria-* HTML ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ง€์›ํ•˜๊ณ  ์žˆ๋‹ค. ์ด ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋Š” ์ผ๋ฐ˜์ ์ธ HTML๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ hypen-case๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

<input
  type="text"
  aria-label={labelText}
  aria-required="true"
  onChange={onchangeHandler}
  value={inputValue}
  name="name"
/>

JSX๋ž€?

JavaScript๋ฅผ ํ™•์žฅํ•œ ๋ฌธ๋ฒ•์ด๋‹ค. JSX๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ฝ”๋“œ๊ฐ€ ๋ฒˆ๋“ค๋ง๋˜๋Š” ๊ณผ์ •์—์„œ ๋ฐ”๋ฒจ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ผ๋ฐ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ˜•ํƒœ์˜ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜๋œ๋‹ค.

์‹œ๋ฉ˜ํ‹ฑ HTML

์‹œ๋ฉ˜ํ‹ฑ HTML์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์žˆ์–ด ์ ‘๊ทผ์„ฑ์˜ ๊ธฐ์ดˆ์ด๋‹ค. HTML ํƒœ๊ทธ๋ฅผ ์›น ์‚ฌ์ดํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ ‘๊ทผ์„ฑ์ด ๊ฐ–์ถ”์–ด์ง„๋‹ค. ์ฆ‰, ์˜๋ฏธ์— ๋งž๋Š” ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฌธ์„œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

๋ฆฌ์•กํŠธ์—์„œ๋Š” <div> ์™€ ๊ฐ™์€ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค React Fragment๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฌถ๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

import React, { Fragment } from 'react';

function ListItem({ item }) {
  return (
    <Fragment>
      <dt>{item.term}</dt>
      <dd>{item.description}</dd>
    </Fragment>
  );
}

์ ‘๊ทผ์„ฑ ์žˆ๋Š” ํผ

๋ผ๋ฒจ๋ง

<input>๊ณผย <textarea>ย ๊ฐ™์€ ๋ชจ๋“  HTML ํผ ์ปจํŠธ๋กค์€ ์Šคํฌ๋ฆฐ ๋ฆฌ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•ด ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ๋ฒจ์ด ํ•„์š”ํ•˜๋‹ค.

<label htmlFor="namedInput">Name:</label>
<input id="namedInput" type="text" name="name"/>

ํฌ์ปค์Šค ์ปจํŠธ๋กค

ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค์™€ ํฌ์ปค์Šค ์œค๊ณฝ์„ 

React ์•ฑ๋“ค์€ ๋Ÿฐํƒ€์ž„๋™์•ˆ HTML DOM์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ€๋” ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค๋ฅผ ์žƒ๊ฑฐ๋‚˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์—˜๋ฆฌ๋จผํŠธ์— ํฌ์ปค์Šค๋ฅผ ๋งž์ถ”๊ณค ํ•œ๋‹ค.

โš ๏ธย ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค๋Š” ๋งค์šฐ ์ค‘์š”ํ•œ ์ ‘๊ทผ์„ฑ ๊ธฐ๋Šฅ์ด์ง€๋งŒ, ๋™์‹œ์— ๋งค์šฐ ์กฐ์‹ฌํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค ํ๋ฆ„์ด ํํŠธ๋Ÿฌ์กŒ์„ ๋•Œ ์ด๋ฅผ ๊ณ ์น˜๋ ค๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์›ํ•˜๋Š” ์ฝ˜ํ…์ธ ๋กœ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

ํ‚ค๋ณด๋“œ๋กœ ์ด์ „์— ํƒ์ƒ‰ํ•œ ์˜์—ญ์„ ๊ฑด๋„ˆ๋›ธ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค.

Skil Navigation Links

ํ‚ค๋ณด๋“œ ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ๋•Œ๋งŒ ํ‘œ์‹œ๋˜๋Š” ์ˆจ๊ฒจ์ง„ ๋งํฌ๋“ค

  1. ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฑด๋„ˆ๋›ฐ๊ธฐ ๋งํฌ ๋งŒ๋“ค๊ธฐ(ex. <nav>)
  2. ์ผ์‹œ์ ์œผ๋กœ ์ˆจ๊ฒจ์ง„ ๊ฑด๋„ˆ๋›ฐ๊ธฐ ๋งํฌ(ex. ์ดˆ์ ์ด ๋งž์ถฐ์ง€๋ฉด ๋ณด์ž„)

ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ ์œผ๋กœ ํฌ์ปค์Šค ๊ด€๋ฆฌํ•˜๊ธฐ

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ชจ๋‹ฌ์ด ๋‹ซํžŒ ํ›„์—๋Š” ๋ชจ๋‹ฌ์„ ์—ด์—ˆ๋˜ ๋ฒ„ํŠผ์œผ๋กœ ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค๋ฅผ ๋‹ค์‹œ ๋งž์ถฐ์ฃผ์–ด์•ผ ํ•จ

React์—์„œ ํฌ์ปค์Šค๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•

  • DOM ์—˜๋ฆฌ๋จผํŠธ์— ref ์‚ฌ์šฉ
    • ๊ณต์‹๋ฌธ์„œ Refs and the DOM
    • ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ์•กํŠธ ๋‚ด์žฅ ํ•จ์ˆ˜ createRef
      class App extends React.Component {
        componentDidMount() {
          this.divRef = React.createRef();
        }
        render() {
          return (
            <div>
              <div id="divR" ref={this.divRef}>
                App, here
              </div>
            </div>
          );
        }
      }
    • ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ์•กํŠธ ํ›… useRef
      import React, { useRef } from "react";
      
      const App = () => {
        const divRef = React.useRef();
        const valueRef = React.useRef(90);
        return (
          <div>
            ๊ฐ’ : {valueRef.current}
            <div id="divR" ref={divRef}>
              App, here
            </div>
            <button onClick={() => (valueRef.current = 88)}> ์ฆ๊ฐ€ </button>
          </div>
        );
      };
      
      export default App;
      • ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์— createRef๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ref๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์–ด ์›ํ•˜๋Š” ๊ฐ’์„ ์–ป์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— useRef๋ฅผ ์‚ฌ์šฉ

๋งˆ์šฐ์Šค์™€ ํฌ์ธํ„ฐ ์ด๋ฒคํŠธ

๋งˆ์šฐ์Šค ํ˜น์€ ํฌ์ธํ„ฐ ์ด๋ฒคํŠธ๋กœ ๋…ธ์ถœ๋œ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ํ‚ค๋ณด๋“œ๋งŒ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผํ•œ๋‹ค.

ํด๋ฆญ ์ด๋ฒคํŠธ๋กœ ์ ‘๊ทผ์„ฑ์ด ๋–จ์–ด์ง€๋Š” ์˜ˆ์‹œ

  • ์™ธ๋ถ€ ํด๋ฆญ ํŒจํ„ด

    • ์ด๋Š” ํ‚ค๋ณด๋“œ ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ๊ธฐ๋Šฅ์ ์œผ๋กœ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค. ๋”ฐ๋ผ์„œ onBlur ๋˜๋Š” onFocus ์™€ ๊ฐ™์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿ”ฅ ๋Š๋‚€์ 

๊ณต๋ถ€ํ•˜๋ฉด์„œ ๊ทธ๋™์•ˆ ์›น ์‹œ๋ฉ˜ํ‹ฑ์ด๋ผ๊ณ  ํ•˜๋ฉด์„œ ์ ‘๊ทผ์„ฑ์„ ๋‹จ์ •์ง“์ง€ ์•Š์•˜๋‚˜ํ•˜๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ์ ‘๊ทผ์„ฑ์—๋Š” ์‹œ๋ฉ˜ํ‹ฑ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํผ, ํ‚ค๋ณด๋“œ, ๋งˆ์šฐ์Šค ์›€์ง์ž„ ๋“ฑ์˜ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์˜ ์›€์ง์ž„๋„ ํฌํ•จํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.

๋˜ํ•œ aria-*๋„ aria-label๋ง๊ณ ๋Š” ์ ๊ทน์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ํƒœ๊ทธ๋งŒ์œผ๋กœ ์„ค๋ช…ํ•  ์ˆ˜ ์—†์„ ๊ฒฝ์šฐ ๊ผญ ๋„ฃ์–ด์•ผ ๊ฒ ๋‹ค๊ณ  ๋‹ค์งํ–ˆ๋‹ค.

Refer

profile
๋งค ์ˆœ๊ฐ„ ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€