HTML 폼 구성 방법 - Web 개발 학습하기

HTML 폼 구성 방법
============

HTML폼을 만들떄 구조화 하는것은 중요한 것이다. 이것은 두가지 이유로 중요하다. 폼이 사용 할수 있다는 것을 보장하고 접근성도 늘릴수 있기 떄문이다.(즉 장애인들도 쉽게 사용할 수 있다.) HTML 폼의 접근성은 중요한 점이고 어떻게 폼 접근성을 높일 수 있는지 볼것이다.

* 이전
* Overview: Forms
* 다음

기본 사항을 다룬 후에는 이제 폼의 다른 부분에 구조와 의미를 부여하는 데 사용되는 요소들을 좀 더 자세히 살펴보겠습니다.

|  |  |
| --- | --- |
| 전제 조건: | 기본적인 컴퓨터 사용능력과 HTML에 대한 기본적인 이해. |
| 목표: | HTML 폼을 구조화하고 의미를 부여하여 사용가능하고 접근성있는 폼을 만드는 방법을 이해합니다. |

폼의 유연성은 폼을 HTML의 가장 복잡한 구조 중 하나로 만듭니다. 전용 요소들과 특성들로 모든 종류의 기본적인 폼을 만들 수 있습니다. HTML 폼을 만들때 올바른 구조를 사용하게되면 사용성과 접근성을 확보 할 수 있습니다.

<form> 요소
---------

`<form>` 요소는 폼을 형식적으로 정의하는 폼의 동작 방식을 결정하는 속성들을 포함합니다. HTML폼을 생성할떄마다 반드시 이 요소로 시작하고 모든 내용을 내부에 중첩해야 합니다. 많은 보조 기술이나 브라우저 플러그인이 `<form>` 요소를 발견하고 사용하기 쉽게 만들기 위해 특별한 기능을 제공 할 수 있습니다.

우리는 저번 문서에서 이미 이 내용을 다루었습니다.

**경고:** 폼을 다른 폼으로 중첩하는 것은 엄격하게 제한되어 있습니다. 그렇게 하면 사용자가 사용하는 브라우저에 따라 예측할 수 없는 방식으로 작동하므로 좋은 방법이 아닙니다.

언제든지 `<form>` 요소 바깥에서 폼 컨트롤을 사용할 수 있습니다. 이럴 경우 기본적으로 컨트롤은 `form` (en-US) 특성을 사용하여 연결해주지 않는한 어떤 폼과도 관련이 없습니다. 이것은 컨트롤이 폼 요소 내부에 중첩되어있지 않더라도 명시적으로 컨트롤을 명시적으로 바인딩할 수 있도록 하기위해 도입됐습니다.

다음으로 폼 내부의 중첩되어있는 구조요소에 대해 다루겠습니다.

<fieldset> 와 <legend> 요소
------------------------

`<fieldset>` 요소는 같은 목적을 가진 위젯들을 편리하게 그룹화 하는 방법입니다. `<fieldset>`에 레이블을 붙이려면 `<fieldset>` 태그 바로 아래에 `<legend>` 요소를 포함하면 됩니다. `<legend>`의 텍스트 컨텐츠는 `<fieldset>` 요소의 목적을 형식적으로 설명합니다.

많은 보조 기술들이 `<legend>` 요소를 해당 `<fieldset>` 요소내의 각 컨트롤의 레이블의 일부인것 처럼 사용합니다. 예를 들어 Jaws 와 NVDA 같은 스크린 리더는 각 컨트롤의 라벨을 읽기전에 legend를 읽을 것입니다.

아래 작은 예제가 있습니다.

```html
<form>
  <fieldset>
    <legend>Fruit juice size</legend>
    <p>
      <input type="radio" name="size" id="size\_1" value="small" />
      <label for="size\_1">Small</label>
    </p>
    <p>
      <input type="radio" name="size" id="size\_2" value="medium" />
      <label for="size\_2">Medium</label>
    </p>
    <p>
      <input type="radio" name="size" id="size\_3" value="large" />
      <label for="size\_3">Large</label>
    </p>
  </fieldset>
</form>
```

**참고:** 예제는 여기서 찾을수 있습니다. fieldset-legend.html (see it live also).

위 예제를 스크린 리더가 읽을때 Fruit juice size small을 먼저 읽고 Fruit juice size medium을 읽은 다음 마지막으로 Fruit juice size large을 읽을 것입니다.

이 예제에서의 사용 사례는 가장 중요한것 중 하나입니다. 라디오 버튼의 셋트는 항상 `<fieldset>` 요소 내부에 중첩해야 합니다. 다르게 사용하는 사례도 있으며, 흔히 `<fieldset>` 요소는 폼의 구획을 나누는데도 사용 할 수 있습니다. 이상적으로는 긴 폼을 여러 페이지에 걸쳐 나누는 것이 좋지만, 폼이 길어지고 단일 페이지에 위치해야 하는 경우, 서로 다른 관련 섹션을 각각 fieldset 내에 넣는것은 사용성을 향상 시킵니다.

보조기술에 대한 영향력으로 인해, `<fieldset>` 요소는 접근성 있는 폼을 구축하기위한 주요 요소 중 하나입니다. 그러나 이를 남용하지 않는것은 여러분의 책임입니다. 가능하다면 폼을 작성할 때마다 스크린리더가 어떻게 해석하는지 들어보는것 (en-US)이 좋습니다. 스크린리더가 읽는것이 이상하게 들린다면 폼 구조를 개선해보세요.

<label> 요소
----------

이전 글에서 볼 수 있듯이 `<label>` 요소는 HTML 폼 위젯에 대한 레이블을 정의하는 공식적인 방법입니다. 올바르게 구현되면 스크린 리더는 폼 요소의 레이블과 관련된 지시사항을 읽어주며 시각 장애인 사용자 뿐만 아니라 시각적으로 볼 수 있는 사용자에게도 유용합니다. 이전 글에서 본 것처럼, 다음과 같은 예시를 살펴보겠습니다.

```html
<label for="name">Name:</label> <input type="text" id="name" name="user\_name" />
```

`<label>` 요소가 `<input>`요소와 `for` 속성을 통해 (`<input>` 요소의 `id` 속성을 사용) 올바르게 연결되어 있을 때 스크린 리더는 "이름, 텍스트 수정"과 같은 내용을 읽어줍니다.

다른 방법으로도 폼 컨트롤과 레이블을 연결할 수 있습니다. 폼 컨트롤을 `<label>` 내부에 중첩하여 암묵적으로 연결할 수 있습니다.

```html
<label for="name">
  Name: <input type="text" id="name" name="user\_name" />
</label>
```

심지어 이러한 경우에도, 레이블과 위젯간의 관계를 보조기술이 이해할 수 있도록 `for` 속성을 설정하는 것이 가장 좋은 방법으로 권장됩니다.

레이블이 없거나 폼 컨트롤이 암묵적으로나 명시적으로 레이블과 연결되지 않은 경우, 스크린 리더는 "텍스트 수정 공백"과 같은 내용을 읽어주는데, 이는 전혀 도움이 되지 않습니다.

### 레이블도 클릭할 수 있습니다!

레이블을 올바르게 설정했을때의 또다른 장점은 해당 위젯을 활성화 하기위해 레이블을 클릭하거나 탭할 수 있다는 것입니다. 이는 텍스트입력과 같은 컨트롤에 유용합니다. 텍스트 입력의 경우 레이블 뿐만 아니라 입력란을 클릭하여 포커스를 활성화할 수 있지만, 라디오버튼과 체크박스 같은 경우애는 특히 유용합니다. 이러한 컨트롤의 클릭 영역은 매우 작을 수 있으므로 활성화하기 쉽도록 만드는 것이 유용합니다.

예를 들어 아래 예시의 "I like cherry"레이블 텍스트를 클릭하면 *taste\_cherry* 체크박스의 선택 상태가 토글됩니다.

```html
<form>
  <p>
    <input type="checkbox" id="taste\_1" name="taste\_cherry" value="cherry" />
    <label for="taste\_1">I like cherry</label>
  </p>
  <p>
    <input type="checkbox" id="taste\_2" name="taste\_banana" value="banana" />
    <label for="taste\_2">I like banana</label>
  </p>
</form>
```

>
> **Note:** 예제는 여기서 찾을수 있습니다. checkbox-label.html (see it live also).
>
>
>

### 여러개의 레이블

엄밀히 말하자면, 하나의 위젯에 여러개의 레이블을 넣을 수도 있지만, 이는 일부 보조기술에서 처리하는데 문제가 발생할 수 있으므로 좋은 아이디어는 아닙니다. 여러 레이블을 사용하는 경우 위젯과 해당 레이블을 하나의 `<label>` 요소안에 중첩시켜야 합니다.

다음 예시를 살펴보겠습니다.

```html
<p>Required fields are followed by <span aria-label="required">*</span>.</p>

<!-- 따라서 이렇게 작성합니다. -->
<!--div>
 <label for="username">Name:</label>
 <input id="username" type="text" name="username" required>
 <label for="username"><span aria-label="required">\*</label>
</div-->

<!-- 이렇게 작성하는것이 더 좋습니다. -->
<!--div>
 <label for="username">
 <span>Name:</span>
 <input id="username" type="text" name="username" required>
 <span aria-label="required">\*</span>
 </label>
</div-->

<!-- 하지만 이렇게 작성하는 것이 가장 좋을것입니다. -->
<div>
  <label for="username">Name: <span aria-label="required">*</span></label>
  <input id="username" type="text" name="username" required />
</div>
```

위의 문단은 필수 요소에대한 규칙을 설명합니다. 이 규칙은 필수요소를 만나기 전에 시각적으로 확인하는 사용자와 스크린 리더와 같은 보조 기술을 사용하는 사용자가 해당 규칙을 알 수 있도록 '이전'에 포함되어야 합니다. 이 방법은 사용자에게 애스터리스크의 의미를 알려주는데 도움이 됩니다. 그러나 이것으로는 부족합니다. 스크린리더는 애스터리스크를 '별표'라고 읽어줍니다. 시각적인 마우스 사용자가 마우스 호버하면 '필수'가 표시되어야 하는데, 이는 `title` 속성을 사용하여 달성할 수 있습니다. `title` 속성이 스크린 리더에서 읽히는 것은 스크린 리더의 설정에 다라 달라지므로 항상 스크린 리더에서 읽히는 `aria-label` 속성 또한 추가하는 것이 더 신뢰할 수 있습니다.

위의 예시들은 효과적으로 사용하기 위해 순서대로 개선되었습니다.

* 첫 번째 예시에서는 입력필드와 함께 레이블이 읽히지 않고 "텍스트 수정 공백"만 읽힙니다. 또한 실제 레이블들이 따로 읽히기 때문에 여러개의 `<label>` 요소가 스크린 리더를 더 혼란스럽게 만듭니다.
* 두 번째 예시에서는 조금 더 명확해집니다. 입력필드와 함께 읽히는 레이블은 "이름 별표 이름 텍스트수정 리콰이어드"로 읽히고, 레이블들은 여전히 따로 읽힙니다. 여전히 약간 혼동스럽지만, 이번에는 `<input>` 에 레이블이 연결되어있어서 조금 더 나아진 것입니다.
* 세 번째 예시가 가장 좋습니다. 실제 레이블이 모두 함께 읽히고, 입력필드와 함께 읽히는 레이블은 "이름 리콰이어드 텍스트 수정"으로 읽힙니다.

**참고:** 실제로 사용하는 스크린 리더에 따라 결과가 약간 다를 수 있습니다. 이 예시는 VoiceOver에서 테스트 되었으며, NVDA도 비슷하게 작동합니다. 여러분에 경험에 대해서도 듣고 싶습니다.

**참고:** 이 예시는 GitHub에서 required-labels.html (see it live also)로 찾을 수 있습니다. 다만, 주의해야 할 점은 두개이상의 버전을 주석 해제하여 테스트하지 않아야 한다는 점입니다. 동일한 ID를 가진 여러개의 레이블과 입력 필드가 있는 경우 스크린 리더가 혼란스러워질 수 있습니다!

폼과 함께 사용되는 일반 HTML 구조
---------------------

웹 폼과 관련된 구조 이외에도, 폼 마크업은 단지 HTML일 뿐이라는 것을 기억하는것이 좋습니다. 이는 HTML의 모든 기능을 활용하여 웹 폼을 구조화할 수 있다는 것을 의미합니다.

예시에서 확인할 수 있듯이, 레이블과 해당 위젯을 `<ul>` 또는 `<ol>` 리스트 내에서 `<li>` 요소로 감싸는 것이 흔한 방법입니다. `<p>`와 `<div>` (en-US) 요소도 흔히 사용됩니다. 여러 개의 체크박스 또는 라디오 버튼을 구조화하기 위해 리스트를 사용하는 것이 권장됩니다.

`<fieldset>` 요소 외에도, 복잡한 폼을 구조화 하기 위해 HTML 제목 (예: h1, h2) 과 섹션화 (e.g. `<section>`) 을 사용하는 것이 흔한 방법입니다.

무엇보다도, 접근 가능하고 사용하기 쉬운 폼을 만들기 위해 편안한 코딩 스타일을 찾는것은 여러분에게 달려있습니다. 각각의 기능 섹션은 별도의 `<section>` 요소에 포함되어야 하며, 라디오 버튼을 포함하는 `<fieldset>` 요소를 사용해야 합니다.

학습 활동: 폼 구조 만들기
---------------

자 그럼 아이디어를 실제로 적용해보고 약간 더 복잡한 폼의 결제 폼을 만들어보겠습니다. 이 폼에는 아직 이해하지 못할 수도 있는 여러가지 컨트롤 유형이 포함됩니다. 현재는 걱정하지 마세요. 다음 글에서 이들이 어떻게 작동하는지 알게될 것입니다 (기본 네이티브 폼 컨트롤). 지금은 아래 지침을 주의 깊게 읽으며, 폼을 구조화 하는데 사용하는 래퍼 요소와 그 이유를 천천히 파악해보세요.

1. 컴퓨터의 새로운 경로에 빈 템플릿 파일 과 결제 폼을 위한 CSS 의 로컬 복사본을 만드는것으로 시작해 봅시다.
2. HTML에 CSS를 적용하기 위해 HTML `<head>` 내부에 아래의 코드를 추가하세요

```html
<link href="payment-form.css" rel="stylesheet" />
```

3. 다음으로, `<form>` 요소를 추가해 폼을 생성하세요.

```html
<form>
...
</form>
```

4. 유저에게 필수 입력 필드가 어떻게 표시될지 알려주기 위해 `<form>` 요소 안에 제목과 문단을 추가하세요

```html
<h1>Payment form</h1>
<p>
  Required fields are followed by
  <strong><span aria-label="required">*</span></strong>.
</p>
```

5. 다음으로, 이전 항목 아래에 더 큰 코드 섹션을 폼에 추가하겠습니다. 여기에서는 연락처 정보를 필드를 별도의 `<section>` 요소로 감싸고 있는것을 볼 수 있습니다. 또한, 세 개의 라디오 버튼을 각각 자체적인 목록(`<li>`) 요소 내에 넣고 있습니다. 또한, 두 개의 일반 텍스트가 `<input>` (en-US) 과 그에 해당하는 `<label>` 요소가 각각 `<p>` 안에 포함되어 있으며, 비밀번호를 입력을 위한 비밀번호 입력란도 있습니다. 아래 코드를 폼에 추가하세요.

```html
<section>
  <h2>Contact information</h2>
  <fieldset>
    <legend>Title</legend>
    <ul>
      <li>
        <label for="title\_1">
          <input type="radio" id="title\_1" name="title" value="K" />
          King
        </label>
      </li>
      <li>
        <label for="title\_2">
          <input type="radio" id="title\_2" name="title" value="Q" />
          Queen
        </label>
      </li>
      <li>
        <label for="title\_3">
          <input type="radio" id="title\_3" name="title" value="J" />
          Joker
        </label>
      </li>
    </ul>
  </fieldset>
  <p>
    <label for="name">
      <span>Name: </span>
      <strong><span aria-label="required">*</span></strong>
    </label>
    <input type="text" id="name" name="username" required />
  </p>
  <p>
    <label for="mail">
      <span>Email: </span>
      <strong><span aria-label="required">*</span></strong>
    </label>
    <input type="email" id="mail" name="usermail" required />
  </p>
  <p>
    <label for="pwd">
      <span>Password: </span>
      <strong><span aria-label="required">*</span></strong>
    </label>
    <input type="password" id="pwd" name="password" required />
  </p>
</section>
```

6. 우리 폼의 두번째 `<section>` 은 결제정보 입니다.
 여기에서는 각각의 라벨과 함께 세 가지 독립적인 컨트롤이 포함된 `<p>` 가 있습니다.
 첫 번째는 신용카드 종류를 선택하기 위한 드롭다운 메뉴 (`<select>` (en-US)) 입니다.
 두번째는 신용카드 번호를 입력하기 위한 `tel` 타입의 `<input>` 요소입니다. 우리는 `number` 타입을 사용할 수 도 있지만, 우리는 번호입력기 UI(number's spinner UI)를 사용하고 싶지 않습니다.
 마지막으로 카드의 만료 날짜를 입력하기 위한 `text` 타입의 `<input>` 요소입니다. 이는 올바른 형식을 나타내는 *placeholder* 속성과 입력된 날짜가 올바른 형식인지 검사하는 *pattern* 속성이 포함되어 있습니다.
 이런 최신 입력 타입은 The HTML5 input types 에서 다시 소개됩니다.
 이전 섹션 아래에 다음 코드를 입력해주세요.

```html
<section>
  <h2>Payment information</h2>
  <p>
    <label for="card">
      <span>Card type:</span>
    </label>
    <select id="card" name="usercard">
      <option value="visa">Visa</option>
      <option value="mc">Mastercard</option>
      <option value="amex">American Express</option>
    </select>
  </p>
  <p>
    <label for="number">
      <span>Card number:</span>
      <strong><span aria-label="required">*</span></strong>
    </label>
    <input type="tel" id="number" name="cardnumber" required />
  </p>
  <p>
    <label for="expiration">
      <span>Expiration date:</span>
      <strong><span aria-label="required">*</span></strong>
    </label>
    <input
 type="text"
 id="expiration"
 required="true"
 placeholder="MM/YY"
 pattern="^(0[1-9]|1[0-2])\/([0-9]{2})$" />
  </p>
</section>
```

7. 마지막 섹션에서 추가할 섹션은 훨씬 간단합니다, 이 섹션에서는 데이터를 제출하기 위한 `submit` 타입의 `<button>` 이 포함되어 있습니다. 이를 폼 가장 아래에 추가해주세요.

```html
<section>
  <p>
    <button type="submit">Validate the payment</button>
  </p>
</section>
```

8. 마지막으로, 폼을 완성하기 위해 닫는 `<form>` 태그를 추가해주세요.

```html
</form>
```

아래에서 완성된 폼을 확인할 수 있습니다. (GitHub에서도 확인할 수 있습니다. — payment-form.html source 와 running live를 확인 하세요):

실력을 시험해 보세요!
------------

이 글을 끝까지 읽었지만 가장 중요한 내용을 기억할 수 있나요? 이동하기 전에 Test your skills: Form structure (en-US) 를 방문해 확인 해보세요!

요약
--

이제 웹 폼을 올바르게 구조화하는 데 필요한 모든 지식을 갖게 되었습니다. 다음 기사에서는 사용자로부터 정보를 수집하기 위해 사용할 다양한 종류의 폼 위젯에 대해 자세히 알아볼 것입니다. 앞으로 몇 가지 기사에서 소개된 기능들을 자세히 다룰것 입니다.

함께 보기
-----

* A List Apart: *Sensible Forms: A Form Usability Checklist*
* 이전
* Overview: Forms
* 다음
### 고급 주제

* How to build custom form controls (en-US)
* Sending forms through JavaScript (en-US)
* Property compatibility table for form widgets (en-US)


기본 네이티브 양식 컨트롤 - Web 개발 학습하기

기본 네이티브 양식 컨트롤
==============

* 이전
* Overview: Forms
* 다음

이전 글에서는 기능적인 웹 폼 예시를 마크업하며, 일부 폼 컨트롤과 공통 구조 요소를 소개하고 접근성 모범 사례에 중점을 두었습니다. 다음에는 폼 컨트롤 또는 위젯의 기능을 자세히 살펴보고, 다양한 유형의 데이터를 수집하기 위한 모든 다른 옵션을 연구할 것입니다. 이 글에서는 웹 초기부터 모든 브라우저에서 사용 가능한 원래의 폼 컨트롤 세트를 살펴볼 것입니다.

|  |  |
| --- | --- |
| 사전 요구 사항 |
 기본 컴퓨터 지식과 기본
 HTML 이해가 필요합니다.
  |
| 목표: | 브라우저에서 사용 가능한 원래의 네이티브 양식 위젯 세트에 대해 자세히 이해하고, 이를 HTML로 구현하는 방법을 알아보십시오. |

이미 `<form>`, `<fieldset>`, `<legend>`, `<textarea>` (en-US), `<label>`, `<button>`, 그리고 `<input>` (en-US) 같은 몇 가지 양식 요소들을 만나보셨을 것입니다. 이 글에서는 다음을 다룹니다.

* 일반 입력 유형 button, checkbox, file, hidden (en-US), image (en-US), password (en-US), radio (en-US), reset (en-US), submit (en-US), 그리고 text (en-US).
* 몇 가지 속성들은 모든 양식 컨트롤에 공통적으로 적용됩니다.

**참고:** 다음 두 글에서 더욱 강력한 양식 컨트롤에 대해 다룹니다. 좀 더 고급 참조를 원하시면, HTML 양식 요소 참조와 특히 <input> 유형 (en-US) 참조를 참고하십시오.

텍스트 입력 필드
---------

텍스트 `<input>` (en-US) 필드는 가장 기본적인 양식 위젯입니다. 이것은 사용자가 어떠한 종류의 데이터라도 입력하는 데 매우 편리한 방법이며, 이미 몇 가지 간단한 예제를 보셨을 것입니다.

**참고:** HTML 양식 텍스트 필드는 간단한 일반 텍스트 입력 컨트롤입니다. 이는 풍부한 텍스트 편집(볼드체, 이탤릭체 등)을 수행할 수 없다는 것을 의미합니다. 당신이 마주칠 모든 리치 텍스트 편집기는 HTML, CSS, 그리고 JavaScript로 만들어진 사용자 정의 위젯입니다.

모든 기본 텍스트 컨트롤은 몇 가지 공통 행동을 공유합니다.

* `readonly` (en-US)로 표시될 수 있습니다(사용자는 입력 값을 수정할 수 없지만, 나머지 양식 데이터와 함께 전송됩니다) 또는 `disabled` (en-US) (입력 값은 수정할 수 없고, 나머지 양식 데이터와 함께 전송되지 않습니다).
* `placeholder` (en-US)를 가질 수 있습니다. 이는 텍스트 입력 상자 안에 나타나는 텍스트로, 텍스트 입력 상자의 목적을 간략하게 설명하는 데 사용되어야 합니다.
* `size` (en-US) (상자의 물리적 크기)와 `maxlength` (en-US) (상자에 입력할 수 있는 최대 문자 수)에서 제한될 수 있습니다.
* 브라우저가 지원하는 경우 철자 검사를 받을 수 있습니다(`spellcheck` 속성 사용).

**참고:** `<input>` (en-US) 요소는 입력 유형에 따라 여러 가지 형태를 취할 수 있기 때문에 HTML 요소 중에서 유일합니다. 단일 줄 텍스트 필드, 시간 및 날짜 컨트롤, 텍스트 입력 없는 컨트롤(예: 체크박스, 라디오 버튼, 색상 선택기) 및 버튼을 포함한 대부분의 양식 위젯을 생성하는 데 사용됩니다.

### 단일 줄 텍스트 필드

단일 줄 텍스트 필드는 `type` 속성 값이 `text`로 설정된 `<input>` (en-US) 요소를 사용하여 만들어집니다. 또는 `type` 속성을 전체적으로 생략하여 (`text`는 기본값입니다) 생성할 수 있습니다. `type` 속성에 지정한 값이 브라우저에서 알 수 없는 경우 (`type="color"`를 지정하고 브라우저가 기본 색상 선택기를 지원하지 않는 경우) 이 속성의 값 `text`는 대체 값이 됩니다.

**참고:** 모든 단일 줄 텍스트 필드 유형의 예제는 GitHub에서 single-line-text-fields.html에서 확인할 수 있습니다. (라이브 데모도 확인하세요).

다음은 기본 단일 줄 텍스트 필드 예제입니다.

```html
<input
 type="text"
 id="comment"
 name="comment"
 value="저는 텍스트 필드입니다." />
```

단일 줄 텍스트 필드에는 하나의 제약만 있습니다. 줄 바꿈이 있는 텍스트를 입력하면 브라우저는 해당 데이터를 서버로 전송하기 전에 줄 바꿈을 제거합니다.

### 비밀번호 필드

원래의 입력 유형 중 하나는 `password` 텍스트 필드 유형입니다.

```html
<input type="password" id="pwd" name="pwd" />
```

`password` 값은 입력된 텍스트에 특별한 제약 조건을 추가하지 않지만, 필드에 입력된 값을 은폐합니다(예: 점 또는 별표로) 다른 사람이 쉽게 읽을 수 없습니다.

이것은 단순히 사용자 인터페이스 기능일 뿐입니다. 양식을 안전하게 제출하지 않으면 데이터는 일반 텍스트로 전송되므로 보안에 좋지 않습니다. 악의적인 당사자가 데이터를 가로채어 비밀번호, 신용카드 정보 또는 제출한 기타 내용을 훔칠 수 있습니다. 이로부터 사용자를 보호하는 가장 좋은 방법은 보안 연결(즉, `https://` 주소에 위치한)을 통해 양식과 관련된 모든 페이지를 호스팅하는 것입니다. 그러면 데이터가 전송되기 전에 암호화됩니다.

브라우저는 안전하지 않은 연결을 통해 양식 데이터를 전송하는 것의 보안 문제를 인식하며, 사용자가 안전하지 않은 양식을 사용하지 않도록 경고합니다. Firefox에서 구현하는 내용에 대한 자세한 내용은 Insecure passwords를 참조하세요.

### 숨겨진 컨텐츠

또 다른 원래의 텍스트 컨트롤은 `hidden` 입력 유형입니다. 이것은 사용자에게 보이지 않는 양식 컨트롤을 만드는 데 사용됩니다. 그러나 제출된 양식 데이터와 함께 서버로 전송됩니다. 예를 들어 주문이 접수되었을 때 서버에 타임스탬프를 제출하려고 할 수 있습니다. 숨겨져 있기 때문에 사용자는 값을 볼 수 없고 의도적으로 편집할 수 없으며 포커스를 받지 않으며 스크린 리더도 이를 인식하지 않습니다.

```html
<input type="hidden" id="timestamp" name="timestamp" value="1286705410" />
```

이러한 요소를 만들려면 `name` 및 `value` 속성을 설정해야 합니다. 값은 JavaScript를 통해 동적으로 설정할 수 있습니다. `hidden` 입력 유형에는 관련 레이블이 없어야 합니다.

다른 텍스트 입력 유형, 예를 들면 search (en-US), url (en-US), 그리고 tel (en-US)은 다음 자습서인 HTML5 입력 유형에서 다룰 것입니다.

체크 가능한 항목: 체크박스와 라디오 버튼
-----------------------

체크 가능한 항목은 클릭하여 또는 관련 레이블을 클릭하여 상태를 변경할 수 있는 컨트롤입니다. 체크 가능한 항목에는 체크박스와 라디오 버튼 두 가지 유형이 있습니다. 둘 다 기본적으로 위젯이 체크되어 있는지 여부를 나타내는 `checked` 속성을 사용합니다.

이러한 위젯이 다른 양식 위젯과 정확히 같은 방식으로 동작하지 않는 것은 주목할 만한 사실입니다. 대부분의 양식 위젯의 경우, 양식이 제출되면 `name` (en-US) 속성을 가진 모든 위젯이 전송됩니다. 값을 입력하지 않아도 마찬가지입니다. 체크 가능한 항목의 경우, 체크되어 있으면 값만 전송됩니다. 이름조차도 체크되어 있지 않으면 아무것도 전송되지 않습니다, 값이 없지만 체크되어 있으면 이름이 *on* 값과 함께 전송됩니다.

### 체크박스

체크박스는 `<input>` (en-US) 요소를 사용하여 생성되며, 그 `type` (en-US) 속성 값은 checkbox로 설정됩니다.

```html
<input type="checkbox" id="questionOne" name="subscribe" value="yes" checked />
```

관련 체크박스 항목은 동일한 `name` (en-US) 속성을 사용해야 합니다. `checked` 속성을 포함하면 페이지가 로드될 때 체크박스가 자동으로 체크됩니다. 체크박스를 클릭하거나 관련 레이블을 클릭하면 체크박스가 켜고 꺼집니다.

### 라디오 버튼

라디오 버튼은 `type` (en-US) 속성 값이 `radio`로 설정된 `<input>` (en-US) 요소를 사용하여 생성됩니다.

```html
<input type="radio" id="soup" name="meal" value="soup" checked />
```

여러 라디오 버튼을 함께 연결할 수 있습니다. 그들이 `name` (en-US) 속성의 동일한 값을 공유하면, 그들은 동일한 버튼 그룹에 있다고 간주됩니다. 주어진 그룹의 버튼 중 하나만 한 번에 체크될 수 있습니다. 이는 그 중 하나가 체크되면 다른 모든 것이 자동으로 체크 해제된다는 것을 의미합니다.

실제 버튼
-----

라디오 버튼은 이름에도 불구하고 실제 버튼이 아닙니다. 실제 버튼을 살펴보겠습니다! 세 가지 입력 유형이 버튼을 생성합니다.

`submit`

양식 데이터를 서버로 전송합니다. `<button>` 요소의 경우, `type` 속성을 생략하거나 `type`의 잘못된 값은 제출 버튼으로 간주됩니다.

`reset`

모든 양식 위젯을 기본 값으로 재설정합니다.

`button`

자동 효과가 없는 버튼이지만 JavaScript 코드를 사용하여 사용자 정의할 수 있습니다.

그리고 우리는 `<button>` 요소 그 자체를 가지고 있습니다. 이는 위에서 언급한 세 가지 `<input>` 유형의 동작을 흉내내기 위해 `submit`, `reset`, 또는 `button` 값의 `type` 속성을 가질 수 있습니다. 두 요소 사이의 주요 차이점은 실제 `<button>` 요소가 스타일을 적용하기가 훨씬 쉽다는 것입니다.

버튼은 사용자가 `<button>` 요소를 사용하던지 `<input>` (en-US) 요소를 사용하던지 항상 동일하게 동작합니다. 그러나 예제에서 볼 수 있듯이, `<button>` 요소는 내용에 HTML을 사용할 수 있게 해줍니다. 이 내용은 여는 `<button>` 태그와 닫는 `<button>` 태그 사이에 삽입됩니다. 반면에 `<input>` (en-US) 요소는 void elements입니다. 따라서 표시된 내용은 `value` 속성 내부에 삽입되며, 내용으로 일반 텍스트만 허용됩니다.

**이미지 버튼** 컨트롤은 사용자가 클릭하면 제출 버튼처럼 동작하는 것을 제외하고는 `<img>` 요소와 정확히 똑같이 렌더링됩니다.

이미지 버튼은 `type` (en-US) 속성 값이 `image`로 설정된 `<input>` (en-US) 요소를 사용하여 생성됩니다. 이 요소는 `<img>` 요소가 지원하는 동일한 속성 집합을 지원하며, 다른 양식 버튼이 지원하는 모든 속성도 지원합니다.

만약 이미지 버튼이 양식을 제출하는 데 사용된다면, 이 컨트롤은 그 값을 제출하지 않습니다. 대신 이미지에 클릭된 X와 Y 좌표가 제출됩니다(좌표는 이미지에 상대적으로, 즉 이미지의 왼쪽 상단 모서리는 좌표 (0, 0)을 나타냅니다). 좌표는 두 개의 키/값 쌍으로 전송됩니다:

* X 값 키는 `name` (en-US) 속성의 값 뒤에 문자열 "*.x*"가 붙은 것입니다.
* Y 값 키는 `name` (en-US) 속성의 값 뒤에 문자열 "*.y*"가 붙은 것입니다.

예를 들어 이미지의 좌표 (123, 456)에서 클릭하여 `get` 방식으로 제출하면, URL에 다음과 같이 값이 추가되어 표시됩니다.

```url
http://foo.com?pos.x=123&pos.y=456
```

이것은 "핫 맵"을 구성하는 매우 편리한 방법입니다. 이러한 값들이 어떻게 전송되고 검색되는지에 대한 자세한 내용은 양식 데이터 보내기 (en-US) 글에서 확인할 수 있습니다.

파일 선택기
------

마지막으로 초기 HTML에서 우리에게 제공된 `<input>` 유형이 하나 있습니다. 파일 입력 유형. 양식은 서버로 파일을 전송할 수 있습니다. 파일 선택기 위젯은 전송할 하나 이상의 파일을 선택하는 데 사용될 수 있습니다.

`<input>` (en-US) 요소의 `type` (en-US) 속성 값을 `file`로 설정하여 파일 선택기 위젯을 만듭니다. `accept` (en-US) 속성을 사용하여 허용되는 파일의 유형을 제한할 수 있습니다. 또한 사용자가 여러 파일을 선택하도록 허용하려면 `multiple` (en-US) 속성을 추가하면 됩니다.

### 예시

이 예시에서는 그래픽 이미지 파일을 요청하는 파일 선택기를 생성합니다. 이 경우 사용자는 여러 파일을 선택할 수 있습니다.

```html
<input type="file" name="file" id="file" accept="image/\*" multiple />
```

일부 모바일 기기에서는 `accept` 속성에 캡처 정보를 추가함으로써 파일 선택기가 기기의 카메라와 마이크로 직접 캡처한 사진, 비디오 및 오디오에 액세스 할 수 있습니다.

```html
<input type="file" accept="image/\*;capture=camera" />
<input type="file" accept="video/\*;capture=camcorder" />
<input type="file" accept="audio/\*;capture=microphone" />
```

공통 속성
-----

폼 컨트롤을 정의하는데 사용되는 많은 요소들은 고유한 특정 속성들을 가지고 있습니다. 그러나 모든 폼 요소에 공통으로 적용되는 속성들이 있습니다. 아래에는 이미 알고 있는 것들을 포함한 그러한 공통 속성들의 목록이 있습니다.

| 속성 이름 | 기본 값 | 설명 |
| --- | --- | --- |
| autofocus (en-US) | false | 이 부울 속성은 페이지가 로드될 때 요소가 자동으로 입력 포커스를 가져야 함을 지정합니다. 문서에 이 속성을 지정할 수 있는 폼 관련 요소는 하나뿐입니다. |
| disabled (en-US) | false | 이 부울 속성은 사용자가 요소와 상호 작용할 수 없음을 나타냅니다. 이 속성이 지정되지 않으면 요소는 포함하는 요소, 예를 들어, `<fieldset>`의 설정을 상속합니다. `disabled` 속성이 설정된 포함 요소가 없으면 요소는 활성화됩니다. |
| form |  | 위젯이 연결된 `<form>` 요소, 중첩되어 있지 않은 경우에 사용됩니다. 속성의 값은 같은 문서의 `<form>` 요소의 `id` 속성이어야 합니다. 이를 통해 폼 컨트롤을 다른 폼 요소 내부에 있더라도 해당 폼과 연결할 수 있습니다. |
| name (en-US) |  | 요소의 이름입니다. 이것은 폼 데이터와 함께 제출됩니다. |
| value (en-US) |  | 요소의 초기 값입니다. |

실력을 시험해 보세요!
------------

이 글의 끝에 도달했지만, 가장 중요한 정보를 기억하고 있나요? 이 정보를 기억하고 있는지 확인하기 위한 추가 테스트를 찾을 수 있습니다 — 지식 테스트: 기본 컨트롤 (en-US)를 참조하세요.

요약
--

이 글은 모든 브라우저에서 잘 지원되는 HTML 초기 시절에 도입된 원래의 입력 유형들을 다루었습니다. 다음 섹션에서는 `type` 속성의 더 현대적인 값들을 살펴볼 것입니다.

* 이전
* Overview: Forms
* 다음
### 고급 주제

* How to build custom form controls (en-US)
* Sending forms through JavaScript (en-US)
* Property compatibility table for form widgets (en-US)


나의 첫 HTML 폼 - Web 개발 학습하기

나의 첫 HTML 폼
===========

이 문서는 HTML 폼 소개 문서입니다. 간단한 폼들을 살펴보면서 HTML 폼을 만들기에 대한 기본적인 필요 사항들을 볼 수 있을 것이다. 이 문서는 HTML폼에 대해서는 아무것도 몰라도 되지만 다음 문서에 나와 있는 기본적인 HTML이나 CSS를 알아야 한다. (the basics of HTML, CSS)

시작하기전에
------

### HTML 폼 이란?

HTML폼은 사용자와 웹사이트 또는 어플리케이션이 서로 상호 작용하는 것 중 중요한 기술 중에 하나이다. 폼은 사용자가 웹사이트에 데이터를 전송하는 것을 허용한다. 일반적으로 데이터는 웹 서버로 전송되지만 웹페이지가 데이터를 사용하기 위하여 사용할 수 도 있다.

HTML 폼은 하나 이상의 위젯으로 만들어 진다. 이러한 위젯들은 텍스트 필드(한줄 또는 여러줄), 셀렉 박스, 버튼, 체크박스, 라디오 버튼이 될 수 있다. 대부분 이러한 위젯들은 위젯을 설명하는 라벨과 함께 사용된다.

### 폼을 사용하려면 무엇이 필요합니까?

HTML을 다루기 위한 텍스트 에디터나 웹 브라우저외는 아무것도 필요 없습니다. 물론 비주얼 스튜디오, 이클립트, 앱타나 등 통합개발환경(IDE)을 사용하면 많은 이점이 있지만 이것은 만드는 사람 마음이다.

HTML 폼과 일반적인 HTML 요소의 주요 차이점은 폼에 의해 수집된 데이터는 대부분 웹서버에 전송된다는 점이다. 이런 경우 데이터를 받거나 처리하는 웹서버를 설정해야한다. 웹서버를 설정하는 방법은 이 문서의 범위를 벗어나지만 알고 싶다면 다음 문서를 참조 하시오 Sending and retrieving form data (en-US).

폼 디자인하기
-------

코드를 보기전에 항상 잠시 뒤로 물러나 폼에 대하여 생각하는 것이 더 중요하다. 간단한 모형을 디자인 하는것은 개발자가 사용자에게 묻고 싶은 데이터를 올바르게 정의하는데 도움을 준다. 사용자 경험 (UX)의 관점에서 폼이 많을수록 사용자들이 더 줄어든다는 사실을 기억하는게 중요하다. 반드시 필요한것이 무엇인지 생각하면서 간단하게 유지하는 것이 중요하다. 폼 디자인은 사이트나 어플리케이션을 만드는 과정 중 중요한 단계이다. 폼들의 디자인은 이 문서의 범위를 벗어나지만 만약 더 자세하게 알고 싶은 경우 다음 문서를 참조 하세요.

* Smashing는 폼 UX에 매우 좋은 잡지다 good articles about forms UX의 Extensive Guide To Web Form Usability.
* UXMatters 도 좋은 폼 양식을 볼수 있다. basic best practices 의 multi-page forms.

이 문서에서는 간단한 문의를 하는 폼을 만들것이다. 거칠게 스케치 해보자.

![The form to build, roughly sketch](/files/4579/form-sketch-low.jpg)

우리가 만들 폼은 3개의 텍스트 필드와 하나의 버튼을 가지고 있다. 기본적으로 우리는 사용자에게 이름, 이메일, 문의사항을 물어 볼 것이고 버튼을 눌러서 웹서버로 데이터를 보내는게 목적이다.

HTML를 직접 다루어 보자
---------------

자 이제 HTML에가서 폼을 코딩 할 준비가 되었다. 우리의 문의하는 폼에서 다음과 같은 HTML 요소들을 사용할 것이다. `<form>`, `<label>`, `<input>` (en-US), `<textarea>` (en-US), and `<button>`.

### `<form>` 요소

모든 HTML 폼은 `<form>` 요소로 다음과 같이 시작된다:

```html
<form action="/my-handling-form-page" method="post"></form>
```

이 요소는 폼의 공식적인 형태이다. 이 요소는 다음 `<div>` (en-US) 나 `<p>` 요소와 같이 사용되고,뿐만 아니라 폼이 동작하는 방식을 설정하는 일부 속성들을 지정 해야한다. 이러한 모든 속성은 선택적이지만 `action` 속성과 `method` 속성은 필수적으로 설정해야 한다.

* `action` 속성은 데이터를 보낼 URL을 지정한다.
* `method` 속성은 어떤 HTTP 방식을 사용할 것인지 지정한다.(GET 이나 POST)

만약 이러한 속성에 더 자세한 내용을 알고 싶다면 다음 문서를 참조하시오. Sending and retrieving form data (en-US).

### `<label>`, `<input>` (en-US), 그리고 `<textarea>` (en-US) 요소 추가하기

우리의 문의하는 폼은 정말 간단하고 라벨을 가지고 있는 세 개의 텍스트필드를 가지고 있다. 이름을 입력 받는 입력 필드는 한줄 텍스트 필드를 사용하고, 이메일을 입력 받는 입력 필드는 이메일만 입력받는 한줄 텍스트 필드를 사용하고, 문의 내용을 입력받는 입력 필드는 다중 라인 텍스트 필드가 사용 될것이다.

HTML코드를 다음과 같이 짤 것이다.

```html
<form action="/my-handling-form-page" method="post">
  <div>
    <label for="name">Name:</label>
    <input type="text" id="name" />
  </div>
  <div>
    <label for="mail">E-mail:</label>
    <input type="email" id="mail" />
  </div>
  <div>
    <label for="msg">Message:</label>
    <textarea id="msg"></textarea>
  </div>
</form>
```

`<div>` (en-US) 요소는 코드를 편리하게 구성하고 스타일링 쉽게 만들어 줍니다. 중요한 점은 for속성은 모든`<label>` 요소에서 공식적으로 폼 위젯과 라벨을 연결하는데 사용된는 것이다. 이 속성은 위젯에 맞는 ID를 참조한다. 이 것은 몇 가지 장점이 있다. 가장 두드러 지는 것은 사용자가 라벨을 눌럿을때 그거에 맞는 위젯을 활성화 시키는 것이다.만약 이 속성에 대한 장점을 더 알고 싶다면 다음 문서에 자세히 나와있다. How to structure an HTML form (en-US).

`<input>` (en-US) 요소의 가장 중요한 속성은 type 속성이다. 이 속성은 `<input>` (en-US) 요소가 어떻게 입력을 받을 것인지 정의하기 떄문에 매우 중요하다. 이것은 아예 요소를 변경하기 떄문에 주의 해야한다. 만약 이것에 대하여 더 자세한 정보를 알고 싶다면 다음 문서를 참조 하라. native form widgets (en-US) 우리의 예제에서는 이 속성의 기본 값인 오직 text값만 사용했다. 이 값은 제어나 유효성 검사 없이 모든 종류의 텍스트를 받아 들이는 한줄 텍스트 필드를 나타낸다. 또한 오직 이메일 주소만 받는 한줄 텍스트 필드 email값을 사용했다. 이 마지막 값은 기본 텍스트 필드를 사용자가 입력 한 데이터에 대한 몇 가지 검사를 수행하는 "지능형"필드의 종류로 전환한다. 만약 폼 데이터 유효성 확인에 대하여 자세히 알고싶다면 다음 문서를 참조 해라. Form data validation (en-US)

마지막 요소를 보기전에 다음 `<input />` VS `<textarea></textarea>요소를 봐야한다`. 이것은 이상한 HTML 요소중 하나이다. `<input>태그는 자동 닫힘 태그다 무슨 의미냐면` 요소가 끝날떄 반드시 "/"닫는 태그에 추가해야 하는 것을 의미한다. 이와 반대로, `<textarea>` (en-US)은 자동 닫힘 태그가 아니다 그래서 반드시 엔딩태그를 사용하여 요소를 종료해야한다. 이 것은 기본 값을 정의하는 특정 기능에 영향을 미친다. 요소의 기본 값 정의는 반드시 value 속성을 다음과 같이 지정 해야 한다.

```html
<input type="text" value="by default this element is filled with this text" />
```

이와 반대로 `<textarea>` (en-US)요소 에서 기본값을 정의하고 싶다면, `<textarea>` (en-US)요소의 시작 태그와 끝 태그 사이에 문자들을 다음과 같이 입력 하면된다.

```html
<textarea>by default this element is filled with this text</textarea>
```

### `<button>` 요소로 끝내기

우리의 폼이 거의 완성되간다. 이제 단지 사용자 데이터를 서버에 보낼수 있도록 버튼을 추가하면된다. 이것은 간단하게 `<button>` 요소를 사용한다.

```html
<form action="/my-handling-form-page" method="post">
  <div>
    <label for="name">Name:</label>
    <input type="text" id="name" />
  </div>
  <div>
    <label for="mail">E-mail:</label>
    <input type="email" id="mail" />
  </div>
  <div>
    <label for="msg">Message:</label>
    <textarea id="msg"></textarea>
  </div>

  <div class="button">
    <button type="submit">Send your message</button>
  </div>
</form>
```

버튼은 다음과 같은 3개 종류가 있다. `submit`, `reset`, `button`.

* submit 버튼을 클릭하면 폼 데이터를 `<form>` 요소의 action속성에 정의된 웹페이지 에 전송된다.
* `reset` 버튼을 클릭하면 모든 폼 위젯을 기본 값으로 바꾼다. UX 관점에서 이방법은 안좋은 방법이라 본다.
* `button 버튼은... 아무것도 안한다! 이 말이 이상하게 들릴수도 있지만 JavaScript를 사용하면 놀랍게 유용한 사용자 버튼이 될 수 있다.`

알아두어야 할것은 `<input>` (en-US) 요소를 사용하여 버튼 유형을 만들 수 있다. `<button>`요소와 가장 큰 차이점은 `<input>` (en-US)요소는 오직 일반 텍스트만 보내는 반면 `<button>`요소는 전체 HTML 콘텐츠를 보낸다.

CSS로 더욱 나이스하게 만들기
-----------------

이제 우리는 HMLT폼을 가졋지만 가지고 있는 브라우저에서 보면 구리게 보인다.

![](/files/4049/form-no-style.png)

CSS 스타일시트를 이용하여 조금만더 나이스하게 만들어 보자.

폼을 가운데로 정렬하고 테두리를 보이게 하는것 부터 시작하자.

```css
form {
  /\* Just to center the form on the page \*/
  margin: 0 auto;
  width: 400px;
  /\* To see the outline of the form \*/
  padding: 1em;
  border: 1px solid #ccc;
  border-radius: 1em;
}
```

그 다음 각각 폼 위젯사이에 여백을 추가하자.

```css
form div + div {
  margin-top: 1em;
}
```

이제 레이블에 초점을 맞추자. 우리의 폼을 더 읽기 쉽게 만들기 위해 모든 라벨들이 같은 사이즈와 같은 쪽을 정렬이 되게하자. 이 경우 오른쪽 정렬을 하지만 경우에 따라서 왼쪽 정렬도 좋을 수 있다.

```css
label {
  /\* To make sure that all label have the same size and are properly align \*/
  display: inline-block;
  width: 90px;
  text-align: right;
}
```

HTML 폼을 다루는 가장 어려운 것중 하나는 HTML자체를 위젯으로 스타일 하는 것이다. 텍스트 필드는 쉽게 스타일 할수 있지만 다른 위젯들은 아니다. 만약 HTML 폼 위젯 스타일에 대하여 자세한 정보를 알고 싶으면 다음 문서를 참조하시오. Styling HTML forms (en-US)

폰트, 크기, 테두리를 변경 해보자

```css
input,
textarea {
  /\* To make sure that all text fields have the same font settings
 By default, textareas have a monospace font \*/
  font: 1em sans-serif;

  /\* To give the same size to all text field \*/
  width: 300px;
  -moz-box-sizing: border-box;
  box-sizing: border-box;

  /\* To harmonize the look & feel of text field border \*/
  border: 1px solid #999;
}
```

HTML 폼은 요소의 상태를 나타내는 많은 가상클래스 를 지원한다.예르들어 위젯이 활성화 되면 하이라이트 효과를 추가할 수있다. 이것은 사용자가 쉽게 따라가도록 하는 편리한 방법이다.

```css
input:focus,
textarea:focus {
  /\* To give a little highlight on active elements \*/
  border-color: #000;
}
```

다중 텍스트 필드는 몇몇 사용자 지정 스타일이 필요하다. 기본적으로 `<textarea>` (en-US)요소는 바닥이 텍스트 기준선에 정렬되는 인라인 블록 이다. 대부분 이것들은 우리가 원하는 것이 아니다. 이런 경우 나이스하게 라벨과 필드를 정렬하려면 `<textarea>` (en-US)요소의 `vertical-align` 속성을 `top이라 변경 해야 한다`.

또하나 유용한 `resize` 프로퍼티는 사용자가 쉽게 `<textarea>` (en-US)요소의 크기를 조정 할수 있게 해준다.

```css
textarea {
  /\* To properly align multiline text fields with their labels \*/
  vertical-align: top;

  /\* To give enough room to type some text \*/
  height: 5em;

  /\* To allow users to resize any textarea vertically
 It does not work on every browsers \*/
  resize: vertical;
}
```

버튼도 특별한 스타일이 필요하다. 이를 위해 우선 `<div>` (en-US)요소안에 버튼을 넣는다. 그리고 다른 위젯들과 정렬을 해야한다. 그럴러면 `<label>`요소를 흉내 내야한다. 그 후에 패딩 과 마진 속성을 지정하면된다

```css
.button {
  /\* To position the buttons to the same position of the text fields \*/
  padding-left: 90px; /\* same size as the label elements \*/
}

button {
  /\* This extra margin represent roughly the same space as the space
 between the labels and their text fields \*/
  margin-left: 0.5em;
}
```

이제 폼이 더 나이스 해졋다.

![](/files/4051/form-style.png)

웹서버로 데이터 보내기
------------

까다로울지 모르는 마지막 부분은 데이터를 서버측에서 처리하는 것이다. 앞에서 언급 된 바와 같이 HTML폼은 사용자에게 데이터를 물어보고 웹서버로 데이터를 전달하는 데 편리한 방법이다.

`<form>` 요소는 action속성과 method속성을 사용하여 데이터를 어디에 어떻게 보낼것인지 정의한다.

이걸로 충분하지않다. 데이터의 이름을 지정해야한다. 이러한 이름들은 브라우저측이나 서버 측 모두에게 중요하다. 브라우저에게는 데이터 각 부분에는 이름을 지정하고 서버측 에서는 이름을 이용하여 데이터를 다룰수 있게 해준다.

그래서 데이터의 이름을 지정하려면 데이터를 받는 각 폼 위젯에 name속성을 지정해야한다.

```html
<form action="/my-handling-form-page" method="post">
  <div>
    <label for="name">Name:</label>
    <input type="text" id="name" name="user\_name" />
  </div>
  <div>
    <label for="mail">E-mail:</label>
    <input type="email" id="mail" name="user\_email" />
  </div>
  <div>
    <label for="msg">Message:</label>
    <textarea id="msg" name="user\_message"></textarea>
  </div>

  <div class="button">
    <button type="submit">Send your message</button>
  </div>
</form>
```

우리의 예제에서는 다음과 같이 3가지 데이터 이름을 지정했다. "`user_name`", "`user_email`" and "`user_message`". 이 데이터는 "`/my-handling-form-page`"로 HTTP POST 방식으로 전송된다.

서버 측에서는 URL에서 HTTP 요청에 의해 구현된 3개의 키/벨류 항목의 목록 데이터를 받게 된다. 스크립트로 데이터를 다루는 방법은 너에게 달려있다. 각각 의 서버 측 언어들은(PHP, Python, Ruby, Java, C# 등)자신만의 방식으로 이를 다룬다. 더 깊게 들어가는 것은 이문서의 범위를 벗어나지만 더자세히 알고 싶다면 다음 문서를 참조하시오. Sending and retrieving form data (en-US).

결론
--

축하한다! 첫번째 HTML폼을 만들었다.

| Live example |
| --- |
|  |
| Check out the source code (en-US) |

하지만 이제 시작일 뿐이고, 더 깊게 파고들 시간이다. HTML폼은 이 문서에서 본 것 보다 더 강력한 도구이고, 이 가이드의 다른 문서가 나머지 내용을 배우는데 도움이 될 것이다.

* Overview: Forms
* 다음  (en-US)


HTML5 입력 유형 - Web 개발 학습하기

HTML5 입력 유형
===========

이전 글에서는 초기 HTML 시대부터 사용 가능한 `type` 속성의 원래 값을 사용하여 `<input>` (en-US) 요소를 살펴보았습니다. 이제 HTML5에서 추가된 특정 유형의 데이터 수집을 허용하기 위해 추가된 몇 가지 새로운 입력 유형을 포함하여 더 많은 폼 컨트롤의 기능에 대해 자세히 살펴보겠습니다.

|  |  |
| --- | --- |
| 필요한 사전 지식: |
 기본 컴퓨터 활용 능력과 기본적인
 HTML 이해가 필요합니다.
  |
| 목표: | HTML을 사용하여 구현하는 방법을 포함하여 사용 가능한 새로운 입력 유형 값에 대한 이해를 얻습니다. |

**참고:** 이 글에서 다루는 대부분의 기능은 브라우저 간에 다양하게 지원됩니다. 예외 사항은 알려 드리겠습니다. 브라우저 지원에 대한 자세한 내용을 원하신다면, HTML 폼 요소 참조 및 특히 상세한 <input> 유형 (en-US) 참조를 참고하십시오.

웹 개발자들은 때때로 사용자 지정 폼 컨트롤을 만들기 위해 HTML 폼 컨트롤 외관을 디자인 사양과 다르게 만들기도 합니다. 우리는 고급 튜토리얼에서 이것을 다룹니다. 사용자 정의 폼 위젯 만들기 (en-US).

이메일 주소 필드
---------

이 유형의 필드는 `type` (en-US) 속성의 값으로 `email`을 사용하여 설정됩니다.

```html
<input type="email" id="email" name="email" />
```

이 `type` (en-US)을 사용하면 사용자는 필드에 유효한 이메일 주소를 입력해야 합니다. 그렇지 않은 경우 브라우저는 폼이 제출될 때 오류를 표시합니다. 아래 스크린샷에서 이것을 확인할 수 있습니다.

![유효하지 않은 이메일 입력에 "이메일 주소를 입력하세요."라는 메시지가 표시됩니다.](/ko/docs/Learn/Forms/HTML5_input_types/email_address_invalid.png)

`email` 입력 유형과 함께 `multiple` (en-US) 속성을 사용하여 동일한 입력에서 여러 이메일 주소를 입력하도록 허용할 수도 있습니다(쉼표로 구분됨).

```html
<input type="email" id="email" name="email" multiple />
```

일부 장치에서 — 특히 동적 키보드가 있는 터치 장치인 스마트폰과 같은 장치에서 — `@` 키를 포함하여 이메일 주소를 입력하기에 더 적합한 다른 가상 키보드가 제공될 수 있습니다. 아래의 Firefox for Android 키보드 스크린샷은 예시입니다:

![기본적으로 at 기호가 표시되는 Firefox for Android 이메일 키보드.](/ko/docs/Learn/Forms/HTML5_input_types/fx-android-email-type-keyboard.jpg)

**참고:** 기본 텍스트 입력 유형의 예제는 기본 입력 예제에서 찾을 수 있습니다(또한 소스 코드도 확인해보세요).

여러 디바이스에서 사용자 경험을 향상시킨다는 점에서 이러한 새로운 입력 유형을 사용하는 또 다른 좋은 이유입니다.

### 클라이언트 측 유효성 검사

위에서 볼 수 있듯이, `email`은 클라이언트 측 오류 유효성 검사를 제공하는 다른 새로운 `input` 유형 중 하나입니다. 이는 데이터가 서버로 전송되기 전에 브라우저에서 수행됩니다. 이것은 사용자가 정확하게 폼을 작성하도록 안내하는 유용한 도움말입니다. 클라이언트 측 유효성 검사는 너무 쉽게 끄기 때문에 악의적인 사용자가 여전히 나쁜 데이터를 서버로 쉽게 전송할 수 있습니다.

하지만 이것은 광범위한 보안 조치로 간주되어서는 안됩니다. 당신의 앱은 항상 *서버 측*에서도 어떠한 폼 제출된 데이터에 대한 보안 검사를 수행해야 합니다. 웹사이트 보안 (en-US)에서 무엇이 발생할 수 있는지에 대한 아이디어를 읽어보세요. 서버 측 유효성 검사를 구현하는 것은 이 모듈의 범위를 다소 벗어나지만, 이것을 기억해두어야 합니다.

`a@b`는 제공된 기본 제약 조건에 따라 유효한 이메일 주소입니다. 이는 `email` 입력 유형이 기본적으로 인트라넷 이메일 주소를 허용하기 때문입니다. 다른 유효성 검사 동작을 구현하려면 `pattern` (en-US) 속성을 사용할 수 있으며, 오류 메시지도 사용자 정의할 수 있습니다. 이러한 기능을 어떻게 사용하는지에 대한 내용은 나중에 클라이언트 측 폼 유효성 검사 (en-US) 글에서 다룰 것입니다.

**참고:** 입력된 데이터가 이메일 주소가 아닌 경우, `:invalid` (en-US) 의사 클래스가 일치하며, `validityState.typeMismatch` (en-US) 속성은 `true`를 반환합니다.

검색 필드
-----

검색 필드는 페이지와 앱에서 검색 상자를 생성하기 위해 사용됩니다. 이 유형의 필드는 `type` (en-US) 속성의 값으로 `search`를 사용하여 설정됩니다.

```html
<input type="search" id="search" name="search" />
```

`text` 필드와 `search` 필드의 주요 차이점은 브라우저가 어떻게 그것의 외관을 스타일링하는지입니다. 대개 `search` 필드는 둥근 모서리로 렌더링되며, 때로는 클릭하면 필드의 값을 지우는 "Ⓧ"도 표시됩니다. 또한 동적 키보드가 있는 장치에서 키보드의 엔터 키는 "검색"이라고 읽히거나 돋보기 아이콘을 표시할 수 있습니다.

아래 스크린샷은 macOS에서의 Firefox 71, Safari 13 및 Chrome 79, 그리고 Windows 10에서의 Edge 18 및 Chrome 79에서 비어 있지 않은 검색 필드를 보여줍니다. 필드에 값이 있으면 지우기 아이콘만 표시되며, Safari를 제외하고는 필드에 포커스가 있을 때만 표시됩니다.

![여러 플랫폼에서의 검색 필드 스크린샷.](/ko/docs/Learn/Forms/HTML5_input_types/search_focus.png)

또 다른 주목할 만한 특징은 검색 필드의 값이 자동으로 저장되어 동일한 웹사이트의 여러 페이지 간에 자동 완성을 제공할 수 있다는 것입니다. 이것은 대부분의 현대 브라우저에서 자동으로 발생하는 경향이 있습니다.

전화번호 필드
-------

`tel`을 `type` (en-US) 속성의 값으로 사용하여 전화 번호를 입력하기 위한 특별한 필드를 생성할 수 있습니다.

```html
<input type="tel" id="tel" name="tel" />
```

동적 키보드가 있는 터치 장치로 액세스하면 대부분의 장치에서 `type="tel"`이 발견될 때 숫자 키보드가 표시됩니다. 이 의미는 이 유형이 전화 번호에만 사용되지 않고 숫자 키보드가 유용할 때마다 사용될 수 있다는 것입니다.

아래의 Firefox for Android 키보드 스크린샷은 예시입니다.

![기본적으로 앰퍼샌드가 표시되는 Firefox for Android 이메일 키보드.](/ko/docs/Learn/Forms/HTML5_input_types/fx-android-tel-type-keyboard.jpg)

전화 번호 형식의 다양성 때문에 이 유형의 필드는 사용자가 입력한 값에 대해 어떠한 제약도 강제하지 않습니다(즉, 문자 등을 포함할 수 있습니다).

앞서 언급했듯이, `pattern` (en-US) 속성을 사용하여 제약을 적용할 수 있으며, 클라이언트 측 폼 유효성 검사 (en-US)에서 이에 대해 알아볼 수 있습니다.

URL 필드
------

URL을 입력하기 위한 특별한 유형의 필드는 `type` (en-US) 속성의 값으로 `url`을 사용하여 생성할 수 있습니다.

```html
<input type="url" id="url" name="url" />
```

이것은 필드에 특별한 유효성 검사 제약을 추가합니다. 프로토콜(예: `http:`)이 입력되지 않거나 URL이 잘못된 경우 브라우저는 오류를 보고합니다. 동적 키보드가 있는 장치에서 기본 키보드는 일반적으로 콜론, 마침표 및 슬래시 중 하나 또는 모든 것을 기본 키로 표시합니다.

아래에 예시를 확인해보세요 (Firefox for Android에서 촬영).

![기본적으로 앰퍼샌드가 표시되는 Firefox for Android 이메일 키보드.](/ko/docs/Learn/Forms/HTML5_input_types/fx-android-url-type-keyboard.jpg)

**참고:** URL이 제대로 형성되었다는 것은 반드시 그것이 실제로 존재하는 위치를 가리킨다는 것을 의미하지 않습니다!

숫자 필드
-----

숫자를 입력하기 위한 컨트롤은 `<input>` (en-US) `type` (en-US)을 `number`로 사용하여 생성할 수 있습니다. 이 컨트롤은 텍스트 필드와 유사하게 보이지만 부동 소수점 숫자만 허용하며, 일반적으로 컨트롤의 값을 증가시키고 감소시키는 스피너 형태의 버튼을 제공합니다. 동적 키보드가 있는 장치에서는 숫자 키보드가 일반적으로 표시됩니다.

아래의 스크린샷(From Firefox for Android)은 예시입니다.

![기본적으로 앰퍼샌드가 표시되는 Firefox for Android 이메일 키보드.](/ko/docs/Learn/Forms/HTML5_input_types/fx-android-number-type-keyboard.jpg)

숫자 입력 유형과 함께, `min` (en-US) 및 `max` (en-US) 속성을 설정하여 허용되는 최소 및 최대 값을 제한할 수 있습니다.

또한 스피너 버튼을 눌렀을 때 증가 및 감소를 야기하는 증가량을 설정하기 위해 `step` 속성을 사용할 수 있습니다. 기본적으로 숫자 입력 유형은 숫자가 정수인 경우에만 유효성을 검사합니다. 부동 소수점 숫자를 허용하려면 `step="any"` (en-US)를 지정합니다. 생략하면 `step` 값은 기본적으로 `1`로 설정되어, 오직 전체 숫자만 유효합니다.

이것을 알아보기 위해 몇 가지 예를 살펴보겠습니다. 아래의 첫 번째 예는 값이 `1`에서 `10` 사이의 임의의 값으로 제한되며, 증가 및 감소 버튼이 값을 `2`로 변경하는 숫자 컨트롤을 생성합니다.

```html
<input type="number" name="age" id="age" min="1" max="10" step="2" />
```

두 번째 예는 값이 `0`에서 `1` 사이의 값으로 제한되며, 증가 및 감소 버튼이 값을 `0.01`로 변경하는 숫자 컨트롤을 생성합니다.

```html
<input type="number" name="change" id="pennies" min="0" max="1" step="0.01" />
```

`number` 입력 유형은 유효한 값의 범위가 제한되어 있을 때 의미가 있습니다. 예를 들어 사람의 나이나 키 같은 것입니다. 범위가 너무 크면 증가 분량이 의미가 없습니다(예: 미국 ZIP 코드, `00001`에서 `99999`까지의 범위). 이 경우 `tel` 유형이 더 나은 옵션일 수 있습니다. 숫자 키보드를 제공하면서 숫자의 스피너 UI 기능을 포기합니다.

슬라이더 컨트롤
--------

또 다른 방법으로 숫자를 선택하는 방법은 **슬라이더**를 사용하는 것입니다. 부동산 사이트와 같은 사이트에서는 이를 종종 볼 수 있습니다. 여기서는 필터링하기 위해 설정할 최대 부동산 가격을 선택하려고 합니다. 이것을 설명하기 위해 실시간 예제를 살펴보겠습니다.

사용법에 따라 슬라이더는 텍스트 필드보다 정확하지 않습니다. 따라서 그들은 정확한 값이 꼭 필요하지 않은 숫자를 선택하기 위해 사용됩니다.

슬라이더는 `<input>` (en-US)을 사용하여 생성되며, 그 `type` (en-US) 속성의 값은 `range`로 설정됩니다. 슬라이더 썸네일은 마우스나 터치 또는 키패드의 화살표로 이동할 수 있습니다.

슬라이더를 올바르게 구성하는 것이 중요합니다. 이를 위해, `min` (en-US), `max` (en-US), 및 `step` (en-US) 속성을 설정하는 것이 강력히 권장됩니다. 이들은 각각 최소, 최대 및 증가 값을 설정합니다.

위의 예제의 코드를 살펴보면 어떻게 하는지 알 수 있습니다. 먼저 기본 HTML부터 살펴보겠습니다.

```html
<label for="price">여름에 언제 가능하세요?</label>
<input
 type="range"
 name="price"
 id="price"
 min="50000"
 max="500000"
 step="100"
 value="250000" />
<output class="price-output" for="price"></output>
```

이 예제는 값이 `50000`에서 `500000` 사이로 범위를 제한하고, 한 번에 100씩 증가/감소하는 슬라이더를 생성합니다. `value` 속성을 사용하여 기본값을 `250000`으로 지정했습니다.

슬라이더의 문제점 중 하나는 사용자가 현재 값을 쉽게 볼 수 없다는 것입니다. 이를 해결하기 위해, 우리는 `<output>` 요소를 추가하였습니다. 이 요소는 슬라이더의 현재 값을 표시하기 위한 것입니다.

JavaScript 코드는 슬라이더의 값을 `<output>` 요소에 동기화합니다.

```javascript
const priceInput = document.querySelector("#price");
const output = document.querySelector(".price-output");

priceInput.addEventListener("input", function () {
  output.textContent = priceInput.value;
});

output.textContent = priceInput.value; // 초기 출력 값 설정
```

여기서 우리는 `range` 입력과 `output`에 대한 참조를 두 변수에 저장합니다. 그 다음에 즉시 `output`의 `textContent`를 입력의 현재 `value`로 설정합니다. 마지막으로 범위 슬라이더가 움직일 때마다 `output`의 `textContent`가 새 값으로 갱신되도록 이벤트 수신기가 설정됩니다.

**참고:** CSS Tricks에 이 주제를 다루는 멋진 튜토리얼이 있습니다. The Output Element.

날짜와 시간 선택기
----------

전통적으로 날짜와 시간 값을 수집하는 것은 웹 개발자들에게 악몽이었습니다. 좋은 사용자 경험을 위해서는 사용자가 네이티브 달력 애플리케이션으로 컨텍스트 전환을 하거나 해석하기 어려운 다양한 형식으로 입력하는 것을 필요로하지 않고 날짜를 선택할 수 있는 달력 선택 UI를 제공하는 것이 중요합니다. 예를 들어, 지난 천년의 마지막 분은 다음과 같은 다양한 방법으로 표현될 수 있습니다. 1999/12/31, 23:59 또는 12/31/99T11:59PM.

HTML 날짜 컨트롤은 이러한 특정 종류의 데이터를 처리하기 위해 제공되며, 달력 위젯을 제공하고 데이터를 균일하게 만듭니다.

날짜와 시간 컨트롤은 `<input>` (en-US) 요소와 `type` (en-US) 속성의 적절한 값을 사용하여 생성되며, 날짜, 시간 또는 둘 다를 수집하고자 하는지에 따라 다릅니다. 지원하지 않는 브라우저에서 `<select>` (en-US) 요소로 대체되는 실시간 예제가 있습니다.

다양한 유형들을 간략하게 살펴보겠습니다. 이 유형들의 사용은 상당히 복잡하며, 특히 브라우저 지원을 고려할 때입니다(아래 참조); 전체 세부 사항을 알아보려면 아래 링크를 따라 각 유형의 참조 페이지로 이동하세요.

### `datetime-local`

`<input type="datetime-local">` (en-US)은 특정 시간대 정보 없이 날짜와 시간을 표시하고 선택하는 위젯을 생성합니다.

```html
<input type="datetime-local" name="datetime" id="datetime" />
```

### `month`

`<input type="month">` (en-US)은 연도와 함께 달을 표시하고 선택하는 위젯을 생성합니다.

```html
<input type="month" name="month" id="month" />
```

### `time`

`<input type="time">` (en-US)은 시간 값을 표시하고 선택하는 위젯을 생성합니다. 시간은 12시간 형식으로 *표시*될 수 있지만, 반환되는 *값*은 24시간 형식입니다.

```html
<input type="time" name="time" id="time" />
```

### `week`

`<input type="week">` (en-US)은 주 번호와 그 해를 표시하고 선택하는 위젯을 생성합니다.

주는 월요일부터 시작하여 일요일까지 진행됩니다. 또한, 각 해의 첫 번째 주 1은 해당 해의 첫 번째 목요일을 포함합니다. 이는 연초의 첫 날을 포함하지 않을 수도 있고, 이전 해의 마지막 며칠을 포함할 수도 있습니다.

```html
<input type="week" name="week" id="week" />
```

### 날짜/시간 값 제한

모든 날짜와 시간 컨트롤은 `min` (en-US)과 `max` (en-US) 속성을 사용하여 제한될 수 있으며, `step` (en-US) 속성을 통해 추가 제한이 가능합니다(값은 입력 유형에 따라 다릅니다).

```html
<label for="myDate">여름에 언제 가능하세요?</label>
<input
 type="date"
 name="myDate"
 min="2013-06-01"
 max="2013-08-31"
 step="7"
 id="myDate" />
```

색상 선택기 컨트롤
----------

색상은 항상 조금 어려운 편입니다. 여러 가지 방법으로 표현할 수 있습니다. RGB 값(십진수 또는 16진수), HSL 값, 키워드 등등.

`color` 컨트롤은 `<input>` (en-US) 요소와 그 `type` (en-US) 속성의 값이 `color`로 설정되어 생성됩니다.

```html
<input type="color" name="color" id="color" />
```

색상 컨트롤을 클릭하면 일반적으로 운영 체제의 기본 색상 선택 기능이 표시됩니다.

다음은 시도할 수 있는 실시간 예제입니다.

반환되는 값은 항상 소문자 6자리 16진수 색상입니다.

실력을 시험해 보세요!
------------

이 글의 끝에 도달했지만 가장 중요한 정보를 기억하고 있나요? 이 정보를 기억했는지 확인하기 위한 몇 가지 추가 테스트를 찾을 수 있습니다. 다음으로 이동하기 전에 기술 테스트: HTML5 컨트롤 (en-US)을 확인하십시오.

요약
--

이로써 HTML5 양식 입력 유형의 투어를 마치게 되었습니다. 매우 특정한 동작들 때문에 쉽게 그룹화될 수 없는 몇몇 다른 컨트롤 유형들이 있지만, 알아두면 좋습니다. 다음 글에서 그것들을 다룹니다.

### 고급 주제

* How to build custom form controls (en-US)
* Sending forms through JavaScript (en-US)
* Property compatibility table for form widgets (en-US)


Example - Web 개발 학습하기

Example
=======

HTML 폼 구성 방법의 기본 결제 폼 예제 입니다.

결제 폼
----

### HTML

```html
<form method="post">
  <h1>Payment form</h1>
  <p>
    Required fields are followed by
    <strong><span aria-label="required">*</span></strong>.
  </p>
  <section>
    <h2>Contact information</h2>
    <fieldset>
      <legend>Title</legend>
      <ul>
        <li>
          <label for="title\_1">
            <input type="radio" id="title\_1" name="title" value="A" />
            Ace
          </label>
        </li>
        <li>
          <label for="title\_2">
            <input type="radio" id="title\_2" name="title" value="K" />
            King
          </label>
        </li>
        <li>
          <label for="title\_3">
            <input type="radio" id="title\_3" name="title" value="Q" />
            Queen
          </label>
        </li>
      </ul>
    </fieldset>
    <p>
      <label for="name">
        <span>Name: </span>
        <strong><span aria-label="required">*</span></strong>
      </label>
      <input type="text" id="name" name="username" />
    </p>
    <p>
      <label for="mail">
        <span>Email: </span>
        <strong><span aria-label="required">*</span></strong>
      </label>
      <input type="email" id="mail" name="usermail" />
    </p>
    <p>
      <label for="pwd">
        <span>Password: </span>
        <strong><span aria-label="required">*</span></strong>
      </label>
      <input type="password" id="pwd" name="password" />
    </p>
  </section>
  <section>
    <h2>Payment information</h2>
    <p>
      <label for="card">
        <span>Card type:</span>
      </label>
      <select id="card" name="usercard">
        <option value="visa">Visa</option>
        <option value="mc">Mastercard</option>
        <option value="amex">American Express</option>
      </select>
    </p>
    <p>
      <label for="number">
        <span>Card number:</span>
        <strong><span aria-label="required">*</span></strong>
      </label>
      <input type="tel" id="number" name="cardnumber" />
    </p>
    <p>
      <label for="expiration">
        <span>Expiration date:</span>
        <strong><span aria-label="required">*</span></strong>
      </label>
      <input
 type="text"
 id="expiration"
 required="true"
 placeholder="MM/YY"
 pattern="^(0[1-9]|1[0-2])\/([0-9]{2})$" />
    </p>
  </section>
  <section>
    <p><button type="submit">Validate the payment</button></p>
  </section>
</form>
```

### CSS

```css
h1 {
  margin-top: 0;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

form {
  margin: 0 auto;
  width: 400px;
  padding: 1em;
  border: 1px solid #ccc;
  border-radius: 1em;
}

div + div {
  margin-top: 1em;
}

label span {
  display: inline-block;
  width: 120px;
  text-align: right;
}

input,
textarea {
  font: 1em sans-serif;
  width: 250px;
  box-sizing: border-box;
  border: 1px solid #999;
}

input[type="checkbox"],
input[type="radio"] {
  width: auto;
  border: none;
}

input:focus,
textarea:focus {
  border-color: #000;
}

textarea {
  vertical-align: top;
  height: 5em;
  resize: vertical;
}

fieldset {
  width: 250px;
  box-sizing: border-box;
  margin-left: 136px;
  border: 1px solid #999;
}

button {
  margin: 20px 0 0 124px;
}

label {
  position: relative;
}

label em {
  position: absolute;
  right: 5px;
  top: 20px;
}
```

### 결과


What is accessibility? - Web 개발 학습하기

What is accessibility?
======================

* Overview: Accessibility
* 다음

이 글에서는 접근성이 실제로 무엇인지 자세히 살펴보기로 합니다. 웹 개발에서 고려해야 할 사용자 그룹, 다양한 사람들이 웹과 상호 작용하기 위해 사용하는 도구들, 그리고 개발 워크 플로우에 접근성을 포함시키는 방법에 대한 내용을 다룹니다.

|  |  |
| --- | --- |
| 필요한 사전 지식: | 기본적인 컴퓨터 사용 능력, HTML과 CSS에 대한 기본적인 이해. |
| 목표: | 접근성과 친해지기. 접근성이 무엇이고 웹 개발자에게 어떤 영향을 미치는지 알아보기. |

그렇다면 접근성이란 무엇일까요?
-----------------

접근성은 가능한 한 많은 사람이 웹 사이트를 사용할 수 있도록 하는 방법입니다. 통상적으로 장애인만을 대상으로 한다고 생각하지만, 실제로는 모바일 장치나 느린 네트워크 연결을 사용하는 사람들 등 다른 사용자들에게도 도움을 줍니다.

접근성을 모든 사람을 동일하게 대하고, 그들의 능력이나 상황에 상관 없이 그들에게 같은 기회를 주는 것으로 생각할 수도 있습니다. 현대의 공공 건물에는 일반적으로 휠체어 경사로나 엘리베이터가 있습니다. 휠체어를 타고있다는 이유로 누군가를 물리적 건물에서 제외시키는 것이 옳지 않기 때문입니다. 같은 맥락에서 시각 장애가 있다는 이유로 누군가를 웹 사이트에서 제외시키는 것도 옳지 않습니다. 우리 모두는 다르지만 인간으로서 동일한 권리를 가집니다.

접근성은 당연히 지켜져야 할 일입니다. 일부 국가에서는 법의 일부이기도 하며, 이것은 서비스 사용이나 제품 구매가 불가능했던 사람들을 불러모아 중요한 시장을 만들 수 있다는 것을 의미합니다.

접근성을 갖춘 웹 사이트를 만드는 일은 다음과 같이 모든 사람에게 도움이 될 수 있습니다.

* 접근성이 향상된 시맨틱 HTML은 SEO도 개선해 사이트를 찾기 쉽고 시장성 있게 해줍니다.
* 접근성을 고려하는것은 좋은 윤리와 도덕 관념을 보여 주는데, 이것은 서비스의 대중적인 이미지를 개선합니다.
* 접근성을 향상시키려는 좋은 노력은 당신의 사이트를 다른 여러 사용자가 사용하기 쉽게 만듭니다. 휴대폰 사용자, 낮은 네트워크 속도의 사용자 등이 포함됩니다.
* 일부 지역에서는 법적으로 규정되어 있다고도 언급하지 않았나요?
우리가 살펴볼 장애 유형은 무엇일까요?
---------------------

장애가 있는 사람들은 그렇지 않은 사람들만큼 다양하고 그들의 장애 역시 그렇습니다. 여기서 중요한 교훈은 당신의 컴퓨터, 그리고 당신이 웹을 사용하는 방식을 넘어서 생각하는 방법에 대해 배우는 것입니다. 당신이 아닌 유저, 다른 사람들이 그것을 어떻게 사용하는지에 대해서 말이죠.

아래에는 생각해보아야 하는 장애의 주요 유형들이 설명되어 있습니다. 웹 콘텐츠에 접근하기 위해 사용하는 특별한 도구가 있다면 함께 살펴보겠습니다. 이런 도구들은 보조 기술(**assistive technologies**, 또는 **ATs**)이라고 불립니다.

**참고:** 세계 보건 기구(WHO)의 장애 및 보건 현황 보고서에 따르면 전 세계 인구의 약 15%에 해당하는 10억명 이상의 사람들이 장애를 갖고 있으며 1억 1천만명에서 1억 9천만명 사이의 성인들이 심각한 장애를 갖고 있습니다.

### 시각 장애가 있는 사람

여기에는 전맹, 저시력 장애인 및 색각 장애인등이 포함됩니다. 많은 경우 물리적 돋보기나 소프트웨어의 확대 기능을 통해 화면을 확대해서 이용합니다. 요즘에는 대부분의 브라우저와 운영체제가 확대 기능을 제공합니다. 일부 사용자는 디지털 텍스트를 소리내어 읽어주는 소프트웨어인 스크린 리더(screen reader)를 사용합니다. 이런 예시들이 있습니다.

* JAWS (Windows) and Dolphin Screen Reader (Windows) 와 Dolphin Screen Reader (Windows) 같은 상업 소프트웨어
* NVDA (Windows), ChromeVox (Chrome), 그리고 Orca (Linux)와 같은 무료 소프트웨어
* VoiceOver (macOS, iPadOS, iOS), Narrator (Windows), ChromeVox (on ChromeOS), 그리고 TalkBack (Android)와 같은 OS 자체 소프트웨어

이런 스크린 리더에 익숙해지기를 권장합니다. 직접 설치하고 다루어보면서 어떻게 동작하는지 감을 익혀보면 좋습니다. Cross-browser testing screen readers guide (en-US)에서 사용 방법에 대한 더 자세한 내용을 확인할 수 있습니다. 아래의 영상에서도 이 경험에 대한 간단한 예시를 보여줍니다.

통계적으로 세계 보건 기구(WHO)는 "전 세계적으로 2억 8,500만 명이 시각 장애를 가진 것으로 추정되고, 그 중 3,900만 명이 맹인이고 2억 4,600만 명이 저시력자이다." 라고 추정합니다. (Visual impairment and blindness 참고) 이것은 미국 인구와 비슷한 크기를 가진 중요한 비중의 인구입니다. 당신의 사이트는 제대로 코딩되지 않았다는 이유만으로 이 사용자들을 놓칠 수 있습니다.

### 청각 장애가 있는 사람

청각 장애 및 난청 (Deaf and hard-of-hearing, DHH) 사람들은 경도에서 심도까지 다양한 수준의 난청을 가지고 있습니다. 이들 중 일부는 보조 기술(AT, 청각, 음성, 언어 장애가 있는 사람들을 위한 보조 장치 참고)을 사용하지만 보편적이지는 않습니다.

따라서 접근성을 위해서는 대체 텍스트가 제공되어야 합니다. 영상에는 수동으로 자막을 달고 오디오 콘텐츠에 대해서도 대본을 제공해야 합니다. 또, DHH 인구의 높은 언어 박탈 (language deprivation))을 고려해 텍스트 단순화가 필요할 수 있습니다.

청각 장애 및 난청 인구도 의미있는 비중을 차지하는 유저입니다. 세계 보건 기구(WHO)의 Deafness and hearing loss fact sheet에 따르면 전 세계 4억 6,600만 명의 사람들이 난청을 겪고 있습니다.

### 운동 장애가 있는 사람

운동 장애(mobility impairments)는 사지의 상실이나 마비 등 물리적인 원인 또는 신경학적/유전적인 장애에 기인하는 팔 다리 통제력의 약화/상실로 인해 움직임에 제약이 생기는 것입니다. 이런 사람들은 마우스를 사용하기 위해 필요한 정교한 손의 움직임이 어려울 수도 있고, 심각한 경우 컴퓨터와의 상호작용을 위해 헤드 포인터를 사용해야 할 정도로 마비가 진행되었을 수도 있습니다.

이런 장애의 원인은 특정한 트라우마나 질병이 아닐 수도 있습니다. 노화가 될 수도 있고, 마우스가 없는 사용자처럼 하드웨어의 제약이 될 수도 있습니다.

운동 장애를 고려한 웹 개발의 보편적인 요구 사항은 키보드를 통해 컨트롤(이 가능한 요소들)에 접근할 수 있도록 해야 한다는 것입니다. 이 과정의 다른 아티클에서 키보드 접근성에 대해 이야기하겠지만, 웹 사이트를 키보드만으로 사용하는 일을 한번 해보세요. 어떻게 될까요? Tab 키를 사용해 웹 form의 컨트롤 요소들을 왔다갔다 할 수 있나요? 키보드 컨트롤에 관련된 더 많은 이야기는 Cross browser testing Using native keyboard accessibility (en-US) 섹션에서 다루어집니다.

통계적으로도 많은 수의 사람들이 운동 장애를 가지고 있습니다. US Centers for Disease Control and Prevention의 Disability and Functioning (Non-institutionalized Adults 18 Years and Over)에 따르면 미국에서 신체 기능 장애가 있는 성인 비율은 16.1%입니다.

### 인지 장애가 있는 사람

인지 장애의 정의는 광범위합니다. 가장 제한된 인지 능력을 가지는 지적 장애부터 시작해, 나이가 들며 생각하고 기억하는 데 어려움을 느끼는 우리 모두를 가리키기도 합니다. 우울증이나 정신분열증 같은 정신 질환 그리고 난독증, ADHD 같은 학습 장애도 포함합니다. 인지 장애에 대한 임상적인 정의는 다양하지만, 중요한 것은 모두가 공통적으로 겪는 기능 문제가 있다는 것입니다. 예를 들어 콘텐츠를 제대로 이해하거나 작업을 완료하는 방법을 기억하는 과정에서 발생하는 어려움과 일관성 없는 웹 페이지의 레이아웃으로 발생하는 혼란이 있습니다.

인지 장애를 고려한 접근성의 좋은 기반은 다음과 같습니다.

* 콘텐츠를 하나 이상의 방식으로 제공합니다. 텍스트-음성 변환 또는 비디오 등의 방법을 사용할 수 있습니다.
* 표준 문법을 지켜 작성된 텍스트처럼 쉽게 이해할 수 있는 콘텐츠를 제공합니다.
* 중요한 콘텐츠에는 주의가 집중될 수 있도록 합니다.
* 불필요한 내용이나 광고처럼 산만한 요소들을 최소화합니다.
* 일관된 웹 페이지 레이아웃과 네비게이션을 사용합니다.
* 방문하지 않은 경우 파란색, 방문한 경우는 보라색 밑줄이 그어지는 링크처럼 친숙한 요소를 사용합니다.
* 프로세스를 논리적이고 중요한 단계로 나누어서 생각할 수 있게 진행 상황을 표시해주는 장치를 사용합니다.
* 보안과 타협하지 않는 선에서 웹 사이트 인증은 가능한 쉽게 구현합니다.
* 양식은 완성하기 쉽게 만듭니다. 에러는 명확한 메세지를 보여주고 간단하게 복구되어야 합니다.
### 참고

* 인지적 접근성 (en-US)을 고려한 디자인은 좋은 디자인입니다. 모든 사람들에게 이점을 제공합니다.
* 많은 경우 인지 장애는 신체 장애를 동반합니다. 웹 사이트는 인지적 접근성 가이드라인 (en-US)을 포함해 W3C의 Web Content Accessibility Guidelines를 준수해야 합니다.
* W3C의 Cognitive and Learning Disabilities Accessibility Task Force에서 인지 장애가 있는 사람들을 위한 웹 접근성 가이드를 제공합니다.
* WebAIM Cognitive page에서 관련 정보와 자료를 제공합니다.
* 미국 질병통제센터(The United States Centers for Disease Control)는 2018년 기준으로 미국 시민 4명 중 1명이 장애를 가지고 있으며, 그 중에서 인지 장애는 젊은 사람들에게서 가장 흔하다고 추정합니다.
* 미국에서 역사적으로 일부 지적 장애가 "정신 지체(mental retardation)"라고 불려왔습니다. 현재는 혐오 표현으로 생각되어 사용을 권장하지 않습니다.
* 영국에서 일부 지적 장애는 "학습 장애(learning disabilities 또는 learning difficulties)"로 불리기도 합니다.
프로젝트에 접근성 구현하기
--------------

실제 프로젝트 구현 단계에서 접근성은 "비싼 추가 사항"으로 간주되는 경우가 많은데, 아래와 같은 경우에는 사실이 될 수 있습니다.

* 심각한 접근성 이슈가 있는 기존의 웹 사이트에 접근성을 추가하며 개조하려고 하는 경우
* 프로젝트가 한참 진행된 뒤에야 접근성을 고려하며 관련된 이슈들을 발견한 경우

하지만, 프로젝트를 시작할 때부터 접근성을 고려한다면 대부분의 콘텐츠를 접근성있게 만드는 데에 드는 비용은 꽤 적습니다.

프로젝트 계획을 세울 때, 대상 데스크탑이나 모바일 브라우저와 같은 중요한 타겟 오디언스 세그먼트를 위한 테스팅과 함께 접근성 테스팅을 고려하세요. 빠르게, 자주 테스트하세요. 이상적인 방식은 자동화된 테스트를 통해 누락되어 있는 접근성 관련 기능들(예를 들어 이미지의 대체 텍스트 (en-US)나 잘못된 링크 텍스트. Element relationships and context (en-US)를 참고하세요)을 잡아내는 것입니다. 또, 장애가 있는 유저 그룹을 대상으로 일부 테스팅을 진행하며 그들이 복잡한 사이트 기능을 얼마나 잘 활용할 수 있는지 확인할 수 있습니다. 다음과 같은 기준을 사용할 수 있습니다.

* 날짜 선택 위젯은 스크린 리더에서 사용성이 있나요?
* 동적으로 업데이트되는 콘텐츠를 시각 장애인도 인지할 수 있나요?
* UI 버튼들이 키보드와 터치 인터페이스 유저들 모두에게 접근성을 제공하나요?

접근성을 위한 작업이 필요한 잠재적 문제 영역에 대해 기록하고, 철저하게 테스팅 될 수 있도록 하며 해결 방안과 대안을 생각해야 합니다. 텍스트 콘텐츠는 (다음 아티클에서 살펴볼 것처럼) 쉬운 편이지만, 멀티미디어 콘텐츠나 최신 3D 기술로 만들어진 그래픽들은 어떻게 해야할까요? 프로젝트 예산을 고려해 이런 콘텐츠들을 접근성 있게 만들기 위해서 어떤 일을 할 수 있는지 생각해보세요. 비용은 많이 들겠지만 모든 멀티미디어에 대해 다른 형태의 기록, 음성 등을 제공하는 것도 가능합니다.

동시에 현실적으로 생각하세요. "100% 접근성"은 실현 불가능한 이상입니다. 언제나 예외가 존재하고 어떤 사용자는 어떤 콘텐츠를 사용하기 어렵다고 느낄 것입니다. 하지만 할 수 있는 만큼 노력해야 합니다. 만약 WebGL을 사용해 멋진 3D 파이 차트 그래픽을 만들 계획이라면, 같은 데이터에 대한 데이터 테이블을 접근성 있는 형태로 포함할 수 있습니다. 또는 3D 파이 차트를 테이블로 대체할 수도 있겠습니다. 테이블은 모두에게 접근성 있으며, 더 빠르게 개발 가능하고, CPU 집약적이지도 않으며 유지보수도 더 쉽습니다.

반면에 흥미로운 3D 아트를 전시하는 갤러리 웹사이트를 작업하고 있다면, 모든 작품이 전적으로 시각적인 매체이므로 시각 장애인에게 완벽한 접근성을 제공하기는 어려울 것입니다.

당신이 접근성에 대해 고민하고 생각하고 있다는 것을 드러내기 위해서는 사이트에 접근성 설명을 발행하는 것이 좋습니다. 접근성에 대한 당신의 정책과 어떤 노력을 기울였는지 게시해두세요. 누군가 사이트에서 접근성 문제를 발견했다고 알려준다면, 공감하며 대화하고 문제 해결을 위해 합리적인 절차를 거치세요.

**참고:** Handling common accessibility problems article (en-US) 에서 보다 세부적으로 테스트 되어야 하는 접근성에 대해 다룹니다.

요약하자면,

* 프로젝트 초기부터 접근성을 고려하고, 빠르게 자주 테스트하세요. 접근성 문제도 다른 버그들과도 마찬가지로 늦게 발견될수록 더 많은 비용이 발생합니다.
* 좋은 접근성은 장애인 사용자 뿐만 아니라 모든 사용자들에게 도움이 된다는 것을 기억하세요. 예를 들어, 간결한 시맨틱 마크업은 스크린 리더에게 좋을 뿐만 아니라 빠르게 로드되고 성능이 좋습니다. 특히 모바일이나 느린 네트워크 환경의 사용자 경험을 향상시킵니다.
* 사이트에 접근성 성명을 게시하고 문제를 겪는 사람들과 소통하세요.
접근성 지침 및 법률
-----------

접근성 테스트를 위한 가이드로 사용할 수 있는 체크리스트와 가이드라인들은 언뜻 보기에 압도적으로 많아 보입니다. 우리의 조언은 당신이 신경써야 하는 가장 기본적인 영역에 익숙해지는 것이 좋다는 것입니다. 물론 관련된 가이드라인의 고차원적인 구조들을 이해하는 것도 필요합니다.

* 우선 W3C에서 아주 길고 디테일한 문서를 발행했습니다. 여기에서 접근성 적합성에 대해 상세하고 사용 기술에 구애받지 않는 기준을 제시합니다. Web Content Accessibility Guidelines (WCAG)라고 불리는 이 문서는 간단하게 읽어지지는 않습니다. 기준은 네 개의 메인 카테고리로 나뉘고, 구현을 인식 가능하게, 작동 가능하게, 이해 가능하게, 또 견고하게 만드는 방법을 설명합니다. 가벼운 소개를 읽고 학습을 시작하기 좋은 곳은 WCAG at a Glance 입니다. WCAG의 모든 기준을 배울 필요는 없습니다. 주요 관심 분야에 대해 인지하고, WCAG 기준을 충족시키지 못하는 영역을 하이라이트 해주는 다양한 기술과 도구를 사용하세요 (아래쪽에 더 설명되어 있습니다).
* 당신의 국가에 웹 사이트의 접근성 제공 필요성에 대한 법률이 있을 수도 있습니다. 예를 들어 EU의 EN 301 549, 미국의 Section 508 of the Rehabilitation Act, 독일의 Federal Ordinance on Barrier-Free Information Technology, 영국의 Accessibility Regulations 2018, 이탈리아의 Accessibilità, 호주의 Disability Discrimination Act 등이 있습니다. WC3에서 나라 별로 웹 접근성 법률 및 정책 목록을 관리하고 있습니다.

WCAG는 가이드라인일 뿐이지만 당신의 국가에 웹 접근성, 또는 대중을 상대로 한 서비스의 접근성에 대한 법률이 있을 것입니다. 당신에게 적용되는 법이 무엇인지 알아보는 것을 권장합니다. 접근성을 위해 노력하지 않으면 사람들이 불만을 제기할 경우 법적인 책임이 생길 수 있습니다.

심각하게 들리겠지만, 지금까지 설명한 것처럼 웹 개발에 있어서 접근성을 정말로 주된 우선순위로 고려하세요. 잘 모르겠다면 자격을 갖춘 변호사에게 조언을 구하세요. 우리는 변호사가 아니기 때문에 이 이상의 조언은 드리지 않겠습니다.

접근성 API
-------

웹 브라우저는 보조 기술(AT)에 유용한 정보를 드러내는 운영체제의 **접근성 API**를 활용합니다. 보조 기술은 대부분 시맨틱 관련 정보를 사용하므로 여기에는 스타일 정보나 JavaScript 같은 것들이 포함되지 않습니다. 이 정보들은 **접근성 트리**라고 불리는 트리로 구조화됩니다.

각각의 운영체제는 다른 접근성 API를 사용합니다.

* Windows: MSAA/IAccessible, UIAExpress, IAccessible2
* macOS: NSAccessibility
* Linux: AT-SPI
* Android: Accessibility framework
* iOS: UIAccessibility

웹 앱의 HTML 요소들이 제공하는 네이티브 시맨틱 정보가 부족한 경우는 접근성 트리에 시맨틱 정보를 추가해 접근성을 개선하는 WAI-ARIA 명세서의 기능들로 보완이 가능합니다. 이 과정의 WAI-ARIA basics (en-US)에서 더 많은 내용을 설명합니다.

요약
--

이 문서에서는 접근성에 대한 고차원적인 개요를 제공했습니다. 이것이 왜 중요한지, 워크플로우에 어떻게 적용할 수 있을지 살펴봤습니다. 이제 접근성있는 사이트를 만들기 위해서 어떤 구현 디테일이 필요한지 궁금할텐데요. 이 과정을 통해 배울 수 있을 것입니다. 다음 섹션에서는 왜 HTML이 접근성을 위한 좋은 토대가 되는지 살펴보며 그 과정을 시작하겠습니다.

* Overview: Accessibility
* 다음


HTML: 접근성의 좋은 기반 - Web 개발 학습하기

HTML: 접근성의 좋은 기반
================

* 이전
* Overview: Accessibility
* 다음  (en-US)

HTML 요소를 늘 올바른 목적에 따라 사용하는 것 만으로 수많은 웹 콘텐츠가 접근성을 갖춥니다. 이번 글에서는 접근성을 최대한으로 보장하기 위해 HTML을 어떻게 사용해야 하는지 자세히 설명합니다.

|  |  |
| --- | --- |
| 필요한 사전 지식: | 기본적인 컴퓨터 활용 능력, HTML에 대한 기본적인 이해 (HTML 소개 참고), 그리고 접근성이 무엇인지에 대한 이해. |
| 목표: | 접근성 이점을 가져다주는 HTML 요소와 웹 문서에서 그들을 적절하게 사용하는 방법에 익숙해지기. |

HTML과 접근성
---------

HTML에 대해 더 많은 자료와 예제를 접하고, 더 많이 배우면 배울수록 당신은 시맨틱 HTML(POSH 또는 Plain Old Semantic HTML라고 부르기도 합니다)을 사용하는 것이 중요하다는 공통 주제를 계속해서 접하게 될 것입니다. 이것은 최대한 올바른 HTML 요소를 그 의도에 맞는 목적으로 사용하는 것을 의미합니다.

이게 왜 그렇게 중요한지 이해되지 않을 수도 있습니다. 사실 CSS와 JavaScript 조합만으로 거의 모든 HTML 요소들을 원하는 방식으로 동작시킬 수 있습니다. 예를 들어 사이트에서 동영상을 재생하기 위한 버튼을 이렇게 마크업 할 수 있습니다.

```html
<div>Play video</div>
```

하지만 나중에 더 자세히 살펴볼 것처럼, 작업에 올바른 HTML 요소를 사용하는 것이 합리적입니다.

```html
<button>Play video</button>
```

HTML `<button>`은 적절한 스타일(아마 덮어쓰고 싶을지 모르지만)이 기본적으로 적용되어 있을 뿐 아니라, 키보드 접근성도 내장되어 있습니다. 사용자는 `Tab` 키를 사용해서 버튼 사이를 이동할 수 있고, `Space`, `Return` 또는 `Enter` 키를 사용해 선택된 버튼을 활성화 시킬 수 있습니다.

시맨틱 HTML을 프로젝트 초기부터 지속적으로 사용한다면 시맨틱하지 않은, 즉 나쁜 마크업을 작성하는 것보다 더 오래 걸리지도 않습니다. 사실 시맨틱 마크업은 접근성 외의 이점도 가지고 있습니다.

1. **개발이 더 쉬워집니다** — 앞서 언급했듯이 내장된 몇몇 기능을 활용할 수 있으며, 이해하기에도 확실히 더 쉽습니다.
2. **모바일 환경에서 더 좋습니다** — 시맨틱 HTML은 시맨틱하지 않은 스파게티 코드보다 파일 사이즈가 가볍고 반응형으로 만들기도 더 쉽습니다.
3. **SEO에 좋습니다** — 검색 엔진은 의미가 없는 `<div>` 등의 태그보다 헤딩, 링크 등의 태그 내부 키워드에 더 많은 가중치를 부여합니다. 이는 고객들이 웹 문서를 더 찾기 쉽도록 만들어줍니다.

이제 접근성 있는 HTML에 대해 더 자세하게 살펴봅시다.

**참고:** 앞으로 살펴볼 예시들을 테스트 해볼 수 있도록 로컬 컴퓨터에 스크린 리더를 설치해두는 것이 좋습니다. 스크린 리더 가이드 (en-US)에서 더 자세한 내용을 확인할 수 있습니다.

좋은 시맨틱
------

우리는 제대로 된 시맨틱의 중요성, 그리고 왜 작업에 적합한 HTML 요소를 사용해야 하는지에 대해 이미 이야기했습니다. 이것은 제대로 다뤄지지 않았을 때 접근성을 심각하게 저해하는 요인이기 때문에 무시할 수 없습니다.

하지만 실제 웹에서 사람들은 HTML 마크업으로 아주 이상한 짓들을 합니다. 몇몇 HTML 오용은 레거시 관행의 잔재에, 몇몇은 단순한 무지에 기인합니다. 어떤 경우든 그런 나쁜 코드들은 고쳐져야 합니다.

가끔은 당신이 형편없는 마크업을 제거할 수 없는 위치에 있을지도 모릅니다. 페이지가 전적으로 제어할 수 없는 서버 사이드 프레임워크에 의해 생성되었을 수 있거나, 광고 배너처럼 제어할 수 없는 외부 콘텐츠가 페이지에 포함되어 있을 수 있습니다.

다만 목표는 "전부 또는 아무것도"가 아니라는 점을 생각하세요. 개선을 위한 노력 하나하나가 접근성 증진에 도움이 될 것입니다.

### 문자 콘텐츠

헤딩, 패러그래프, 리스트 등으로 이루어진 완벽한 콘텐츠 구조는 스크린 리더 사용자가 제공받을 수 있는 가장 좋은 접근성 지원 중 하나입니다. 다음은 완벽한 시맨틱 예시입니다.

```html
<h1>My heading</h1>

<p>This is the first section of my document.</p>

<p>I'll add another paragraph here too.</p>

<ol>
  <li>Here is</li>
  <li>a list for</li>
  <li>you to read</li>
</ol>

<h2>My subheading</h2>

<p>
  This is the first subsection of my document. I'd love people to be able to
  find this content!
</p>

<h2>My 2nd subheading</h2>

<p>
  This is the second subsection of my content, which I think is more interesting
  than the last one.
</p>
```

우리는 당신이 스크린 리더를 사용해볼 수 있도록 더 긴 내용이 포함된 버전을 준비했습니다 (good-semantics.html을 살펴보세요). 한번 시도해 보면 이 문서가 스크린 리더로 탐색하기에 꽤 쉽다는 것을 알 수 있을 것입니다.

1. 콘텐츠를 읽어나가는 동안 스크린 리더가 어떤 것이 헤딩이고, 어떤 것이 문단인지를 알려주면서 각각의 헤더를 읽어줍니다.
2. 당신이 편안한 속도로 탐색을 진행할 수 있도록 하나의 요소가 끝나면 멈춥니다.
3. 많은 스크린 리더에서 다음/직전 헤딩으로 이동할 수 있습니다.
4. 또한 많은 스크린 리더에서 모든 헤딩의 목록을 제공합니다. 특정 정보를 찾기 위한 편리한 목차로써 활용할 수 있습니다.

사람들은 종종 헤딩, 문단 등을 줄바꿈이나 스타일링만을 위한 HTML 요소를 통해 작성하기도 합니다. 다음 예시처럼요.

```html
<span style="font-size: 3em">My heading</span> <br /><br />
This is the first section of my document.
<br /><br />
I'll add another paragraph here too.
<br /><br />
1. Here is
<br /><br />
2. a list for
<br /><br />
3. you to read
<br /><br />
<span style="font-size: 2.5em">My subheading</span>
<br /><br />
This is the first subsection of my document. I'd love people to be able to find
this content!
<br /><br />
<span style="font-size: 2.5em">My 2nd subheading</span>
<br /><br />
This is the second subsection of my content. I think is more interesting than
the last one.
```

이것의 긴 버전을 스크린 리더로 읽어본다면 (bad-semantics.html을 살펴보세요) 좋지 못한 경험을 하게 될 것입니다. 스크린 리더가 표지판으로 사용할 수 있는 요소가 아무것도 없기 때문에 당신은 유용한 목차를 찾을 수 없고, 페이지 전체가 하나의 커다란 블록으로 여겨져 한번에 전부 읽어집니다.

접근성 외에도 다른 이슈들이 발생합니다. 예를 들어, 선택자로 사용할 수 있는 요소가 없기 때문에 CSS를 사용해 콘텐츠를 스타일링하거나 JavaScript를 사용해 조작하기 어렵습니다.

#### 명확한 언어 사용하기

당신이 사용하는 언어도 접근성에 영향을 줄 수 있습니다. 대체로 지나치게 복잡하지 않고 불필요한 전문 용어나 비속어를 사용하지 않는 명확한 표현을 사용해야 합니다. 이는 인지 또는 다른 장애가 있는 사람들뿐 아니라 작성 언어가 모국어가 아닌 사람들, 어린 사람들 등, 결론적으로 모든 사람들에게 도움이 됩니다. 그 외에도 스크린 리더가 똑바로 읽을 수 없는 언어나 문자의 사용을 지양해야 합니다. 다음과 같은 예시가 있습니다.

* 가능하다면 대시를 사용하지 마세요. 5-7로 쓰는 대신에 5에서 7로 작성하세요.
* 약어는 실제 표현으로 대체하세요. Jan 대신 January를 사용하세요.
* 두문자어는 적어도 한 번에서 두 번은 본 표현으로 사용하고, 설명을 위해 `<abbr>` 태그를 사용하세요.
### 페이지 레이아웃

HTML 테이블을 사용해 페이지 레이아웃을 만들던 시절이 있습니다. 헤더, 푸터, 사이드바, 메인 콘텐츠 열 등을 각각 테이블 셀 내부에 작성한 것이죠. 이것은 좋은 생각이 아닙니다. 스크린 리더가 읽는 내용이 혼란스러워질 가능성이 높기 때문입니다. 특히 레이아웃이 복잡하고 테이블이 중첩되어 있을 경우 그렇습니다.

저희의 예시 table-layout.html를 한번 시도해보세요. 이런 식으로 생겼습니다.

```html
<table width="1200">
  <!-- main heading row -->
  <tr id="heading">
    <td colspan="6">
      <h1 align="center">Header</h1>
    </td>
  </tr>
  <!-- nav menu row -->
  <tr id="nav" bgcolor="#ffffff">
    <td width="200">
      <a href="#" align="center">Home</a>
    </td>
    <td width="200">
      <a href="#" align="center">Our team</a>
    </td>
    <td width="200">
      <a href="#" align="center">Projects</a>
    </td>
    <td width="200">
      <a href="#" align="center">Contact</a>
    </td>
    <td width="300">
      <form width="300">
        <label
 >Search
          <input
 type="search"
 name="q"
 placeholder="Search query"
 width="300" />
        </label>
      </form>
    </td>
    <td width="100">
      <button width="100">Go!</button>
    </td>
  </tr>
  <!-- spacer row -->
  <tr id="spacer" height="10">
    <td></td>
  </tr>
  <!-- main content and aside row -->
  <tr id="main">
    <td id="content" colspan="4">
      <!-- main content goes here -->
    </td>
    <td id="aside" colspan="2" valign="top">
      <h2>Related</h2>

      <!-- aside content goes here -->
    </td>
  </tr>
  <!-- spacer row -->
  <tr id="spacer" height="10">
    <td></td>
  </tr>
  <!-- footer row -->
  <tr id="footer">
    <td colspan="6">
      <p>©Copyright 1996 by nobody. All rights reversed.</p>
    </td>
  </tr>
</table>
```

일부 스크린 리더가 테이블 레이아웃과 데이터 테이블을 구분할 수 있기는 하지만, 스크린 리더로 이 문서를 탐색하려고 한다면 아마도 살펴볼 테이블이 있다고 말해줄 것입니다. 당신이 어떤 스크린 리더를 사용하는지에 따라 다르지만 테이블 객체로 들어가 내부 속성들을 따로따로 살펴보고 다시 나와서 콘텐츠 탐색을 계속해야 할지도 모릅니다.

테이블 레이아웃은 과거의 유물입니다. 브라우저에 CSS 지원이 널리 보급되지 않았을 때는 의의가 있었지만 지금은 스크린 리더 사용자들에게 혼란을 불러올 뿐입니다. 또, 이런 소스 코드는 더 많은 마크업을 필요로 하기 때문에 유연성과 유지보수성이 떨어집니다. 당신은 다음과 같은 더 현대적인 웹 사이트 구조 예시와 이전의 예시를 비교하며 이를 증명할 수 있을 것입니다.

```html
<header>
  <h1>Header</h1>
</header>

<nav>
  <!-- main navigation in here -->
</nav>

<!-- Here is our page's main content -->
<main>
  <!-- It contains an article -->
  <article>
    <h2>Article heading</h2>

    <!-- article content in here -->
  </article>

  <aside>
    <h2>Related</h2>

    <!-- aside content in here -->
  </aside>
</main>

<!-- And here is our main footer that is used across all the pages of our website -->

<footer>
  <!-- footer content in here -->
</footer>
```

스크린 리더로 현대적인 예시를 시도해본다면, 더 이상 콘텐츠 읽기에 레이아웃 마크업이 끼어들어 혼란을 만들지 않는다는 것을 알 수 있을 것입니다. 코드 사이즈 면에서도 훨씬 간결하고 작습니다. 유지보수가 더 쉽고, 사용자가 다운로드 할 때 더 적은 대역폭이 필요하다는 것을 의미합니다 (특히 네트워크가 느린 사용자에게 유용합니다).

레이아웃을 생성할 때 고려할 다른 사항은 위의 예시처럼 HTML 시맨틱 요소들(콘텐츠 섹션을 확인하세요)을 사용하는 것입니다. `<div>` (en-US) 요소들을 중첩해서 레이아웃을 만들 수도 있지만, 네비게이션 메뉴는 `<nav>`, 푸터는 `<footer>`, 반복되는 콘텐츠 단위는 `<article>`로 감싸는 등 적절한 섹션 요소들을 사용하는 것이 더 좋습니다. 이것은 스크린 리더 또는 다른 도구들에 추가적인 의미를 제공함으로써 유저에게 탐색 중인 콘텐츠에 대한 단서를 추가적으로 제공합니다 (스크린 리더 지원에 대해 더 알아보고 싶다면 스크린 리더의 HTML5 섹션 요소 지원을 참고하세요).

**참고:** 좋은 시맨틱과 매력적인 레이아웃을 제공하는 것에 더불어 당신의 콘텐츠는 논리적인 순서에 따라 배치되어야 합니다. 물론 추후 CSS를 사용해 원하는 위치에 놓을 수 있지만, 스크린 리더 사용자들이 말도 안 되는 내용을 듣게 되지 않도록 처음부터 제대로 된 순서를 지켜야 합니다.

### UI 컨트롤

UI 컨트롤이란, 웹 문서에서 사용자와 상호작용하는 주요 영역들을 의미합니다. 일반적으로 버튼, 링크, 폼 컨트롤 요소들을 포함합니다. 이번 섹션에서는 이런 컨트롤 요소를 생성할 때 알고 있어야 하는 기본적인 접근성 이슈들을 살펴보겠습니다. 나중에 나오게 될 WAI-ARIA와 멀티미디어에 관한 아티클에서 UI 접근성에 대한 또 다른 관점들을 보게 될 것입니다.

UI 컨트롤 접근성에 대한 핵심적인 측면 중 하나는 브라우저가 기본적으로 키보드로 이들을 조작할 수 있도록 한다는 것입니다. native-keyboard-accessibility.html 예시에서 시험해 볼 수 있습니다. (소스 코드 참고). 이 예시를 새 탭에서 열고 탭 키를 눌러보세요. 몇 번 누르면 탭 포커스가 다른 포커스 가능 요소로 이동하는 것을 볼 수 있습니다. 모든 브라우저에서 포커스 된 요소는 기본적으로 강조 스타일링 되기 때문에 (브라우저마다 조금씩 다르기는 합니다) 어떤 요소에 포커스가 있는지 구분할 수 있을 것입니다.

!["Click me!", "Click me too!", 그리고 "And me!"라고 쓰여있는 세 개의 버튼. 세번째 버튼은 현재 탭 포커스를 드러내기 위해 둘레에 파란색 테두리가 있습니다.](/ko/docs/Learn/Accessibility/HTML/button-focused-unfocused.png)

**참고:** 개발자 도구에서 페이지의 탭 순서를 보여주는 오버레이를 활성화 할 수 있습니다. 더 많은 정보는 다음 링크에서 확인하세요. Accessibility Inspector > Show web page tabbing order.

그런 다음 엔터 또는 뒤로 가기 키를 눌러 포커스 된 링크로 이동하거나, 버튼을 누르거나 (예시에는 버튼을 눌렀을 때 경고 메세지가 표시되도록 하는 JavaScript가 포함되어 있습니다), 텍스트 인풋에 내용을 입력할 수 있습니다. 서로 다른 폼 요소들은 다른 컨트롤을 제공합니다. 예를 들어, `<select>` (en-US) 요소는 위 아래 방향키로 옵션을 보여주고 순회할 수 있도록 합니다.

**참고:** 브라우저마다 조작 옵션이 다를 수 있습니다. 자세한 내용은 네이티브 키보드 접근성 사용하기 (en-US)에서 확인하세요.

적절한 요소를 사용하는 것 만으로 이런 기능을 활용할 수 있습니다. 다음 예시처럼 말이죠.

```html
<h1>Links</h1>

<p>This is a link to <a href="https://www.mozilla.org">Mozilla</a>.</p>

<p>
  Another link, to the
  <a href="https://developer.mozilla.org">Mozilla Developer Network</a>.
</p>

<h2>Buttons</h2>

<p>
  <button data-message="This is from the first button">Click me!</button>
  <button data-message="This is from the second button">Click me too!</button>
  <button data-message="This is from the third button">And me!</button>
</p>

<h2>Form</h2>

<form>
  <div>
    <label for="name">Fill in your name:</label>
    <input type="text" id="name" name="name" />
  </div>
  <div>
    <label for="age">Enter your age:</label>
    <input type="text" id="age" name="age" />
  </div>
  <div>
    <label for="mood">Choose your mood:</label>
    <select id="mood" name="mood">
      <option>Happy</option>
      <option>Sad</option>
      <option>Angry</option>
      <option>Worried</option>
    </select>
  </div>
</form>
```

이것은 링크, 버튼, 폼 요소, 그리고 라벨(폼 컨트롤을 위한 `<label>` 요소 포함)을 적절하게 사용하는 것을 의미합니다.

그러나 여기서 또 사람들이 HTML로 이상한 짓을 하는 상황이 발생합니다. 예를 들어, 당신은 가끔 `<div>` (en-US)를 사용해 버튼을 마크업한 것을 보게 됩니다. 예를 들면 다음과 같습니다.

```html
<div data-message="This is from the first button">Click me!</div>
<div data-message="This is from the second button">Click me too!</div>
<div data-message="This is from the third button">And me!</div>
```

이런 식의 코드를 사용하는 것은 권장되지 않습니다. `<button>` 요소를 사용했다면 있었을 내장 키보드 접근성과 기본 CSS 스타일링을 곧장 잃게 됩니다. 혹시라도 버튼을 위해 버튼 외의 요소를 사용해야 하는 아주 아주 드문 경우가 있다면, `button` role (en-US)을 사용하고 키보드와 마우스 지원을 포함한 버튼의 모든 내장 기능을 구현하세요.

#### 키보드 접근성 다시 구축하기

이런 장점을 다시 추가하는 작업에는 노력이 꽤 필요합니다. (fake-div-buttons.html 예시를 참고하세요. 소스 코드도 확인할 수 있습니다.) 이 예시에서는 가짜 `<div>` 버튼에 `tabindex="0”` 속성을 부여해 탭을 통한 조작을 포함한 포커스 기능을 추가했습니다. 또한 `role="button"` 명시를 통해서 스크린 리더 사용자가 요소에 포커스하고 상호작용 가능함을 알 수 있도록 했습니다.

```html
<div data-message="This is from the first button" tabindex="0" role="button">
  Click me!
</div>
<div data-message="This is from the second button" tabindex="0" role="button">
  Click me too!
</div>
<div data-message="This is from the third button" tabindex="0" role="button">
  And me!
</div>
```

기본적으로 `tabindex` 속성의 주된 의도는 탭 키로 접근 가능한 요소들의 탭 선택 순서를 양수로 표현해 정해진 소스 순서 외로 커스텀 하는 것 입니다. 사실 대부분의 경우에 큰 혼란을 만들 수 있기 때문에 나쁜 생각입니다. 정말로 필요할 때만 이것을 사용하세요. 예를 들어, 소스 코드의 순서와 아주 다른 시각적 순서로 요소들을 보여주는 레이아웃에서 더 논리적인 동작을 원하는 경우가 있겠습니다. `tabindex`의 다른 옵션이 두 가지 더 있습니다.

* `tabindex="0”` — 위에서 말했듯 이 값은 기본적으로 탭 키로 접근이 불가능한 요소들을 접근이 가능하게 만듭니다. 아마 `tabindex`의 가장 유용한 값일 것입니다.
* `tabindex="-1”` — 기본적으로 탭 키로 접근이 불가능한 요소에 프로그래밍적으로 포커스가 잡히도록 할 수 있습니다. 예를 들어, JavaScript를 통해서나 링크의 타겟으로 말이죠.

이런 추가 작업이 우리가 버튼에 탭을 사용할 수 있도록 하지만, 우리가 `Enter`/`Return` 키를 통해 그것들을 활성화 시킬 수 있게 해주지는 않습니다. 그걸 위해서는 다음과 같은 약간의 JavaScript 트릭을 추가해야 합니다.

```js
document.onkeydown = (e) => {
  // The Enter/Return key
  if (e.key === "Enter") {
    document.activeElement.click();
    33;
  }
};
```

여기에서 우리는 키보드 버튼이 눌렸을 때 `document` 객체가 감지하도록 리스너를 추가했습니다. 이벤트 객체의 `key` 프로퍼티를 통해 어떤 키가 눌렸는지 확인하고, `Enter`/`Return`이라면 `document.activeElement.click()` 스크립트를 통해 버튼의 `onclick` 핸들러를 작동시킵니다. `activeElement`는 페이지에서 현재 포커스 되어있는 요소를 반환합니다.

이렇게 기능을 다시 구현하는 작업은 꽤 번거로울 뿐 아니라 다른 문제들을 야기할 수밖에 없습니다. **처음부터 알맞은 작업에 알맞은 요소를 사용하는 편이 낫습니다.**

#### 의미있는 텍스트 라벨

UI 컨트롤에서 텍스트 라벨은 모든 사용자에게 유용하지만, 이들의 올바른 사용은 장애가 있는 사용자들에게 특히 중요합니다.

버튼과 링크의 텍스트 라벨이 이해하기 좋고 구별 가능하도록 해야합니다. 라벨에 "여기를 클릭하세요" 같은 문구만 사용하지 마세요. 스크린 리더 사용자들은 때때로 버튼과 폼 컨트롤 리스트를 만나기도 합니다. 다음 스크린샷은 Mac VoiceOver에서 우리의 컨트롤이 열거되는 방식을 보여줍니다.

![Mac VoiceOver 소프트웨어에서 열거하는 폼 인풋 라벨 목록. 이 목록에는 버튼, 텍스트 필드, 링크 등의 다양한 폼 컨트롤 요소에 적용된 'happy menu button' 같은 의미없는 라벨이 포함되어 있습니다.](/ko/docs/Learn/Accessibility/HTML/voiceover-formcontrols.png)

맥락 밖에서도 이해 가능한 라벨을 사용하세요. 혼자 읽혀졌을 때에도 속해있는 문단 맥락 안에서 읽힐 때만큼 의미를 드러내야 합니다. 다음 예시는 좋은 링크 텍스트를 보여줍니다.

```html
<p>
  Whales are really awesome creatures.
  <a href="whales.html">Find out more about whales</a>.
</p>
```

이건 나쁜 예시입니다.

```html
<p>
  Whales are really awesome creatures. To find out more about whales,
  <a href="whales.html">click here</a>.
</p>
```

**참고:** 하이퍼링크 만들기 아티클에서 링크 구현과 모범 사례에 대한 더 많은 정보를 찾아볼 수 있습니다. 또한 good-links.html와 bad-links.html에서도 좋은 예시와 나쁜 예시들을 살펴볼 수 있습니다.

폼 라벨은 또한 각각의 인풋에 어떤 내용을 입력해야 하는지에 대한 단서를 주기 때문에 중요합니다. 다음 예시는 충분히 합리적인 것처럼 보입니다.

```html
Fill in your name: <input type="text" id="name" name="name" />
```

하지만 장애가 있는 사용자들에게는 그리 유용하지 않습니다. 위 예시는 볼 수 없는 사용자에게 폼의 인풋과 라벨을 명확하게 연관짓고 입력 영역을 어떻게 채워야 하는지 알려주는 어떤 것도 제공하지 않습니다. 스크린 리더로 이것을 읽는다면 "edit text"라는 설명 한 줄만 주어질 것입니다.

다음 예시가 훨씬 낫습니다.

```html
<div>
  <label for="name">Fill in your name:</label>
  <input type="text" id="name" name="name" />
</div>
```

이 코드로는 라벨이 인풋과 명확하게 연관지어집니다. 스크린 리더 설명은 "Fill in your name: edit text"와 같을 것입니다.

!['Fill in your name'으로 읽히는 좋은 폼 라벨이 주어진 텍스트 인풋 폼 컨트롤.](/ko/docs/Learn/Accessibility/HTML/voiceover-good-form-label.png)

추가로 대부분의 브라우저에서 폼의 라벨과 인풋을 연결하는 것은 라벨을 클릭해 폼 요소를 선택하거나 활성화시킬 수 있음을 의미합니다. 즉, 라벨까지 포함하는 더 큰 영역을 통해 인풋을 쉽게 선택할 수 있습니다.

**참고:** good-form.html과 bad-form.html에서 폼의 좋은 예시와 나쁜 예시들을 볼 수 있습니다.

다음의 영상에서는 제대로 된 텍스트 라벨의 중요성에 대한 좋은 설명과 Firefox Accessibility Inspector를 사용해 텍스트 라벨 이슈를 조사하는 방법을 배울 수 있습니다.

접근성 있는 데이터 테이블
--------------

기본적인 데이터 테이블은 다음처럼 아주 간단한 마크업으로 나타낼 수 있습니다.

```html
<table>
  <tr>
    <td>Name</td>
    <td>Age</td>
    <td>Pronouns</td>
  </tr>
  <tr>
    <td>Gabriel</td>
    <td>13</td>
    <td>he/him</td>
  </tr>
  <tr>
    <td>Elva</td>
    <td>8</td>
    <td>she/her</td>
  </tr>
  <tr>
    <td>Freida</td>
    <td>5</td>
    <td>she/her</td>
  </tr>
</table>
```

하지만 여기에는 문제가 있습니다. 스크린 리더 사용자가 테이블의 행과 열을 데이터 그룹으로 연결지을 수 있는 방법이 없다는 점입니다. 이를 위해서는 헤더 행이 무엇인지, 그리고 이들이 행이나 열 등을 어떻게 표시하고 있는지 알아야 합니다. 위의 예시에서는 시각적으로만 이루어집니다. (bad-table.html 예시를 직접 살펴보세요.)

이제 punk bands table 예시를 보면, 몇몇 접근성 지원이 효과적으로 작동하는 것을 볼 수 있습니다.

* 테이블 헤더가 `<th>` (en-US) 요소를 통해 정의되어 있습니다. 또한 `scope` 속성을 통해 행을 위한 헤더인지 열을 위한 헤더인지도 명시할 수 있습니다. 이것은 스크린 리더가 하나의 단위로 읽을 수 있는 완전한 데이터 그룹을 만듭니다.
* `<caption>` 요소와 `<table>` 요소의 `summary` 속성은 둘 다 테이블의 대체 텍스트로서 비슷한 기능을 합니다. 스크린 리더 사용자에게 테이블 내용에 대한 유용하고 빠른 요약을 제공하는 것이죠. 사실 두개 다 사용하지는 않아도 됩니다. 주로 볼 수 있는 사용자들에게도 해당 콘텐츠를 제공하는 `<caption>` 요소가 선호됩니다.

**참고:** HTML table advanced features and accessibility 아티클에서 접근성을 갖춘 데이터 테이블에 대한 더 자세한 내용을 살펴보세요.

대체 텍스트
------

텍스트 기반 콘텐츠는 내재적으로 접근성을 제공하는 반면 멀티미디어 콘텐츠는 그렇지 않습니다. 시각장애인은 이미지나 영상 콘텐츠를 볼 수 없고, 청각장애인은 음성 콘텐츠를 들을 수 없습니다. 이런 영상과 음성 콘텐츠는 접근성을 갖춘 멀티미디어 (en-US)에서 더 자세하게 다룰 예정이고, 이번 아티클에서는 소박하게 `<img>` 요소의 접근성을 살펴보겠습니다.

동일한 이미지 네 개의 복제본들을 표시하는 간단한 예시 accessible-image.html이 준비되어 있습니다.

```html
<img src="dinosaur.png" />

<img
 src="dinosaur.png"
 alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth." />

<img
 src="dinosaur.png"
 alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."
 title="The Mozilla red dinosaur" />

<img src="dinosaur.png" aria-labelledby="dino-label" />

<p id="dino-label">
  The Mozilla red Tyrannosaurus Rex: A two legged dinosaur standing upright like
  a human, with small arms, and a large head with lots of sharp teeth.
</p>
```

첫번째 이미지는 스크린 리더로 봤을 때 사용자에게 별 도움을 주지 않습니다. 예를 들어 VoiceOver는 "/dinosaur.png, image"라고 읽어줍니다. 조금의 도움이라도 제공하기 위해 파일명을 읽어주는 것이죠. 이 예시에서는 유저가 적어도 어떤 종류의 공룡이라는 점을 알 수 있지만, 대부분의 경우 파일명은 기계(예를 들면 디지털 카메라)가 생성합니다. 아마 이미지 내용에 대한 어떤 맥락도 제공하지 않겠죠.

**참고:** 이것이 이미지 안에 텍스트 콘텐츠를 포함해서는 안되는 이유입니다. 스크린 리더는 그 정보에 접근할 수 없습니다. 다른 단점도 있습니다. 그것을 선택하거나 복사/붙여넣기 할 수 없습니다. 하지 말라면 하지마세요.

두번째 이미지에 대해서는 스크린 리더가 "A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."라는 alt 속성 전부를 읽어줍니다.

이는 **대체 텍스트** 제공이 불가능한 경우를 위해 파일명을 의미있게 작성하는 것만큼, 가능하다면 `alt` 속성에 대체 텍스트를 제공하는 것이 중요하다는 것을 되새겨줍니다.

`alt` 속성 값은 항상 이미지와 이미지가 시각적으로 나타내는 내용에 대한 직접적인 표현을 제공해야 한다는 점에 주목하세요. 대체 텍스트는 짧고 간결해야 하며 이미지가 전달하는 정보 중 주위 텍스트와 중복되지 않는 모든 정보를 포함해야 합니다.

하나의 이미지에 대한 `alt` 속성 값은 맥락에 따라 다를 수 있습니다. 예를 들어, 강아지 Fluffy의 사진이 Yuckymeat 개 사료 리뷰 옆에 위치한 아바타라면, `alt="Fluffy"`는 적절합니다. 하지만 같은 사진이 동물 구호 단체의 입양 페이지에 사용된다면, 예비 강아지 부모를 위해 주변 설명으로는 제공되지 않는, 이미지를 통해서만 알 수 있는 정보가 포함되어야 합니다. `alt="Fluffy, 아주 짧은 세 가지 색의 털을 가진 테리어. 그녀는 입에 테니스 공을 물고 있음.”`와 같은 더 긴 설명이 적절하겠습니다. 플러피의 크기와 종 등은 아마 주위 텍스트를 통해 설명했을 것이므로, `alt` 내용에 포함되지 않습니다. 하지만 강아지에 대한 설명에 털 길이나 색상, 어떤 장난감을 좋아하는지에 대한 설명은 없을 가능성이 많으므로 포함됩니다. 야외에서 찍은 사진인지, 플러피가 파란색 목줄이 달린 목걸이를 하고 있는지는 반려견을 입양할 때 중요하지 않으므로 포함되지 않습니다. 대체 텍스트를 짧고 정확하고 유용하게 유지하세요. 이미지 내용 중 사용자가 접근할 수 있으면서 맥락에 어울리는 것들만이 전달되어야 하는 전부입니다.

이미지를 그 전에 본적이 없는 사람에게 유용하지 않은, 개인적 지식 또는 추가 설명은 포함되지 않아야 합니다. 공이 Fluffy가 좋아하는 장난감인지, 또는 사이트 사용자가 이미지에서 그것을 알 수 있는지 여부는 포함하지 마세요.

한 가지 고려할 부분은 이미지 내용에 의미가 포함되어 있는지, 아니면 순전히 시각적인 장식을 위한 것인지 입니다. 그저 장식 요소라면 `alt` 속성에는 빈 문자열(빈 alt 속성)을 확인하세요)을 작성하거나 CSS background로 페이지에 포함시키는 편이 좋습니다.

**참고:** 이미지 구현에 대한 훨씬 많은 정보와 모범 사례가 궁금하다면 HTML의 이미지과 반응형 이미지를 읽어보세요.

추가로 맥락 정보를 제공하고 싶다면, 이미지 주변 텍스트나 위에서 살펴본 것처럼 `title` 속성 내부에 입력하세요. 이 경우 스크린 리더는 대체 텍스트, title 속성, 그리고 파일명을 읽어줍니다. 또한 브라우저가 마우스 오버에 title 텍스트를 툴팁으로 제공할 것입니다.

!["The mozilla red dinosaur"라는 글자가 마우스 오버 툴팁에 나타나있는 빨간색 티라노사우루스의 스크린샷.](/ko/docs/Learn/Accessibility/HTML/title-attribute.png)

네 번째 방식에 대해서도 빠르게 살펴봅시다.

```html
<img src="dinosaur.png" aria-labelledby="dino-label" />

<p id="dino-label">The Mozilla red Tyrannosaurus…</p>
```

이 경우는 `alt` 속성을 전혀 사용하지 않습니다. 대신, 이미지에 대한 설명을 일반적인 문단으로 작성하고, `id` 속성을 부여한 뒤 `aria-labelledby` 속성을 사용해 해당 `id`를 가리키도록 했습니다. 이렇게 하면 스크린 리더가 해당하는 문단을 이미지의 대체 텍스트/라벨로 사용합니다. 이런 방식은 여러 개의 이미지에 대해 같은 텍스트 라벨을 사용하고 싶을 때 특히 유용합니다. `alt` 속성만으로는 불가능한 일이죠.

**참고:** `aria-labelledby` (en-US)는 개발자가 스크린 리더 접근성을 개선하기 위해 마크업에 추가 시맨틱을 구현할 수 있도록 해주는 WAI-ARIA 스펙의 일부입니다. 더 알아보기 위해서는 WAI-ARIA 기초 (en-US) 아티클을 읽어보세요.

### 피규어와 피규어 캡션

HTML에는 `<figure>`와 어떤 종류(이미지 외에 어떤 것도 될 수 있습니다)의 피규어를 그 캡션과 연동하는 `<figcaption>` 태그가 있습니다.

```html
<figure>
  <img
 src="dinosaur.png"
 alt="The Mozilla Tyrannosaurus"
 aria-describedby="dinodescr" />
  <figcaption id="dinodescr">
    A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a
    human, with small arms, and a large head with lots of sharp teeth.
  </figcaption>
</figure>
```

모든 스크린 리더가 이것을 지원하는 것은 아니지만, 아닌 경우에도 `aria-labelledby` (en-US)나 `aria-describedby`를 사용해 연동을 지원할 수 있습니다. 이런 요소 구조를 사용하는 것은 CSS 스타일링에 유용할 뿐 아니라 이미지에 대한 설명을 소스 옆에 위치시키는 방법을 제공합니다.

### 빈 alt 속성

```html
<h3>
  <img src="article-icon.png" alt="" />
  Tyrannosaurus Rex: the king of the dinosaurs
</h3>
```

페이지 디자인에 포함되어 있는 이미지가 시각적인 장식의 목적만을 가지는 경우가 있습니다. 위 코드 예시에서는 이미지의 `alt` 속성이 비어있는 것을 볼 수 있는데, 이는 스크린 리더가 이미지를 인식해도 설명을 시도하지 않게 하기 위함입니다. "이미지" 같은 것을 말하기보다요.

`alt` 속성을 아예 사용하지 않는 대신 빈 문자열을 넣는 것은 많은 스크린 리더가 `alt` 속성이 없는 경우 이미지 URL 자체를 알려주기 때문입니다. 위 예시의 이미지는 관련된 머릿말을 시각적으로 꾸미는 역할을 합니다. 이런 경우, 또는 정말로 의미있는 내용 없이 장식 요소인 경우 `img` 요소에 빈 `alt` 속성을 추가해야 합니다. 또 다른 방법으로는 aria `role` (en-US) 속성을 활용해 `role="presentation"` (en-US) 설정을 할 수 있습니다. 이 역시 스크린 리더가 대체 텍스트를 읽지 않도록 합니다.

**참고:** 가능하다면 장식용 이미지는 CSS를 통해 표시하기를 권장합니다.

링크 더 알아보기
---------

`href` 속성을 가지는 `<a>` 요소, 즉 링크는 어떻게 사용되는지에 따라 접근성을 개선하기도 저해하기도 합니다. 기본적으로 링크는 접근성을 제공하는 것처럼 보입니다. 사용자가 문서의 다른 섹션으로 빠르게 이동할 수 있도록 도와 접근성을 향상시킵니다. 그러나 접근성 있는 스타일이 제거되거나 JavaScript로 인해 예상치 못한 동작을 제공한다면 접근성에 해가 되기도 합니다.

### 링크 스타일링

색상과 text-decoration 면에서 링크는 다른 텍스트 요소들과 시각적으로 다릅니다. 기본 링크는 파란색에 밑줄이 그어져있고, 방문한 경우 보라색 밑줄, 키보드 포커스가 되어있을 때는 focus-ring이 생깁니다.

색상만으로 링크가 아닌 콘텐츠와 링크를 구분해서는 안됩니다. 다른 모든 텍스트와 마찬가지로 링크 텍스트의 색은 배경 색상과 시각적인 차이를 가져야 합니다 (4.5:1 contrast (en-US)). 또, 링크는 링크가 아닌 텍스트와도 시각적으로 달라야 합니다. 링크 텍스트와 주위 텍스트, 그리고 기본 상태, 방문된 상태, 포커스/활성화된 상태 사이에는 각각 적어도 3:1의 대비가 요구됩니다. 모든 상태 색상 값과 배경 색상 사이에는 4.5:1의 대비가 요구됩니다.

### `onclick` 이벤트

`<a>` 태그의 `onclick` 이벤트는 종종 의사 버튼을 만들기 위한 목적으로 잘못 사용됩니다. 페이지 리프레시를 막기 위해 **href** 속성을 `"#"`로, 또는 `"javascript:void(0)"`를 설정하는 식입니다.

이런 값들은 링크를 복사하거나 드래그할 때, 새 탭이나 창에서 열 때, 북마크 할 때, 그리고 JavaScript가 로드되는 동안 예상하지 못한 동작을 발생시킵니다. 또한 스크린 리더 등의 보조 기술에 잘못된 의미를 전달합니다. 이런 경우 `<button>` 요소를 사용하는 것을 권장합니다. 일반적으로 anchor는 올바른 URL을 사용한 탐색을 위해서만 사용해야 합니다.

### 외부 링크와 HTML 외 자원 링크

`target="_blank”` 선언으로 새로운 탭이나 창에서 열리는 링크나 `href` 속성 값이 파일 리소스를 가리키는 링크의 경우, 활성화 되었을 때 일어나는 동작에 대한 표시를 포함해야 합니다.

저시력 증상이 있거나 스크린 리더 기술의 도움을 받아 탐색하는 사람들, 또는 인지적인 문제를 가진 사람들은 예상하지 못한 새 탭이나 창, 애플리케이션이 열렸을 때 혼란을 겪을 수 있습니다. 오래된 버전의 스크린 리더 소프트웨어들은 이런 동작을 알려주지 않을 수도 있습니다.

#### 새 탭이나 창에서 열리는 링크

```html
<a target="\_blank" href="https://www.wikipedia.org/"
 >Wikipedia (opens in a new window)</a
>
```

#### HTML 외 자원으로 이동하는 링크

```html
<a target="\_blank" href="2017-annual-report.ppt"
 >2017 Annual Report (PowerPoint)</a
>
```

만약 이런 링크 동작을 나타내기 위해 텍스트 대신 아이콘이 사용된다면 대체 텍스트를 꼭 포함하도록 하세요.

* WebAIM: Links and Hypertext - Hypertext Links
* MDN Understanding WCAG, Guideline 3.2 explanations (en-US)
* G200: Opening new windows and tabs from a link only when necessary | W3C Techniques for WCAG 2.0
* G201: Giving users advanced warning when opening a new window | W3C Techniques for WCAG 2.0
### 스킵 링크

skipnav라고도 불리는 스킵 링크는 페이지 주요 콘텐츠 영역의 시작으로 연결되는 `a` 요소입니다. `<body>` 오프닝 태그와 최대한 가까이 위치합니다. 이는 사람들이 웹 사이트의 헤더, 주 네비게이션 바 등 여러 페이지에 걸쳐 반복되는 콘텐츠를 뛰어넘을 수 있도록 해줍니다.

스킵 링크는 특히 스위치 컨트롤, 음성 명령, 마우스 스틱과 헤드 완드 등의 보조 기술의 도움을 받는 사용자들에게 유용합니다. 이들에게 반복되는 링크들을 탐색하는 것은 굉장히 힘든 작업이기 때문입니다.

* WebAIM: "Skip Navigation" Links
* How–to: Use Skip Navigation links - The A11Y Project
* MDN Understanding WCAG, Guideline 2.4 explanations (en-US)
* Understanding Success Criterion 2.4.1 | W3C Understanding WCAG 2.0
### 근접성

anchor를 포함해 많은 상호작용 가능한 콘텐츠들은 서로에게 시각적으로 근접해있기도 합니다. 이런 경우 주변 요소와 분리해 주는 여백을 일부 가져야 합니다. 이 여백은 잘못해서 상호작용 요소를 활성화시키기 쉬운, 운동 장애를 겪는 사람들에게 도움을 줄 수 있습니다.

여백은 `margin` 등의 CSS 프로퍼티를 사용해 만들어질 수 있습니다.

* Hand tremors and the giant-button-problem - Axess Lab
테스트 해보기
-------

아티클을 끝까지 읽었습니다. 중요한 정보들을 전부 기억하고 있나요? 다음 단계로 넘어가기 전에 Test your skills: HTML Accessibility (en-US)에서 이번에 배운 내용을 확인해보세요.

요약
--

이제 당신은 대부분의 상황에서 접근성있는 HTML을 작성하는 능력을 갖췄을 것입니다. 이번 아티클에서는 아주 기본적인 내용들을 다뤘고, 남은 부분 WAI-ARIA 아티클에서 채워질 것입니다. 다음에는 CSS와 JavaScript에 대해 알아보고 모범적인 또는 잘못된 사용이 접근성에 어떻게 영향을 주는지 살펴보겠습니다.

* 이전
* Overview: Accessibility
* 다음  (en-US)


웹어셈블리의 JavaScript API 사용하기 - 웹어셈블리

웹어셈블리의 JavaScript API 사용하기
==========================

Emscripten과 같은 도구를 사용하여 다른 언어의 모듈을 컴파일했거나 코드를 직접로드하여 실행 해봤다면 다음 단계에서는 WebAssembly JavaScript API의 다른 기능을 사용하는 방법에 대해 자세히 알아 봅니다.

**참고:** 여기에서 언급한 기본 개념에 익숙하지 않거나 더 많은 설명이 필요한 경우 WebAssembly concepts를 먼저 읽어보세요.

몇가지 간단한 예제
----------

WebAssembly JavaScript API를 사용하는 방법과 웹 페이지에서 wasm 모듈을 로드하는 방법을 설명하는 몇 가지 예제를 실행 해 보겠습니다.

**참고:** 샘플 코드는 webassembly-examples GitHub repo에서 찾을 수 있습니다.

### 예제 준비하기

1. 먼저 wasm 모듈이 필요합니다! simple.wasm 파일을 로컬 컴퓨터의 새 디렉토리에 저장하세요.
2. 다음으로, wasm 파일과 동일한 디렉토리에 index.html이라는 간단한 HTML 파일을 작성해보세요 (simple template을 참고하면 쉽습니다.)
3. 이제 여기서 무슨 일이 벌어지는지 이해하기 쉽도록 하기위해 wasm 모듈 (Converting WebAssembly format to wasm을 참고)의 텍스트 표현을 살펴 보겠습니다.

```rust
(module
  (func $i (import "imports" "imported\_func") (param i32))
  (func (export "exported\_func")
    i32.const 42
    call $i))
```

4. 두 번째 줄에서 2단계의 import 네임스페이스가 있습니다. 즉, 내부 기능 `$i`는 `imports.imported_func`에서 가져옴을 알 수 있습니다. wasm 모듈로 가져올 객체를 작성할 때 JavaScript에서 이 2단계 네임스페이스를 반영해야 합니다.
 HTML 파일에 `<script></script>`요소를 만들고 다음 코드를 추가합니다.

```js
var importObject = {
  imports: { imported\_func: (arg) => console.log(arg) },
};
```

### 웹어셈블리 모듈을 스트리밍하기

Firefox 58의 새로운 기능으로 기본 소스에서 직접 WebAssembly 모듈을 컴파일하고 인스턴스화하는 기능이 있습니다. 이는 `WebAssembly.compileStreaming()` 와 `WebAssembly.instantiateStreaming()` 메소드를 사용하여 수행됩니다. 이 메소드는 바이트 코드를 직접 `Module`/`Instance` 인스턴스로 변환 할 수 있기 때문에 스트리밍이 아닌 방식의 메소드보다 작성이 쉽습니다. 별도로 `Response`를 `ArrayBuffer`로 호출할 필요성을 없애줍니다.

이 예제는 (GitHub의 instantiate-streaming.html 데모와 view it live를 보세요) `instantiateStreaming()`을 사용하여 wasm 모듈을 가져오고, JavaScript 함수를 가져오고, 컴파일하고 인스턴스화하며, 내 보낸 함수에 액세스하는 방법을 한번에 보여줍니다.

첫 번째 블록 아래에 다음을 추가하십시오.

```js
WebAssembly.instantiateStreaming(fetch("simple.wasm"), importObject).then(
  (obj) => obj.instance.exports.exported\_func(),
);
```

그 결과, 내 보낸 WebAssembly 함수 인 `export_func`를 호출합니다.이 함수는 가져온 JavaScript 함수 `imported_func`를 호출합니다.이 함수는 WebAssembly 인스턴스 (42) 내부에 제공된 값을 콘솔에 기록합니다. 지금 예제 코드를 저장하고 WebAssembly를 지원하는 브라우저에 로드하면 이를 실제로 볼 수 있습니다!

**참고:** 이것은 매우 난해하고, 길고 지루한 예이지만 웹 응용프로그램에서 JavaScript와 함께 WebAssembly 코드를 사용하여 가능한 것을 설명하는 데 도움이 됩니다. 우리가 다른 곳에서 언급했듯이, WebAssembly는 JavaScript를 대체하려는 것이 아니라, 그 두 개가 상호 작용하여 서로의 강점을 이끌어 낼수 있습니다.

### 스트리밍하지 않고 웹어셈블리 모듈 로드

위에서 설명한 스트리밍 방법을 사용할 수 없거나 사용하지 않으려면 스트리밍하지 않는 메서드`WebAssembly.compile` / `WebAssembly.instantiate`를 대신 사용할 수 있습니다.

이 메소드는 바이트 코드에 직접 액세스하지 않으므로 wasm 모듈을 컴파일 / 인스턴스화하기 전에 응답을 `ArrayBuffer`로 변환하는 추가 단계가 필요합니다.

이와 동등한 코드는 다음과 같습니다.

```js
fetch("simple.wasm")
  .then((response) => response.arrayBuffer())
  .then((bytes) => WebAssembly.instantiate(bytes, importObject))
  .then((results) => {
    results.instance.exports.exported\_func();
  });
```

### 개발자 도구에서 웹어셈블리 보기

Firefox 54+에서 Developer Tool Debugger Panel에는 웹 페이지에 포함된 모든 wasm 코드의 텍스트 표현을 표시하는 기능이 있습니다. Debugger 패널로 이동하여 "wasm://" 항목을 클릭할 수 있습니다.

![wasm-debug](/ko/docs/WebAssembly/Using_the_JavaScript_API/wasm-debug.png)

Firefox에서 WebAssembly를 텍스트로 보는 것 외에도 텍스트 형식을 사용하여 개발자는 WebAssembly를 디버깅할 수 있습니다(breakpoint, callstack 검사, 단일 단계 검사 등). 비디오 미리 보기는 WebAssembly debugging with Firefox DevTools을 참조하십시오.

메모리 인스턴스
--------

WebAssembly의 저수준 메모리 모델에서 메모리는 Linear Memory라고하는 형식이 지정되지 않은 바이트의 연속 범위로 표시되며 load and store instructions에 의해 모듈 내부에서 읽고 쓰여집니다. 이 메모리 모델에서 모든 load 또는 store는 linear memory의 모든 바이트에 액세스 할 수 있으므로 포인터와 같은 C / C ++ 개념을 충실하게 표현하는 데 필요합니다.

그러나 네이티브 C / C ++ 프로그램과 달리 사용 가능한 메모리 범위가 전체 프로세스에 걸쳐있는 경우 특정 WebAssembly 인스턴스가 액세스 할 수있는 메모리는 WebAssembly 메모리 객체에 포함 된 특정 범위 (잠재적으로 매우 작은 범위)로 제한됩니다. 이를 통해 단일 웹 응용 프로그램은 WebAssembly를 내부적으로 사용하는 여러 독립 라이브러리를 사용하여 서로 완전히 격리 된 별도의 메모리를 가질 수 있습니다.

자바 스크립트에서 Memory 인스턴스는 크기를 조정할 수있는 ArrayBuffer로 생각할 수 있으며, ArrayBuffers와 마찬가지로 하나의 웹 앱에서 많은 독립적 인 Memory 객체를 만들 수 있습니다. `WebAssembly.Memory()` 생성자를 사용하여 생성 할 수 있습니다. 생성자는 인수로 초기 크기와 (선택적으로) 최대 크기를 인수로 취합니다.

빠르게 예제를 살펴봅시다.

1. 새로운 간단한 HTML 페이지를 만들고 (simple template을 복사하십시오) `memory.html`을 호출하십시오. `<script></script>` 요소를 페이지에 추가하십시오.
2. 이제 스크립트 맨 위에 다음 행을 추가하여 메모리 인스턴스를 만듭니다.

```js
var memory = new WebAssembly.Memory({ initial: 10, maximum: 100 });
```

`initial` 및 `maximum` 단위는 WebAssembly 페이지이며 크기는 64KB로 고정되어 있습니다. 즉, 위 메모리 인스턴스의 초기 크기는 640KB이고 최대 크기는 6.4MB입니다.
 WebAssembly 메모리는 ArrayBuffer를 반환하는 버퍼 getter / setter를 제공함으로써 바이트를 노출합니다. 예를 들어 선형 메모리의 첫 번째 단어에 직접 42를 쓰려면 다음과 같이하면됩니다.

```js
new Uint32Array(memory.buffer)[0] = 42;
```

그런 다음 다음을 사용하여 동일한 값을 반환 할 수 있습니다.

```js
new Uint32Array(memory.buffer)[0];
```

3. 데모에서 지금 사용해보십시오. 지금까지 추가 한 내용은 저장하고 브라우저에로드 한 다음 JavaScript 콘솔에 위의 두 줄을 입력 해보십시오.
### 메모리의 확장

메모리 인스턴스는 `Memory.prototype.grow()`를 호출하여 확장 할 수 있습니다. 여기서 인수는 WebAssembly 페이지 단위로 입력합니다.

```js
memory.grow(1);
```

메모리 인스턴스 생성시 최대 값이 제공되었을 때 이 최대 값을 초과하여 증가하려고 시도하면 `WebAssembly.RangeError` 예외가 발생합니다. 엔진은 이 상한값을 이용하여 미리 메모리를 예약하므로 크기를 보다 효율적으로 조정할 수 있습니다.

`ArrayBuffer`의 byteLength는 불변이므로, `Memory.prototype.grow()` 오퍼레이션이 성공하면, 버퍼 getter는 (새로운 byteLength로) 새로운 ArrayBuffer 객체를 돌려 주어, 이전의 모든 ArrayBuffer 객체는 「detached」가되거나, 이전에 가리켰던 기본 메모리와의 접속이 끊어집니다.

함수와 마찬가지로 선형 메모리를 모듈 내부에서 정의하거나 가져올 수 있습니다. 마찬가지로 모듈은 메모리를 선택적으로 내보낼수도 있습니다. 즉, JavaScript는 새 WebAssembly.Memory를 만들고 가져 오기로 전달하거나 `Instance.prototype.exports` (en-US)를 통해 메모리 내보내기를 하여 WebAssembly 인스턴스의 메모리에 액세스 할 수 있습니다.

### 심화된 메모리 예제

앞서 정의한 메모리 인스턴스를 가져 와서 정수 배열로 채운 다음 더 합친 WebAssembly 모듈을 통해 더 많은 관련 메모리 예제를 살펴봄으로써 위의 내용을 보다 자세히 알아 보겠습니다. memory.wasm에서 찾을 수 있습니다.

1. `memory.wasm`을 이전과 같이 같은 폴더에 복사합니다.

**참고:** memory.wat에서 모듈의 텍스트 표현을 볼 수 있습니다.
2. `memory.html` 샘플 파일로 돌아가서 이전처럼 wasm 모듈을 가져 와서 컴파일하고 인스턴스화합니다. - 스크립트의 맨 아래에 다음을 추가하세요.

```js
WebAssembly.instantiateStreaming(fetch("memory.wasm"), {
  js: { mem: memory },
}).then((results) => {
  // add code here
});
```

3. 이 모듈은 메모리를 내보내므로 instance라는 이 모듈의 인스턴스가 export 된 함수 `accumulate()`를 사용하여 모듈 인스턴스의 선형 메모리 (`mem`)에 직접 입력 배열을 만들고 채울 수 있습니다. 코드에 다음을 추가하십시오.

```js
var i32 = new Uint32Array(memory.buffer);

for (var i = 0; i < 10; i++) {
  i32[i] = i;
}

var sum = results.instance.exports.accumulate(0, 10);
console.log(sum);
```

Memory 객체의 버퍼 (`Memory.prototype.buffer` (en-US))에서 `Uint32Array` (en-US) 뷰를 만드는 방법에 유의하십시오.

메모리 가져 오기는 함수 가져 오기와 마찬가지로 작동하며 메모리 개체 만 JavaScript 함수 대신 값으로 전달됩니다. 메모리 가져 오기는 다음과 같은 두 가지 이유로 유용합니다.

* 그것들은 자바 스크립트가 모듈 컴파일 이전에 또는 모듈 컴파일과 동시에 메모리의 초기 내용을 가져오고 생성 할 수 있도록합니다.
* WebAssembly에서 동적 연결을 구현하는 데 중요한 구성 요소인 multiple module instances에서 단일 Memory 객체를 가져올 수 있습니다.

**참고:** memory.html에서 완전히 동작하는 예제를 확인할 수 있습니다. (see it live also)

테이블 인스턴스
--------

WebAssembly 테이블은 JavaScript 및 WebAssembly 코드로 액세스 할 수 있는 크기가 조정가능한 형식의 references 배열입니다. 메모리는 크기를 조정할 수있는 원시 바이트 배열을 제공하지만 참조는 안전성, 이식성 및 안정성을 이유로 내용으로 직접 읽거나 쓰지 않아야하는 engine-trusted 값이므로 참조가 메모리에 저장되는 것은 안전하지 않습니다.

테이블에는 테이블에 저장할 수있는 참조 유형을 제한하는 요소 유형이 있습니다. WebAssembly의 현재 반복에서는 WebAssembly 코드 함수에 필요한 참조 유형이 하나뿐이므로 올바른 요소 유형이 하나만 있습니다. 향후 반복에서는 더 많은 요소 유형이 추가됩니다.

함수 참조(Function references)는 함수 포인터가 있는 C / C ++와 같은 언어를 컴파일하는 데 필요합니다. C / C ++의 네이티브 구현시 함수 포인터는 프로세스의 가상 주소 공간에있는 함수 코드의 원시 주소로 표시되므로 위에서 언급 한 안전상의 이유로 선형 메모리에 직접 저장할 수 없습니다. 대신 함수 참조는 테이블에 저장되며 선형 메모리에 저장 할 수 있는 정수인 인덱스가 대신 전달됩니다.

함수 포인터를 호출 할 때 WebAssembly 호출자는 인덱스를 제공합니다.이 호출자는 인덱싱 된 함수 참조를 인덱싱하고 호출하기 전에 테이블에 대해 safety bounds를 검사 할 수 있습니다. 따라서 테이블은 현재 저수준 프로그래밍 언어 기능을 안전하고 이식 가능하게 컴파일하는 데 사용되는 다소 낮은 수준의 프리미티브(primitive)입니다.

테이블은 테이블의 값 중 하나를 업데이트하는 `Table.prototype.set()` (en-US)과 테이블에 저장할 수있는 값의 수를 늘리는 `Table.prototype.grow()` (en-US)를 통해 변형 될 수 있습니다. 이를 통해 간접적으로 호출 할 수있는 함수 집합이 시간이 지남에 따라 변경 될 수 있으며 이는 dynamic linking techniques에 필요합니다. mutations는 JavaScript의 `Table.prototype.get()` (en-US)과 wasm 모듈을 통해 즉시 액세스 할 수 있습니다.

### 테이블 예제

두 요소가 있는 테이블(요소 0은 13을 반환하고 요소 1은 42를 반환)을 만들고 내보내는 WebAssembly 모듈(table.wasm에서 확인 가능)로 간단한 테이블 예제를 보겠습니다.

1. 새로운 디렉토리에 `table.wasm`을 복사하여 만듭니다.

**참고:** table.wat에서 모듈의 텍스트 표현(text representation)을 확인할 수 있습니다.
2. HTML template를 같은 디렉토리에 복사하여 `table.html`라는 파일명으로 저장합니다.
3. wasm 모듈을 fetch, compile, instantiate하기 전 다음의 코드를 HTML body아래의 `<script>` 요소안에 넣습니다.

```js
WebAssembly.instantiateStreaming(fetch("table.wasm")).then(
  function (results) {
    // add code here
  },
);
```

4. 이제 테이블 안에 있는 정보에 엑세스 하겠습니다. 다음의 코드를 위의 add code here 부분에 넣습니다.

```js
var tbl = results.instance.exports.tbl;
console.log(tbl.get(0)()); // 13
console.log(tbl.get(1)()); // 42
```

이 코드는 테이블에 저장된 각 함수 참조를 차례로 액세스하고 인스턴스화하여 가지고 있는 값을 콘솔에 출력합니다. `Table.prototype.get()` (en-US) 호출로 각 함수 참조를 검색 한 다음 추가 세트를 추가합니다 실제로 함수를 호출하려면 끝에 괄호를 사용하십시오.

**참고:** 우리의 완전한 데모는 table.html에서 찾을 수 있습니다. (see it live also)

Globals
-------

WebAssembly는 하나 이상의 `WebAssembly.Module` 인스턴스 전체에서 JavaScript와 가져오기 / 내보내기가 가능한 전역 변수 인스턴스를 생성 할 수 있습니다. 이는 여러 모듈을 동적으로 연결할 수 있으므로 매우 유용합니다.

JavaScript 내부에서 WebAssembly 전역 인스턴스를 만들려면 다음과 같은 `WebAssembly.Global ()` 생성자를 사용합니다.

```js
const global = new WebAssembly.Global({ value: "i32", mutable: true }, 0);
```

다음 두가지 매게변수를 확인 할 수 있습니다.

* 전역 변수를 설정하는 두 가지 속성이 포함 된 객체.
    + `value`: WebAssembly 모듈에서 사용할 수 있는 데이터 타입입니다. 다음의 값을 사용할 수 있습니다. — `i32`, `i64`, `f32`, `f64`.
    + `mutable`: boolean 값이며 mutable이 가능한지 여부를 지정합니다.
* 변수의 실제 값을 포함하는 값. 유형이 지정된 데이터 유형과 일치하면 어떤 값이든 될 수 있습니다.

다음예제에서 mutable `i32`타입으로 정의되고 value 0을 가진 global로 어떻게 사용하는지 알아보겠습니다.

global 값은 `Global.value` 속성을 사용하여 처음 42로 변경된 다음 `global.wasm`module에서 내보낸 `incGlobal()` 함수를 사용하여 43으로 변경됩니다. 이것은 값이 주어진 값에 1을 더한 다음 새 값을 반환합니다.

```js
const output = document.getElementById("output");

function assertEq(msg, got, expected) {
  output.innerHTML += `Testing ${msg}: `;
  if (got !== expected)
    output.innerHTML += `FAIL!<br>Got: ${got}<br>Expected: ${expected}<br>`;
  else output.innerHTML += `SUCCESS! Got: ${got}<br>`;
}

assertEq("WebAssembly.Global exists", typeof WebAssembly.Global, "function");

const global = new WebAssembly.Global({ value: "i32", mutable: true }, 0);

WebAssembly.instantiateStreaming(fetch("global.wasm"), { js: { global } }).then(
  ({ instance }) => {
    assertEq(
      "getting initial value from wasm",
      instance.exports.getGlobal(),
      0,
    );
    global.value = 42;
    assertEq(
      "getting JS-updated value from wasm",
      instance.exports.getGlobal(),
      42,
    );
    instance.exports.incGlobal();
    assertEq("getting wasm-updated value from JS", global.value, 43);
  },
);
```

**참고:** running live on GitHub에서 라이브 예제를 확인하고 에서 source code 소스코드를 확인 할 수 있습니다.

Multiplicity
------------

이제 우리는 WebAssembly 기본 블록의 사용법을 보여주었습니다. 다중성의 개념을 언급하기에 좋은 곳입니다. 여기서 구조적 효율성 측면에서의 다양한 발전과 함께 WebAssembly를 제공합니다.

* 하나의 모듈은 하나의 함수 리터럴이 N 개의 클로저 값을 생성 할 수있는 것과 같은 방식으로 N 개의 인스턴스를 가질 수 있습니다.
* 하나의 모듈 인스턴스는 인스턴스의 "주소 공간"을 제공하는 0-1 메모리 인스턴스를 사용할 수 있습니다. WebAssembly의 이후 버전에서는 모듈 인스턴스 당 0-N 개의 메모리 인스턴스가 허용 될 수 있습니다 (Multiple Tables and Memories 참조).
* 하나의 모듈 인스턴스는 0-1 테이블 인스턴스를 사용할 수 있습니다. 이것은 C 함수 포인터를 구현하는 데 사용되는 인스턴스의 "함수 주소 공간"입니다. WebAssembly의 향후 버전에서는 향후 모듈 인스턴스 당 0-N 테이블 인스턴스를 허용 할 수 있습니다.
* 하나의 메모리 또는 테이블 인스턴스는 0-N 모듈 인스턴스에서 사용할 수 있습니다.이 인스턴스는 모두 동일한 주소 공간을 공유하므로 dynamic linking이 가능합니다.

Understanding text format에서 multiplicity in action를 확인 할 수있습니다. - Mutating tables and dynamic linking section을 참조하십시오.

요약
--

여기서 WebAssembly JavaScript API를 사용하여 JavaScript 컨텍스트에 WebAssembly 모듈을 포함하고 해당 기능을 사용하는 방법과 JavaScript에서 WebAssembly 메모리 및 테이블을 사용하는 방법에 대해 살펴 보았습니다. 그리고 다중성의 개념에 대해서도 언급했습니다.

바깥 고리
-----

* webassembly.org
* WebAssembly concepts
* WebAssembly on Mozilla Research


WebAssembly - 웹어셈블리

WebAssembly
===========

**`WebAssembly`** JavaScript 객체는 모든 WebAssembly에 관계된 기능의 네임스페이스로서 역할합니다.

대부분의 전역객체와 다르게, `WebAssembly`는 생성자가 아닙니다 (함수 객체가 아닙니다). 비슷한 예로 수학적인 상수나 함수들을 담고있는 `Math` 객체나, 국제화 관련 생성자나 언어에 민감한 다른 함수들을 담고있는 `Intl` (en-US) 등이 있습니다.

설명
--

`WebAssembly` 객체의 기본적인 사용례는 다음과 같습니다:

* `WebAssembly.instantiate()` 함수를 사용해서 웹어셈블리 코드 불러오기.
* `WebAssembly.Memory()`/`WebAssembly.Table()` 생성자로 새 메모리와 테이블 인스턴스 생성하기.
* `WebAssembly.CompileError()`/`WebAssembly.LinkError()`/`WebAssembly.RuntimeError()` 생성자로 웹어셈블리에서 발생하는 에러에 대한 처리장치 만들기.
메서드
---

`WebAssembly.instantiate()`

WebAssembly 코드를 컴파일하고 인스턴스화하여 `Module`과 첫 번째 `Instance`를 반환하는 기본 API입니다.

`WebAssembly.instantiateStreaming()`

스트리밍 된 원본 소스에서 직접 WebAssembly 모듈을 컴파일하고 인스턴스화하여 `Module`과 첫 번째 `Instance`를 반환합니다.

`WebAssembly.compile()`

WebAssembly 바이너리 코드에서 `WebAssembly.Module`을 컴파일하여 인스턴스화를 별도의 단계로 남겨 둡니다.

`WebAssembly.compileStreaming()`

`WebAssembly.Module`을 스트림 된 원본 소스에서 직접 컴파일하여 인스턴스화를 별도의 단계로 남겨 둡니다.

`WebAssembly.validate()`

바이트가 유효한 WebAssembly 코드 (`true`)인지 아닌지 (`false`)를 반환하여 WebAssembly 바이너리 코드의 지정된 입력 된 배열을 확인합니다.

생성자
---

`WebAssembly.Global()`

Creates a new WebAssembly `Global` object.

`WebAssembly.Module()`

Creates a new WebAssembly `Module` object.

`WebAssembly.Instance()`

Creates a new WebAssembly `Instance` object.

`WebAssembly.Memory()`

Creates a new WebAssembly `Memory` object.

`WebAssembly.Table()`

Creates a new WebAssembly `Table` object.

`WebAssembly.CompileError()`

Creates a new WebAssembly `CompileError` object.

`WebAssembly.LinkError()`

Creates a new WebAssembly `LinkError` object.

`WebAssembly.RuntimeError()`

Creates a new WebAssembly `RuntimeError` object.

예제
--

다음 예제 (GitHub의 instantiate-streaming.html 데모보기 및 라이브보기)에서는 기본 소스에서 .wasm 모듈을 직접 스트리밍 한 다음 컴파일하고 인스턴스화합니다. 프로미스는 `ResultObject`로 충족됩니다. `instantiateStreaming()` 함수는 `Response` 객체에 대한 promise를 받아들이므로 직접 `fetch()` 호출에 전달할 수 있습니다.

```js
var importObject = { imports: { imported\_func: (arg) => console.log(arg) } };

WebAssembly.instantiateStreaming(fetch("simple.wasm"), importObject).then(
  (obj) => obj.instance.exports.exported\_func(),
);
```

그런 다음 ResultObject의 인스턴스 구성에 액세스하고 그 안에 있는 `exported_func`을 호출합니다.

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # webassembly-namespace |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

바깥 고리
-----

* 웹어셈블리 개요 페이지
* 웹어셈블리의 컨셉
* Using the WebAssembly JavaScript API


Compiling an Existing C Module to WebAssembly - 웹어셈블리

Compiling an Existing C Module to WebAssembly
=============================================

WebAssembly의 핵심 Use-case는 기존의 C 라이브러리 생태계를 사용하고 개발자가 웹에서 사용할 수 있도록하는 것입니다.

이러한 라이브러리는 종종 C의 표준 라이브러리, 운영 체제, 파일 시스템 및 기타 사항에 의존합니다. Emscripten은 이러한 기능 대부분을 제공하지만 몇 가지 제한 사항이 있습니다.

예를 들어, WebP 용 인코더를 컴파일 해 봅시다. WebP(웹용 이미지 포맷) 코덱의 소스는 C로 작성되었으며 GitHub에서 사용가능할뿐 아니라 광범위한 API documentation로도 제공됩니다. 꽤 좋은 출발점입니다.

```bash
git clone https://github.com/webmproject/libwebp
```

간단히 시작하려면 `webp.c`라는 C 파일을 작성하여 `encode.h`의 `WebPGetEncoderVersion()` 을 JavaScript로 노출 시키십시오.

```cpp
#include "emscripten.h"
#include "src/webp/encode.h"

EMSCRIPTEN_KEEPALIVE
int version() {
  return WebPGetEncoderVersion();
}
```

이 함수를 호출하기 위해 매개 변수 나 복잡한 데이터 구조가 필요 없기 때문에 libwebp의 소스 코드를 컴파일 할 수 있는지 여부를 테스트하는 좋은 간단한 프로그램입니다.

이 프로그램을 컴파일하려면 -I 플래그를 사용하여 libwebp의 헤더 파일을 어디에서 찾을 수 있는지 컴파일러에게 알려야하며 필요한 libwebp의 모든 C 파일을 전달해야합니다. 유용한 전략은 **모든** C 파일을 제공하고 컴파일러에 의존하여 불필요한 모든 것을 제거하는 것입니다. 그것은 훌륭하게 작동할 것입니다.

```bash
$ emcc -O3 -s WASM=1 -s EXTRA\_EXPORTED\_RUNTIME\_METHODS='["cwrap"]' \
    -I libwebp \
    webp.c \
    libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c
```

**참고:** 이 전략은 모든 C 프로젝트에서 작동하지 않습니다. 많은 프로젝트는 컴파일하기 전에 시스템 특정 코드를 생성하기 위해 autoconf / automake를 사용합니다. Emscripten은 `emconfigure`와 `emmake`를 제공하여 이 명령을 랩핑하고 적절한 매개 변수를 주입합니다. Emscripten documentation에서 자세한 내용을 찾을 수 있습니다.

이제 새 모듈을 로드하기 위해 HTML과 JavaScript 만 있으면 됩니다.

```html
<script src="./a.out.js"></script>
<script>
 Module.onRuntimeInitialized = async (\_) => {
 const api = {
 version: Module.cwrap("version", "number", []),
 };
 console.log(api.version());
 };
</script>
```

output에 라이브러리의 버전 번호가 정확히 표시됩니다.

![Screenshot of the DevTools console showing the correct versionnumber.](/ko/docs/WebAssembly/existing_C_to_Wasm/version.png)

>
> \*\*참고:\*\*libwebp는 현재 버전 인 a.b.c를 16 진수 0xabc로 반환합니다. 예를 들어 v0.6.1은 0x000601 = 1537로 인코딩됩니다.
>
>
>

### Get an image from JavaScript into Wasm

인코더의 버전 번호를 얻는 것은 좋지만 실제 이미지 인코딩은 더욱 인상적입니다.

자 여기서! 어떻게하면 이미지를 wasm으로 가져올 수 있는지가 가장 먼저 궁굼할 것입니다. encoding API of libwebp를 보면 RGB, RGBA, BGR 또는 BGRA의 바이트 배열이 필요함을 알 수 있습니다. 다행히 Canvas API에는 RGBA의 이미지 데이터가 포함 된 `Uint8ClampedArray`를 던져주는 `CanvasRenderingContext2D.getImageData` (en-US)가 있습니다.

```js
async function loadImage(src) {
  // Load image
  const imgBlob = await fetch(src).then((resp) => resp.blob());
  const img = await createImageBitmap(imgBlob);
  // Make canvas same size as image
  const canvas = document.createElement("canvas");
  canvas.width = img.width;
  canvas.height = img.height;
  // Draw image onto canvas
  const ctx = canvas.getContext("2d");
  ctx.drawImage(img, 0, 0);
  return ctx.getImageData(0, 0, img.width, img.height);
}
```

이제 이것은 자바 스크립트에서 wasm로 데이터를 복사하는 것만이 남았습니다. 이를 위해서 두 가지 추가 기능, 즉 wasm 내부의 이미지에 메모리를 할당하는 기능과 다시 해제 할 수있는 기능을 노출해야합니다.

```cpp
#include <stdlib.h> // required for malloc definition

EMSCRIPTEN_KEEPALIVE
uint8\_t\* create\_buffer(int width, int height) {
  return malloc(width \* height \* 4 \* sizeof(uint8\_t));
}

EMSCRIPTEN_KEEPALIVE
void destroy\_buffer(uint8\_t\* p) {
  free(p);
}
```

`create_buffer()` 함수는 RGBA 이미지에 대한 버퍼를 할당하므로 픽셀 당 4 바이트입니다. `malloc()`에 의해 반환 된 포인터는 그 버퍼의 첫번째 메모리 셀의 주소입니다. 포인터가 JavaScript 토큰으로 반환되면 포인터는 숫자로 취급됩니다. cwrap을 사용하여 JavaScript에 함수를 노출 한 후에는 해당 번호를 사용하여 버퍼의 시작 부분을 찾고 이미지 데이터를 복사 할 수 있습니다.

```js
const api = {
  version: Module.cwrap("version", "number", []),
  create\_buffer: Module.cwrap("create\_buffer", "number", ["number", "number"]),
  destroy\_buffer: Module.cwrap("destroy\_buffer", "", ["number"]),
};

const image = await loadImage("./image.jpg");
const p = api.create\_buffer(image.width, image.height);
Module.HEAP8.set(image.data, p);
// ... call encoder ...
api.destroy\_buffer(p);
```

### Encode the Image

이제 wasm에서 이미지를 사용할 수 있습니다. 이번엔 WebP 인코더를 호출하여 작업을 수행 할 차례입니다. WebP documentation을 보면 `WebPEncodeRGBA`가 가장 적합한 것 같습니다. 이 함수는 0과 100 사이의 품질 옵션뿐만 아니라 입력 이미지 및 치수에 대한 포인터를 사용합니다. 또한 WebP 이미지가 완료되면 `WebPFree()`를 사용하여 해제해야하는 출력 버퍼를 할당합니다.

인코딩 작업의 결과는 출력 버퍼와 그 길이입니다. C의 함수는 메모리를 동적으로 할당하지 않는 한 반환 유형으로 배열을 가질 수 없으므로 이 예제는 정적 전역 배열에 의존합니다. 실제로는 32 비트 폭의 wasm 포인터에 의존합니다. 그러나 이것은 일을 단순하게 유지하는 적절한 방법입니다.

```js
int result[2];
EMSCRIPTEN\_KEEPALIVE
void encode(uint8\_t\* img\_in, int width, int height, float quality) {
  uint8_t\* img_out;
  size_t size;

  size = WebPEncodeRGBA(img_in, width, height, width \* 4, quality, &img_out);

  result[0] = (int)img_out;
  result[1] = size;
}

EMSCRIPTEN\_KEEPALIVE
void free\_result(uint8\_t\* result) {
  WebPFree(result);
}

EMSCRIPTEN\_KEEPALIVE
int get\_result\_pointer() {
  return result[0];
}

EMSCRIPTEN\_KEEPALIVE
int get\_result\_size() {
  return result[1];
}
```

이제 그 모든 것을 갖추면 인코딩 함수를 호출하고 포인터와 이미지 크기를 가져 와서 자신의 JavaScript 버퍼에 넣은 다음 프로세스에 할당 된 모든 Wasm 버퍼를 해제 할 수 있습니다.

```js
api.encode(p, image.width, image.height, 100);
const resultPointer = api.get\_result\_pointer();
const resultSize = api.get\_result\_size();
const resultView = new Uint8Array(
  Module.HEAP8.buffer,
  resultPointer,
  resultSize,
);
const result = new Uint8Array(resultView);
api.free\_result(resultPointer);
```

**참고:** `new Uint8Array(someBuffer)`는 `new Uint8Array(someTypedArray)`가 데이터를 복사하는 동안 동일한 memory chunk에 새로운 뷰를 생성합니다.

이미지의 크기에 따라, wasm이 입력 및 출력 이미지를 모두 수용할 만큼 메모리를 늘릴 수 없는 오류가 발생할 수 있습니다.

![Screenshot of the DevTools console showing an error.](/ko/docs/WebAssembly/existing_C_to_Wasm/error.png)

다행히도 이 문제에 대한 해결책은 오류 메시지에 있습니다. 컴파일 명령에 `-s ALLOW_MEMORY_GROWTH=1`을 추가하기 만하면됩니다.

WebP 인코더를 컴파일하고 JPEG 이미지를 WebP로 코드 변환했습니다. 제대로 동작하는지 확인하기 위해 결과 버퍼를 블롭으로 변환하고 `<img>` 요소에 사용합니다.

```js
const blob = new Blob([result], { type: "image/webp" });
const blobURL = URL.createObjectURL(blob);
const img = document.createElement("img");
img.src = blobURL;
document.body.appendChild(img);
```

보거라! 새로운 WebP 이미지의 영광을. :) Demo | Full Code

![DevToolsâ network panel and the generated image.](/ko/docs/WebAssembly/existing_C_to_Wasm/result.jpg)


Exported WebAssembly functions - 웹어셈블리

Exported WebAssembly functions
==============================

Exported WebAssembly functions는 JavaScript에서 WebAssembly 함수를 나타내는 방법입니다. 여기서는 이 함수들에 대해 더 자세히 설명합니다.

Exported... 뭐요?
---------------

내보낸 WebAssembly 함수는 기본적으로 JavaScript에서 WebAssembly 함수를 나타내는 JavaScript 래퍼입니다. 호출 할 때 배경에서 백그라운드로 액티비티를 가져와 wasm이 작업 할 수있는 유형 (예 : JavaScript 숫자를 Int32로 변환)으로 변환하고, 인수가 wasm 모듈 내부의 함수로 전달되고, 함수가 호출되며, 결과가 변환되어 JavaScript로 다시 전달됩니다.

두 가지 방법으로 내 보낸 WebAssembly 함수를 검색 할 수 있습니다.

* 기존 테이블에서 `Table.prototype.get()` (en-US)을 호출합니다.
* `Instance.exports` (en-US)를 통해 wasm 모듈 인스턴스에서 내보낸 함수에 액세스합니다.

어느 쪽이든, 기본 함수에 대해 동일한 종류의 래퍼를 사용합니다. JavaScript의 관점에서 볼 때, 모든 wasm 함수가 JavaScript 함수이기도하지만 - 내보낸 wasm 함수 객체 인스턴스에 의해 캡슐화되며 액세스 할 수있는 제한된 방법이 있습니다.

An example
----------

예제를 보겠습니다. (GitHub의 table-set.html로 찾을 수 있으며 실시간으로 보기(running live also)도 참고하시고. wasm text representation 표현도 확인하세요).

```js
var otherTable = new WebAssembly.Table({ element: "anyfunc", initial: 2 });

WebAssembly.instantiateStreaming(fetch("table.wasm")).then((obj) => {
  var tbl = obj.instance.exports.tbl;
  console.log(tbl.get(0)()); // 13
  console.log(tbl.get(1)()); // 42
  otherTable.set(0, tbl.get(0));
  otherTable.set(1, tbl.get(1));
  console.log(otherTable.get(0)());
  console.log(otherTable.get(1)());
});
```

`WebAssembly.Table`생성자를 사용하여 JavaScript에서 테이블 (`otherTable`)을 만든 다음 `WebAssembly.instantiateStreaming()`를 메서드를 사용하여 table.wasm를 우리가 만든 페이지에 로드합니다.

그런 다음 모듈에서 함수를 내보내고 `tbl.get()` (en-US)을 통해 참조하는 함수를 검색하고 각 함수를 호출 한 결과를 콘솔에 기록합니다. 그런 다음 `set()`을 사용하여 `otherTable` 테이블에 tbl 테이블과 동일한 함수에 대한 참조가 포함되도록합니다.

이를 증명하기 위해 우리는 이러한 참조를 `otherTable`에서 다시 검색하여 그 결과를 콘솔에도 출력하므로 동일한 결과를 얻을 수 있습니다.

They are real functions
-----------------------

앞의 예에서 각 `Table.prototype.get()` (en-US) 호출의 반환 값은 내 보낸 WebAssembly 함수입니다. 이전에 우리가 이야기했던 대로입니다.

이것들은 WebAssembly 함수에 대한 래퍼 (wrapper)가 될뿐만 아니라 실제 JavaScript 함수임을 주목할 필요가 있습니다. 위의 예제를 WebAssembly-supporting browser에 로드하고 콘솔에서 다음 줄을 실행하세요.

```js
var testFunc = otherTable.get(0);
typeof testFunc;
```

그러면 결과 함수(`function`)가 반환됩니다. 그런 다음 JavaScript에서 `call()`, `bind()` 등의 다른 functions를 수행 할 수 있는 기능을 수행 할 수 있습니다. `testFunc.toString()`은 흥미로운 결과를 반환합니다.

```js
function 0() {
    [native code]
}
```

이렇게하면 wrapper-type의 본질에 대해 더 많이 알 수 있습니다.

exported WebAssembly functions에 대해 알아야 할 몇 가지 사항은 다음과 같습니다.

* length 속성은 wasm 함수 시그니처에 선언 된 인수의 개수입니다.
* name 속성은 wasm 모듈에서 함수의 인덱스에 대한 `toString()` 결과입니다.
* i64 유형 값을 사용하거나 가져 오는 내 보낸 wasm 함수를 호출하려고하면 JavaScript는 현재 i64를 정확하게 표현할 방법이 없기 때문에 현재 오류가 발생합니다. 이후에 개선 될 것입니다. - 새로운 int64 유형이 wasm에 의해 사용될 수 있도록 향후 표준으로 고려되고 있습니다.


Loading and running WebAssembly code - 웹어셈블리

Loading and running WebAssembly code
====================================

자바 스크립트에서 WebAssembly를 사용하려면 먼저 컴파일 / 인스턴스화 전에 모듈을 메모리로 가져와야합니다. 여기서 WebAssembly 바이트 코드를 가져 오는 데 사용할 수있는 다양한 메커니즘에 대한 참조와 함께 컴파일 / 인스턴스화 및 실행 방법에 대해 설명합니다.

뭐가 문제인가요 ?
----------

WebAssembly는 아직 `<script type='module'>` 또는 ES2015 `import` statements와 통합되어 있지 않으므로 imports를 사용하여 브라우저에서 가져올 방법이 없습니다.

이전의 `WebAssembly.compile` / `WebAssembly.instantiate` 메소드를 사용하려면 WebAssembly 모듈 바이너리를 포함하는 `ArrayBuffer`를 생성해야합니다. 원시 바이트를 가져온 다음 컴파일 / 인스턴스화합니다. 이것은 `new Function(string)`과 유사합니다. 단, 문자열 (JavaScript 소스 코드)을 바이트 배열 버퍼 (WebAssembly 소스 코드)로 대체한다는 점만 다릅니다.

 최신 `WebAssembly.compileStreaming`/`WebAssembly.instantiateStreaming` 방법이 훨씬 더 효율적입니다.
 네트워크에서는 `ArrayBuffer` 단계가 필요하지 않게 하면서 직접 바이트의 원시 스트림에 대한 작업을 수행합니다.

그러면 어떻게 이 바이트를 어레이 버퍼에 넣고 컴파일할 수 있을까요? 다음 단원에서 설명합니다.

Using Fetch
-----------

Fetch는 네트워크 리소스를 가져 오는 편리한 최신 API입니다.

wasm 모듈을 가져오는 가장 빠르고 효율적인 방법은 새로운 `WebAssembly.instantiateStreaming()` 방법을 사용하는 것입니다. 이 method는 첫번째 인수로 fetch() 호출을 수행할 수 있는 메서드이며, 서버에서 스트리밍할 때 원시 바이트 코드에 액세스하면서 모듈 가져오기, 컴파일 및 인스턴스화를 한 번에 처리합니다.

```js
WebAssembly.instantiateStreaming(fetch("simple.wasm"), importObject).then(
  (results) => {
    // Do something with the results!
  },
);
```

직접 스트림에서 작동하지 않는 이전 `WebAssembly.instantiate` 메서드를 사용한 경우에는 가져온 바이트 코드를 `ArrayBuffer` 로 변환하는 추가단계가 필요합니다.

```js
fetch("module.wasm")
  .then((response) => response.arrayBuffer())
  .then((bytes) => WebAssembly.instantiate(bytes, importObject))
  .then((results) => {
    // Do something with the results!
  });
```

### Aside on instantiate() overloads

`WebAssembly.instantiate()` 함수에는 두 가지 오버로드 양식이 있습니다. 위에 표시된 형식은 바이트 코드를 인수로 컴파일하여 컴파일된 모듈 객체가 포함된 개체로 resolve되는 'promise'을 반환합니다. 개체는 다음과 같습니다.

```js
{
  module: Module; // The newly compiled WebAssembly.Module object,
  instance: Instance; // A new WebAssembly.Instance of the module object
}
```

**참고:** 일반적으로 인스턴스자체만 신경 쓰지만, 모듈을 캐시하거나, `postMessage()` (en-US)를 통해 다른 worker나 윈도우와 공유하거나, 단순히 인스턴스를 더 생성하고자 할 때도 유용합니다.

**참고:** 두 번째 오버로드 형식은 `WebAssembly.Module` 객체를 인수로 사용하여 인스턴스 객체를 직접 포함하는 promise를 결과로 반환합니다. Second overload 예제를 참조하십시오.

### Running your WebAssembly code

JavaScript에서 WebAssembly 인스턴스를 사용할 수있게되면 `WebAssembly.Instance.exports` (en-US) 속성을 통해 내 보낸 속성을 사용할 수 있습니다 . 코드는 다음과 같습니다.

```js
WebAssembly.instantiateStreaming(fetch("myModule.wasm"), importObject).then(
  (obj) => {
    // Call an exported function:
    obj.instance.exports.exported\_func();

    // or access the buffer contents of an exported memory:
    var i32 = new Uint32Array(obj.instance.exports.memory.buffer);

    // or access the elements of an exported table:
    var table = obj.instance.exports.table;
    console.log(table.get(0)());
  },
);
```

**참고:** WebAssembly 모듈에서 내보내는 방법에 대한 자세한 내용은 Using the WebAssembly JavaScript API 및 Understanding WebAssembly text format를 참조하십시오.

Using XMLHttpRequest
--------------------

`XMLHttpRequest`는 Fetch보다 다소 오래된 방법이지만 형식화 된 배열을 얻는 데 부족함이 없습니다. `simple.wasm`을 그대로 사용하여 진행하겠습니다.

1. 새로운 `XMLHttpRequest()` 인스턴스를 만들고 `open()` (en-US) 메서드를 사용하여 요청을 열고 요청 메서드를 GET으로 설정합니다. , 가져올 파일의 경로를 선언하십시오.
2. 핵심 부분은 `responseType` (en-US) 속성을 사용하여 응답 유형을 `'arraybuffer'`로 설정하는 것입니다.
3. 그런 다음 `XMLHttpRequest.send()` (en-US)을 사용하여 요청을 전송합니다.
4. 그런 다음 응답이 다운로드 완료되면 함수를 호출하기 위해 `onload` 이벤트 핸들러를 사용합니다. 이 함수에서는 `response` (en-US) 프로퍼티를 생성 한 다음, Fetch와 마찬가지로 `WebAssembly.instantiate()` 메소드로 넘겨 줍니다.

최종코드는 다음과 같습니다.

```js
request = new XMLHttpRequest();
request.open("GET", "simple.wasm");
request.responseType = "arraybuffer";
request.send();

request.onload = function () {
  var bytes = request.response;
  WebAssembly.instantiate(bytes, importObject).then((results) => {
    results.instance.exports.exported\_func();
  });
};
```

**참고:** xhr-wasm.html 에서도 예제를 확인할 수 있습니다.