루프와 반복 - JavaScript

루프와 반복
======

* « 이전
* 다음 »

루프는 어떤 것을 반복적으로 시행할때 빠르고 간편한 방법을 제공합니다. JavaScript Guide의 이 항목은 JavaScript 에서 사용이 가능한 서로 다른 여러가지 반복문을 소개합니다.

반복문을 게임의 컴퓨터화된 버전이라고 생각해 보세요. 누군가에게 한 방향으로 X만큼 가게 시키고 다른 방향으로 Y만큼 더 가게 한다고 생각해 보십시오. 예를들어, "동쪽으로 5만큼 가세요"는 다음과 같이 반복문으로 표현 될 수 있습니다.

```js
var step;
for (step = 0; step < 5; step++) {
  // Runs 5 times, with values of step 0 through 4.
  console.log("Walking east one step");
}
```

반복문은 매우 다양한 종류가 있습니다. 하지만 반복문이 기본적으로 하는일은 모두 같습니다. 반복문은 한 동작을 여러 번 반복합니다. (사실 0회 반복하는 것도 가능합니다.) 다양한 반복문 메커니즘은 다양한 방법으로 반복문의 시작점과 끝나는 점을 정할 수 있습니다.

JavaScript가 지원하는 반복문은 다음과 같습니다:

* for 문
* do...while 문
* while 문
* 레이블 문
* break 문
* continue 문
* for...in 문
* for...of 문
`for` 문
-------

for 반복문은 어떤 특정한 조건이 거짓으로 판별될 때까지 반복합니다. JavaScript의 반복문은 C의 반복문과 비슷합니다. for 반복문은 다음과 같습니다.
```

    for ([초기문]; [조건문]; [증감문])
      문장
```

for문이 실행될 때, 다음과 같이 실행됩니다.:

1. 초기화 구문인 초기문이 존재한다면 초기문이 실행됩니다. 이 표현은 보통 1이나 반복문 카운터로 초기 설정이 됩니다. 그러나 복잡한 구문으로 표현 될 때도 있습니다. 또한 변수로 선언 되기도 합니다.
2. 조건문은 조건을 검사합니다. 만약 조건문이 참이라면, 그 반복문은 실행됩니다. 만약 조건문이 거짓이라면, 그 for문은 종결됩니다. 만약 그 조건문이 생략된다면, 그 조건문은 참으로 추정됩니다.
3. 문장이 실행됩니다. 많은 문장을 실행할 경우엔, { } 를 써서 문장들을 묶어 줍니다.
4. 갱신 구문인 증감문이 존재한다면 실행되고 2번째 단계로 돌아갑니다.
### **예시**

다음 함수는 스크롤링 목록(다중 선택을 허용하는 요소 `<select>` (en-US)). 에서 선택된 옵션들을 세는 for문 입니다. 이 for문은 변수 i 를 선언하고 0으로 초기화 시킵니다. 이것은 i 가 <select> 요소 안의 옵션 수가 i 보다 작은지 확인 합니다. 다음의 if문을 수행하고 각 루프를 빠져나간 뒤 i 를 1 증가시킵니다.

```html
<form name="selectForm">
  <p>
    <label for="musicTypes"
 >Choose some music types, then click the button below:</label
 >
    <select id="musicTypes" name="musicTypes" multiple="multiple">
      <option selected="selected">R&B</option>
      <option>Jazz</option>
      <option>Blues</option>
      <option>New Age</option>
      <option>Classical</option>
      <option>Opera</option>
    </select>
  </p>
  <p><input id="btn" type="button" value="How many are selected?" /></p>
</form>

<script>
 function howMany(selectObject) {
 var numberSelected = 0;
 for (var i = 0; i < selectObject.options.length; i++) {
 if (selectObject.options[i].selected) {
 numberSelected++;
 }
 }
 return numberSelected;
 }

 var btn = document.getElementById("btn");
 btn.addEventListener("click", function () {
 alert(
 "Number of options selected: " + howMany(document.selectForm.musicTypes),
 );
 });
</script>
```

`do...while` 문
--------------

do...while 문은 특정한 조건이 거짓으로 판별될 때까지 반복합니다. do...while 문은 다음과 같습니다.
```

    do
      문장
    while (조건문);
```

`조건문을 확인하기 전에 문장은 한번 실행됩니다. 많은 문장을 실행하기 위해선 { }를 써서 문장들을 묶어줍니다. 만약 조건이 참이라면, 그 문장은 다시 실행됩니다. 매 실행 마지막마다 조건문이 확인됩니다. 만약 조건문이 거짓일 경우, 실행을 멈추고 do...while 문 바로 아래에 있는 문장으로 넘어가게 합니다.`

### **예시**

다음 예제에서, do 반복문은 최소 한번은 반복됩니다. 그리고 i 가 5보다 작지 않을 때까지 계속 반복됩니다.

```js
do {
  i += 1;
  console.log(i);
} while (i < 5);
```

`while` 문
---------

while 문은 어떤 조건문이 참이기만 하면 문장을 계속해서 수행합니다. while 문은 다음과 같습니다.
```

    while (조건문)
      문장
```

만약 조건문이 거짓이 된다면, 그 반복문 안의 문장은 실행을 멈추고 반복문 바로 다음의 문장으로 넘어갑니다.

조건문은 반복문 안의 문장이 실행되기 전에 확인 됩니다. 만약 조건문이 참으로 리턴된다면, 문장은 실행되고 그 조건문은 다시 판별됩니다. 만약 조건문이 거짓으로 리턴된다면, 실행을 멈추고 while문 바로 다음의 문장으로 넘어가게 됩니다.

많은 문장들을 실행하기 위해선, { }를 써서 문장들을 묶어줍니다.

### **예시 1**

다음 while 반복문은 n이 3보다 작은 한, 계속 반복됩니다.

```js
n = 0;
x = 0;
while (n < 3) {
  n++;
  x += n;
}
```

매 반복과 함께, n이 증가하고 x에 더해집니다. 그러므로, x와 n은 다음과 같은 값을 갖습니다.

* 첫번째 경과 후: `n` = 1 and `x` = 1
* 두번째 경과 후: `n` = 2 and `x` = 3
* 세번째 경과 후: `n` = 3 and `x` = 6

세번째 경과 후에, n < 3 은 더이상 참이 아니므로, 반복문은 종결됩니다.

### **예시 2**

조건문은 항상 거짓이 될지라도 무한 루프는 피해야 합니다. 그렇지 않으면 그 반복문은 영원히 끝나지 않을 것입니다. 아래의 while 문은 조건문이 절대 거짓이 될 수 없으므로 영원히 반복될 것입니다.

```js
// 다음과 같은 코드는 피하세요.
while (true) {
  console.log("Hello, world");
}
```

레이블 문
-----

레이블은 여러분이 프로그램에서 다른 곳으로 참조할 수 있도록 식별자로 문을 제공합니다. 예를 들어, 여러분은 루프를 식별하기 위해 레이블을 사용하고, 프로그램이 루프를 방해하거나 실행을 계속할지 여부를 나타내기 위해 break나 continue 문을 사용할 수 있습니다.

레이블 문의 구문은 다음과 같습니다:
```

    label :
       statement
```

레이블 값은 예약어가 아닌 임의의 JavaScript 식별자일 수 있습니다. 여러분이 레이블을 가지고 식별하는 문은 어떠한 문이 될 수 있습니다.

### **예시**

이 예에서, 레이블 markLoop는 while 루프를 식별합니다.

```js
markLoop: while (theMark == true) {
  doSomething();
}
```

`break` 문
---------

break문은 반복문, switch문, 레이블 문과 결합한 문장을 빠져나올 때 사용합니다.

* 레이블 없이 break문을 쓸 때: 가장 가까운 `while`, `do-while`, `for`, 또는 `switch`문을 종료하고 다음 명령어로 넘어갑니다.
* 레이블 문을 쓸 때: 특정 레이블 문에서 끝납니다.

break문의 문법은 다음과 같습니다.

1. `break;`
2. `break [레이블];`

break문의 첫번째 형식은 가장 안쪽의 반복문이나 switch문을 빠져나옵니다. 두번째 형식는 특정한 레이블 문을 빠져나옵니다.

### **예시** **1**

다음 예

```js
for (i = 0; i < a.length; i++) {
  if (a[i] == theValue) {
    break;
  }
}
```

### **예시 2:** Breaking to a label

```js
var x = 0;
var z = 0;
labelCancelLoops: while (true) {
  console.log("Outer loops: " + x);
  x += 1;
  z = 1;
  while (true) {
    console.log("Inner loops: " + z);
    z += 1;
    if (z === 10 && x === 10) {
      break labelCancelLoops;
    } else if (z === 10) {
      break;
    }
  }
}
```

continue 문
----------

`continue` 문은 while, do-while, for, 레이블 문을 다시 시작하기 위해 사용될 수 있습니다.

* 레이블없이 continue를 사용하는 경우, 그것은 가장 안쪽의 while, do-while, for 문을 둘러싼 현재 반복을 종료하고, 다음 반복으로 루프의 실행을 계속합니다. break문과 달리, continue 문은 전체 루프의 실행을 종료하지 않습니다. while 루프에서 그것은 다시 조건으로 이동합니다. for 루프에서 그것은 증가 표현으로 이동합니다.
* 레이블과 함께 continue를 사용하는 경우, continue는 그 레이블로 식별되는 루프 문에 적용됩니다.

continue 문의 구문은 다음과 같습니다:

1. `continue;`
2. `continue`*`label;`*
### **예시 1**

다음의 예는 i 값이 3일 때 실행하는 continue 문과 함께 while 루프를 보여줍니다. 따라서, n은 값 1, 3, 7, 12를 취합니다.

```js
i = 0;
n = 0;
while (i < 5) {
  i++;
  if (i == 3) {
    continue;
  }
  n += i;
}
```

### **예시 2**

checkiandj 레이블 문은 checkj 레이블 문을 포함합니다. continue가 발생하는 경우, 프로그램은 checkj의 현재 반복을 종료하고, 다음 반복을 시작합니다. 그 조건이 false를 반환 할 때까지 continue가 발생할 때마다, checkj는 반복합니다. false가 반환될 때, checkiandj 문의 나머지 부분은 완료되고, 그 조건이 false를 반환 할 때까지 checkiandj는 반복합니다. false가 반환될 때, 이 프로그램은 다음 checkiandj 문에서 계속됩니다.

continue가 checkiandj의 레이블을 가지고 있다면, 프로그램은 checkiandj 문 상단에서 계속될 것입니다.

```js
checkiandj: while (i < 4) {
  console.log(i);
  i += 1;
  checkj: while (j > 4) {
    console.log(j);
    j -= 1;
    if (j % 2 == 0) {
      continue checkj;
    }
    console.log(j + " is odd.");
  }
  console.log("i = " + i);
  console.log("j = " + j);
}
```

`for...in` 문
------------

`for...in` 문은 객체의 열거 속성을 통해 지정된 변수를 반복합니다. 각각의 고유한 속성에 대해, JavaScript는 지정된 문을 실행합니다. for...in 문은 다음과 같습니다:
```

for (variable in object) {
  statements
}
```

### **예시**

다음 함수는 객체와 객체의 이름을 함수의 인수로 취합니다. 그런 다음 모든 객체의 속성을 반복하고 속성 이름과 값을 나열하는 문자열을 반환합니다.

```js
function dump\_props(obj, obj\_name) {
  var result = "";
  for (var i in obj) {
    result += obj_name + "." + i + " = " + obj[i] + "<br>";
  }
  result += "<hr>";
  return result;
}
```

속성 make와 model을 가진 객체 car의 경우, 결과는 다음과 같습니다:

```js
car.make = Ford;
car.model = Mustang;
```

### **배열**

`배열` 요소를 반복하는 방법으로 이를 사용하도록 유도될 수 있지만, **for...in** 문은 숫자 인덱스에 추가하여 사용자 정의 속성의 이름을 반환합니다. 따라서 만약 여러분이 사용자 정의 속성 또는 메서드를 추가하는 등 Array 객체를 수정한다면, 배열 요소 이외에도 사용자 정의 속성을 통해 **for...in** 문을 반복하기 때문에, 배열을 통해 반복할 때 숫자 인덱스와 전통적인 `for` 루프를 사용하는 것이 좋습니다.

`for...of` 문
------------

`for...of` 문은 각각의 고유한 특성의 값을 실행할 명령과 함께 사용자 지정 반복 후크를 호출하여, 반복 가능한 객체 (en-US)(`배열`, `Map`, `Set` (en-US), 인수 (en-US) 객체 등을 포함)를 통해 반복하는 루프를 만듭니다.
```

    for (variable of object) {
      statement
    }
```

다음 예는 for...of 루프와 `for...in` 루프의 차이를 보여줍니다. 속성 이름을 통해 for...in이 반복하는 동안, for...of은 속성 값을 통해 반복합니다:

```js
let arr = [3, 5, 7];
arr.foo = "hello";

for (let i in arr) {
  console.log(i); // logs "0", "1", "2", "foo"
}

for (let i of arr) {
  console.log(i); // logs "3", "5", "7"
}
```

* « 이전
* 다음 »


JavaScript modules - JavaScript

JavaScript modules
==================

* « 이전 (en-US)

이 가이드는 JavaScript 모듈 구문을 시작하는데 필요한 모든 것을 제공합니다.

A background on modules
-----------------------

JavaScript 프로그램은 꽤 작게 시작되었습니다. 초기에 사용 된 대부분의 스크립트는 독립적인 작업을 수행하여, 필요한 경우 웹 페이지에 약간의 상호 작용을 제공하므로 일반적으로 큰 스크립트가 필요하지 않았습니다. 몇년 후 JavaScript는 많은 브라우저에서 실행되고 있는 완전한 애플리케이션을 실행할 수 있을 뿐 아니라, 다른 컨텍스트에서 (예를들면 Node.js) JavaScript를 사용하게 됩니다.

따라서 최근 몇 년 동안 JavaScript 프로그램을 필요에 따라 가져올 수 있는, 별도의 모듈로 분할하기 위한 매커니즘을 제공하는 것에 대해 생각하기 시작했습니다. node.js는 오랫동안 이러한 능력을 가지고 있었고, 모듈 사용을 가능하게하는 많은 JavaScript 라이브러리와 프레임워크가 있습니다. (예를들어 RequireJS와 같은 CommonJS 와 AMD기반 모듈 시스템, 더 최근에는 Webpack과 Babel 같은 모듈 기반 시스템이 있습니다.)

좋은 소식은 최신 브라우저가 기본적으로 모듈 기능을 지원하기 시작했으며, 이것이 이 기사의 전부입니다. 브라우저는 모듈의 로딩을 최적화 할 수 있기 때문에 라이브러리를 사용하는 것보다 더 효율적이며, 클라이언트 측에서의 추가 처리와 여분의 왕복을 모두 해야하는 것 보다 효율적입니다.

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

### javascript.statements.import

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

### javascript.statements.export

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

Introducing an example
----------------------

모듈 사용법을 설명하기 위해 Github에 간단한 예제 모음을 만들었습니다. 이 예제들은 웹 페이지에 `<canvas>` 요소(element)를 만들고, 캔버스에 다양한 도형을 그리고, 그린것에 대한 정보를 보고하는 간단한 모듈 집합입니다.

이것들은 매우 사소한 것이지만, 모듈을 명확하게 설명하기 의해 의도적으로 단순하게 유지중입니다.

>
> **주의:** 예제를 다운로드하여 로컬에서 실행하려면, 로컬 웹 서버를 통해 예제를 실행해야 합니다.
>
>
>

Basic example structure
-----------------------

첫 번째 예제(basic-modules)를 보면 다음과 같은 파일 구조가 있습니다.
```

    index.html
    main.js
    modules/
        canvas.js
        square.js
```

>
> **주의:** 이 가이드의 모든 예제는 기본적으로 동일한 구조를 가집니다. 위의 내용에 익숙해지시는게 좋습니다.
>
>
>

modules 디렉토리의 두 모듈은 다음과 같습니다.

* `canvas.js` — 캔버스 설정과 관련된 기능을 포함합니다.
    + `create()` — 지정한 ID를 가진 래퍼 `<div>` (en-US) 안에, 지정한 `width` 와 `height` 를 가진 캔버스를 생성합니다. 지정한 ID(첫 번째 인자)는 지정한 부모 요소(두 번째 인자)안에 추가됩니다. 캔버스의 2D 컨텍스트와 래퍼(wrapper div)의 ID가 들어있는 객체를 반환합니다.
    + `createReportList()` — 데이터를 출력하는데 사용할 수 있는, 지정한 래퍼 요소(div) 안에 추가 된 정렬되지 않은 리스트(ul)를 만듭니다. 리스트의 ID를 반환합니다.
* `square.js` — 다음을 포함합니다.
    + `name` — 문자열 'square'를 담고있는 상수입니다.
    + `draw()` — 지정된 크기, 위치, 색상을 사용하여 지정된 캔버스에 사각형을 그립니다. 사각형의 크기, 위치, 색상을 포함하는 객체를 반환합니다.
    + `reportArea()` — 길이가 주어지면 사각형의 넓이를 지정한 보고서 리스트에 작성합니다.
    + `reportPerimeter()` — 길이가 주어지면 사각형의 둘레를 지정한 보고서 리스트에 작성합니다.
Exporting module features
-------------------------

모듈 기능을 사용하려면 먼저 함수를 export 해야 합니다. 이 작업은 `export` 문(statement)을 사용하여 수행합니다.

이를 사용하는 가장 쉬운 방법은 모듈 밖으로 내보내려는 항목 앞에 (export를) 배치하는 것입니다. 예를들면 다음과 같습니다.

```js
export const name = "square";

export function draw(ctx, length, x, y, color) {
  ctx.fillStyle = color;
  ctx.fillRect(x, y, length, length);

  return {
    length: length,
    x: x,
    y: y,
    color: color,
  };
}
```

functions, `var`, `let`, `const`, class를 내보낼 수 있지만, 최상위 항목이어야 합니다. 예를들어, 함수 안에서 `export`를 사용할 수 없습니다.

여러 항목을 내보내는 더 편리한 방법은 모듈 파일 끝에 하나의 export 문을 사용하는 것입니다. 그 다음에 내보내려는 기능들을 쉼표로 구분하여 나열하고 중괄호로 묶습니다.

```js
export { name, draw, reportArea, reportPerimeter };
```

Importing features into your script
-----------------------------------

모듈에서 일부 기능을 내보낸 후에는, 이를 사용할 수 있도록 우리가 사용할 스크립트로 가져와야 합니다. 가장 간단한 방법은 다음과 같습니다.

```js
import { name, draw, reportArea, reportPerimeter } from "./modules/square.js";
```

`import` 문(statement)을 사용하고, 가져올 목록을 쉼표로 구분하여 나열한 뒤 괄호로 묶습니다. 그 뒤에는 from을 쓰고 모듈 파일의 경로를 작성합니다. (사이트 루트에 연관된 경로로, 우리의 `basic-modules` 예제는 `/js-examples/modules/basic-modules` 입니다) `main.js`에서 이러한 코드를 볼 수 있습니다.

그러나 우리는 경로를 조금 다르게 작성했습니다. 우리는 "현재 위치"를 의미하는 점(.) 구문을 사용하고 있으며, 그 다음에 찾고자하는 파일의 경로를 뒤에 써 줍니다. 이것은 상대적으로 전체 상대 경로를 작성하는 것보다 훨씬 빠르며, URL이 더 짧아 지므로 사이트 계층 구조의 다른 위치로 이동하더라도 이 예제가 계속 작동합니다.

예를들면,

```bash
    /js-examples/modules/basic-modules/modules/square.js
```

이렇게 쓸 수 있습니다.

```bash
    ./modules/square.js
```

`main.js`에서 이러한 코드를 볼 수 있습니다.

>
> **주의:** 일부 모듈 시스템에서는 파일 확장명을 생략할 수 있습니다. (예: `'/modules/square'`). 이것은 네이티브 JavaScript에서는 작동하지 않습니다. 또한 앞에 슬래시를 포함해야 합니다.
>
>
>

우리의 스크립트에 기능을 가져오면 동일한 파일 내에 정의한 것처럼 기능을 사용할 수 있습니다. 다음은 `main.js` 의 import 행 아래에 있습니다.

```js
let myCanvas = create("myCanvas", document.body, 480, 320);
let reportList = createReportList(myCanvas.id);

let square1 = draw(myCanvas.ctx, 50, 50, 100, "blue");
reportArea(square1.length, reportList);
reportPerimeter(square1.length, reportList);
```

Applying the module to your HTML
--------------------------------

이제 `main.js` 모듈을 HTML 페이지에 적용하면 됩니다. 이는 몇 가지 주목할만한 차이점을 제외하면 HTML페이지에 일반 스크립트를 적용하는것과 매우 유사합니다.

이 스크립트를 모듈로 선언하려면 `<script>` 요소(element)에 `type="module"` 을 포함시켜야 합니다.

```js
<script type="module" src="main.js"></script>
```

기본적으로 모듈 기능을 가져오는 스크립트는 최상위 모듈로 작동합니다. 이를 생략하면 Firefox로 예를들면, "SyntaxError: import declarations may only appear at top level of a module"라는 오류를 줍니다.

`import` 와 `export` 문(statement)은 모듈 내에서만 사용할 수 있습니다. 정규 스크립트가 아닙니다.

>
> **주의:** `type="module"`을 포함하면 인터널 스크립트에서도 import 모듈을 사용할 수 있습니다. 예: `<script type="module"> /* 여기에 코드를 작성하세요 */ </script>`.
>
>
>

Other differences between modules and standard scripts
------------------------------------------------------

* 로컬 테스트에서의 주의 사항 — HTML파일을 로컬(예를들어 `file://` URL)에서 로드하려고 하면, JavaScript 모듈 보안 요구 사항으로 인해 CORS오류가 발생합니다. 서버를 통해 테스트 해야 합니다.
* 표준 스크립트와 달리 모듈 내부에서 정의된 스크립트 섹션과는 다르게 동작할 수 있습니다. 이는 모듈이 자동적으로 strict mode를 사용하기 때문입니다.
* 모듈 스크립트를 불러올 때 `defer` 속성(`<script>` attributes)를 사용할 필요가 없습니다. 모듈은 자동으로 defer됩니다.
* 마지막으로 모듈 기능을 단일 스크립트의 스코프로 가져왔음을 분명히 해야 합니다. — 전역 스코프에서는 사용할 수 없습니다. 따라서 import한 스크립트에서 가져온 기능에만 접근할 수 있습니다. 예를들어 JavaScript 콘솔에서 접근할 수 없습니다. DevTools에 구문 오류가 표시되지만, 사용하려고 하는 디버깅 기술 중 일부는 사용할 수 없습니다.
Default exports versus named exports
------------------------------------

지금까지 우리가 export 한 기능은 **named exports** 로 구성되었습니다. 각 항목(function, `const` 등)은 export 할 때 이름으로 참조되었으며, import 할 때에 이 이름을 참조하여 사용합니다.

그 외에도 **default export** 라고 부르는 export 도 있습니다. 이것은 모듈이 제공하는 기본 기능을 쉽게 만들 수 있도록 설계되었습니다. 또한 JavaScript 모듈을 기존의 CommonJS 와 AMD 모듈 시스템과 함께 사용(interpolate)하는데도 도움이 됩니다. (Jason Orendorff에 의해 작성된 ES6 In Depth: Modules 에 설명되어있습니다. "Default exports"를 검색해보세요)

예제를 가지고 어떻게 작동하는지 살펴보겠습니다. 예제 중 basic-modules 프로젝트의 `square.js` 파일에서 임의의 색상, 크기, 위치로 갖는 사각형을 만드는 `randomSquare()` 라는 함수를 찾을 수 있습니다. 이것을 기본값으로 export하려고 하므로, 파일의 맨 아래에 다음과 같이 씁니다.

```js
export default randomSquare;
```

중괄호가 없음에 주의하세요.

대신 함수 앞에 `export default` 를 추가하고, 다음과 같이 익명함수로 선언할 수 있습니다.

```js
export default function(ctx) {
  ...
}
```

`main.js` 파일에서 다음 코드처럼 사용하면, default function이 import 됩니다.

```js
import randomSquare from "./modules/square.js";
```

다시 말하지만, 중괄호가 없다는 점에 유의하세요. 하나의 모듈은 하나의 default export만 허용하기 때문에 우리는 `randomSquare` 가 해당 모듈임을 알 수 있습니다. 위의 코드는 아래의 코드를 단축하여 사용한 것입니다.

```js
import { default as randomSquare } from "./modules/square.js";
```

>
> **주의:** export한 항목의 이름을 바꾸는 구문은 Renaming imports and exports 섹션에서 설명합니다.
>
>
>

Avoiding naming conflicts
-------------------------

지금까지 우리의 캔버스 도형 그리기 모듈은 제대로 작동하는 것 같습니다. 원이나 삼각형처럼 다른 도형을 그리는 모듈을 추가하려고 하면 어떻게 될까요? 이 도형(shape)에는 아마도 `draw()`, `reportArea()` 등과 같은 관련 함수가 있을 것입니다. 동일한 이름의 여러 함수를 동일한 최상위 모듈로 가져오려고 하면, 충돌과 에러가 발생합니다.

다행스럽게도 이 문제를 해결할 수 있는 여러가지 방법이 있습니다. 다음 섹션에서 이 내용을 살펴보겠습니다.

Renaming imports and exports
----------------------------

`import` 와 `export` 문(statement)의 중괄호 안에 `as` 키워드를 새 함수의 이름으로 함께 사용하여, 최상위 모듈 내부의 함수들을 식별 가능한 이름으로 변경할 수 있습니다.

예를들어 다음 두 가지 방법은 약간의 차이가 있지만, 두 방법 모두 동일한 작업을 수행하고 있습니다.

```js
// inside module.js
export { function1 as newFunctionName, function2 as anotherNewFunctionName };

// inside main.js
import { newFunctionName, anotherNewFunctionName } from "./modules/module.js";
```

```js
// inside module.js
export { function1, function2 };

// inside main.js
import {
  function1 as newFunctionName,
  function2 as anotherNewFunctionName,
} from "./modules/module.js";
```

실제 사례를 살펴보겠습니다. renaming 디렉토리에서 원과 삼각형을 그리고 보고하기 위해 `circle.js` 와 `triangle.js` 모듈을 추가한다는 점만 제외하면, 앞의 예와 동일한 모듈 시스템을 볼 수 있습니다.

이 모듈듈 각각에는 내부적으로 동일한 이름의 기능이 있습니다. 따라서 각각 하단에 동일한 export 문(statement)이 있습니다.

```js
export { name, draw, reportArea, reportPerimeter };
```

이것들을 `main.js`에 가져올 때 우리는 다음과 같이 시도할 수 있습니다.

```js
import { name, draw, reportArea, reportPerimeter } from "./modules/square.js";
import { name, draw, reportArea, reportPerimeter } from "./modules/circle.js";
import { name, draw, reportArea, reportPerimeter } from "./modules/triangle.js";
```

위와같이 적으면 브라우저에서 "SyntaxError: redeclaration of import name"과 같은 오류가 발생합니다. (Firefox).

대신 import가 고유하도록(식별 가능하도록) 이름을 변경해야 합니다.

```js
import {
  name as squareName,
  draw as drawSquare,
  reportArea as reportSquareArea,
  reportPerimeter as reportSquarePerimeter,
} from "./modules/square.js";

import {
  name as circleName,
  draw as drawCircle,
  reportArea as reportCircleArea,
  reportPerimeter as reportCirclePerimeter,
} from "./modules/circle.js";

import {
  name as triangleName,
  draw as drawTriangle,
  reportArea as reportTriangleArea,
  reportPerimeter as reportTrianglePerimeter,
} from "./modules/triangle.js";
```

다음과 같이 import하는 파일 대신 모듈 파일에서 문제를 해결할 수도 있습니다.

```js
// in square.js
export {
  name as squareName,
  draw as drawSquare,
  reportArea as reportSquareArea,
  reportPerimeter as reportSquarePerimeter,
};
```

```js
// in main.js
import {
  squareName,
  drawSquare,
  reportSquareArea,
  reportSquarePerimeter,
} from "./modules/square.js";
```

그리고 이것은 똑같이 작동 할 것입니다. 사용하는 스타일은 개인의 취향이지만, 모듈 코드를 그대로 두고 import 를 변경하는 것이 더 합리적입니다. 특히 제어 권한이 없는 써드 파티 모듈에서 import를 사용하는 경우에 특히 유용합니다.

Creating a module object
------------------------

위의 방법은 정상적으로 작동하지만, 다소 지저분하고 길어질 수 있습니다. 보다 나은 해결책은 각 모듈의 기능을 모듈 객체 내부로 가져오는 것입니다. 다음과 같은 구문을 사용합니다.

```js
import \* as Module from "./modules/module.js";
```

이 모듈은 `module.js` 내에서 사용할 수 있는 모든 export를 가져옵니다. 그리고 그것들을 객체 `Module` 의 멤버로 만들고 우리 임의의 효과적인 네임스페이스를 제공합니다.

```js
Module.function1()
Module.function2()
etc.
```

다시 한 번 실제 사례를 살펴보겠습니다. module-objects 디렉토리로 가면 같은 예제를 볼 수 있지만, 새로운 구문을 이용하기 위해 다시 작성합니다. 모듈에서 export는 모두 다음과 같은 간단한 형식으로 이루어집니다.

```js
export { name, draw, reportArea, reportPerimeter };
```

반면에 import는 다음과 같습니다.

```js
import \* as Canvas from "./modules/canvas.js";

import \* as Square from "./modules/square.js";
import \* as Circle from "./modules/circle.js";
import \* as Triangle from "./modules/triangle.js";
```

각각의 경우에, 지정한 객체 이름 아래에 있는 모듈의 import에 접근할 수 있습니다. 다음은 그 예시입니다.

```js
let square1 = Square.draw(myCanvas.ctx, 50, 50, 100, "blue");
Square.reportArea(square1.length, reportList);
Square.reportPerimeter(square1.length, reportList);
```

따라서 이제는 이전과 똑같은 코드를 작성할 수 있습니다. (필요한 경우 객체 이름을 포함해야 합니다) import는 보다 깔끔해졌습니다.

Modules and classes
-------------------

이전에 암시 했듯이 class를 export하거나 import 할 수도 있습니다. 이것은 코드에서 충돌을 피하기 위한 또 다른 옵션으로, 모듈 코드가 이미 객체 지향 스타일로 작성된 경우에 특히 유용합니다.

우리의 classes 디렉토리에서 ES 클래스로 다시 작성된 도형 그리기 모듈의 예를 볼 수 있습니다. 예를들어 `square.js` 파일에는 모든 기능이 단일 클래스에 포함되어 있습니다.

```js
class Square {
  constructor(ctx, listId, length, x, y, color) {
    ...
  }

  draw() {
    ...
  }

  ...
}
```

우리는 다음과 같이 export 합니다.

```js
export { Square };
```

`main.js` 에서 우리는 다음과 같이 import 합니다.

```js
import { Square } from "./modules/square.js";
```

그런다음 클래스를 이용하여 사각형을 그립니다.

```js
let square1 = new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, "blue");
square1.draw();
square1.reportArea();
square1.reportPerimeter();
```

Aggregating modules
-------------------

모듈을 모아야 할 때가 있을 것입니다. 여러 서브 모듈을 하나의 부모 모듈로 결합하여 여러 단계의 종속성을 가질 수 있습니다. 상위 모듈에서 다음 양식의 export 구문을 사용하할 수 있습니다.

```js
export \* from "x.js";
export { name } from "x.js";
```

**주의**: 이것은 실제로 import 의 줄임말이고, 그 뒤에 export가 옵니다. 예를들면, "나는 모듈 `x.js`를 가져온 다음, 일부 또는 전부를 export 하겠다" 라는 뜻입니다.

예를들어 module-aggregation 디렉토리를 참조하겠습니다. 이 예제에서는 이전 클래스 예제를 기반으로 `circle.js`, `square.js`, `triangle.js` 의 모든 기능을 함께 모으는 `shapes.js`라는 추가 모듈이 있습니다. 또한 우리는 `shapes` 모듈 디렉토리 안에 있는 서브 디렉토리 내에서 서브 모듈을 이동 시켰습니다. 이제 모듈 구조는 다음과 같습니다.
```

    modules/
      canvas.js
      shapes.js
      shapes/
        circle.js
        square.js
        triangle.js
```

각 하위 모듈에서 export 형태는 같습니다. 예)

```js
export { Square };
```

다음은 집합(aggregation) 부분입니다. `shapes.js` 안에는 다음과 같은 내용이 포함되어 있습니다.

```js
export { Square } from "./shapes/square.js";
export { Triangle } from "./shapes/triangle.js";
export { Circle } from "./shapes/circle.js";
```

이 모듈은 각각의 서브 모듈의 export를 가져와서 `shapes.js` 모듈에서 효과적으로 사용할 수 있도록 합니다.

>
> **주의:** `shapes.js` 에서 참조되는 export는 기본적으로 파일을 통해 리다이렉트 되고 실제로는 존재하지 않으므로, 같은 파일 내에 유용한 코드를 쓸 수 없습니다.
>
>
>

이제 `main.js` 파일에서 우리는 세 개의 모듈 클래스를 모두 대체할 수 있습니다.

```js
import { Square } from "./modules/square.js";
import { Circle } from "./modules/circle.js";
import { Triangle } from "./modules/triangle.js";
```

다음과 같은 한 줄로 작성할 수 있습니다.

```js
import {
  Square,
  Circle,
  Triangle,
} from "/js-examples/modules/module-aggregation/modules/shapes.js";
```

Dynamic module loading
----------------------

브라우저에서 사용할 수 있는 JavaScript 모듈 기능의 최신 부분은 동적 모듈 로딩 입니다. 이렇게 하면 모든 것을 최상위에서 불러오지 않고, 필요할 때만 모듈을 동적으로 불러올 수 있습니다. 이것은 몇 가지 분명한 성능 이점이 있습니다. 계속 읽어보고 어떻게 작동하는지 살펴봅시다.

이 새로운 기능을 통해 `import()` 를 함수로 호출하여 모듈 경로를 매개 변수(parameter)로 전달할 수 있습니다. 모듈 객체(Creating a module object 참조)를 사용하여 promise를 반환하면 해당 객체의 export에 접근할 수 있습니다.

```js
import("/modules/myModule.js").then((module) => {
  // Do something with the module.
});
```

예제를 보겠습니다. In the dynamic-module-imports 디렉토리에는 classes 예제를 기반으로 한 또 다른 예제가 있습니다. 이번에는 예제가 로딩될 때 캔버스에 아무것도 그리지 않습니다. 대신 우리는 세 개의 버튼("Circle", "Square", "Triangle")이 포함되어 있습니다. 이 버튼을 누르면 필요한 모듈을 동적으로 불러온 다음, 이를 사용하여 연관된 도형을 그립니다.

이 예제에서 우리는 index.html 파일과 main.js 파일만 변경했습니다. 모듈 export는 이전과 동일하게 유지됩니다.

`main.js` 에서 `document.querySelector()` 를 사용하여 각 버튼에 대한 참조를 가져왔습니다. 예를들면 다음과 같습니다.

```js
let squareBtn = document.querySelector(".square");
```

그런 다음 각 버튼에 이벤트 리스너를 연결하여 해당 모듈을 누르면, 동적으로 로드되어 도형을 그리는데 사용됩니다.

```js
squareBtn.addEventListener("click", () => {
  import("/js-examples/modules/dynamic-module-imports/modules/square.js").then(
    (Module) => {
      let square1 = new Module.Square(
        myCanvas.ctx,
        myCanvas.listId,
        50,
        50,
        100,
        "blue",
      );
      square1.draw();
      square1.reportArea();
      square1.reportPerimeter();
    },
  );
});
```

Note that, promise fulfillment 가 모듈 객체를 반환하기 때문에 클래스는 객체의 하위 기능으로 만들어집니다. 따라서 이제 `Module` 을 사용하여 생성자(contructor)에 접근해야 합니다. 예를들어 `Module.Square( ... )` 와 같이 앞에 `Module`이 붙습니다.

See also
--------

* Using JavaScript modules on the web, by Addy Osmani and Mathias Bynens
* ES modules: A cartoon deep-dive, Hacks blog post by Lin Clark
* ES6 in Depth: Modules, Hacks blog post by Jason Orendorff
* Axel Rauschmayer's book Exploring JS: Modules
* « 이전 (en-US)


ARIA - 접근성

ARIA
====

**접근가능한 리치 인터넷 어플리케이션**(Accessible Rich Internet Applications, **ARIA**)은 장애를 가진 사용자가 웹 콘텐츠와 웹 어플리케이션(특히 JavaScript를 사용하여 개발한 경우)에 더 쉽게 접근할 수 있는 방법을 정의하는 여러 특성을 말합니다.

ARIA는 HTML을 보충해, 일반적으로 보조 기술이 알 수 없는 상호작용 및 흔히 쓰이는 어플리케이션 위젯에 필요한 정보를 제공합니다. 예를 들어 ARIA는 HTML4에서의 탐색 랜드마크, JavaScript 위젯, 폼 힌트 및 오류 메시지, 실시간 콘텐츠 업데이트 등을 접근 가능한 형태로 제공합니다.

**경고:** 여기 등장하는 많은 위젯은 나중에 HTML5로 통합됐으므로, 구현하려는 기능을 가진 요소가 존재한다면 **개발자는 되도록 의미를 가진 HTML을 ARIA보다 선호해야 합니다**. 몇 가지 예시로, 네이티브 요소는 키보드 접근성, 역할, 상태를 내장하고 있습니다. 그러나 ARIA를 쓰기로 결정했다면 브라우저 동작 방식을 따라 하는 건 개발자의 책임입니다.

다음은 진행 표시줄 위젯의 마크업입니다.

```html
<div
 id="percent-loaded"
 role="progressbar"
 aria-valuenow="75"
 aria-valuemin="0"
 aria-valuemax="100"></div>
```

This progress bar is built using a `<div>`, which has no meaning. Unfortunately, there isn't a more semantic tag available to developers in HTML 4, so we need to include ARIA roles and properties. These are specified by adding attributes to the element. In this example, the `role="progressbar"` attribute informs the browser that this element is actually a JavaScript-powered progress bar widget. The `aria-valuemin` and `aria-valuemax` attributes specify the minimum and maximum values for the progress bar, and the `aria-valuenow` describes the current state of it and therefore must be kept updated with JavaScript. Along with placing them directly in the markup, ARIA attributes can be added to the element and updated dynamically using JavaScript code like this:

```js
// Find the progress bar <div> in the DOM.
var progressBar = document.getElementById("percent-loaded");

// Set its ARIA roles and states,
// so that assistive technologies know what kind of widget it is.`;
progressBar.setAttribute("role", "progressbar");
progressBar.setAttribute("aria-valuemin", 0);
progressBar.setAttribute("aria-valuemax", 100);

// Create a function that can be called at any time to update
// the value of the progress bar.
function updateProgress(percentComplete) {
  progressBar.setAttribute("aria-valuenow", percentComplete);
}
```

>
> **Note:** that ARIA was invented after HTML4, so does not validate in HTML4 or its XHTML variants. However, the accessibility gains it provides far outweigh any technical invalidity. In HTML5, all ARIA attributes validate. The new landmark elements (`<main>`, `<header>`, `<nav>` etc) have built-in ARIA roles, so there is no need to duplicate them.
>
>
>

지원
--

다른 웹 기술과 마찬가지로, ARIA 역시 환경 별 지원 수준에 차이를 보입니다. 지원 수준은 사용자의 운영 체제 및 사용하는 브라우저, 그리고 연결된 보조 기술마다 다릅니다. 게다가 각각의 버전 또한 영향을 줍니다. 오래된 소프트웨어 버전은 특정 ARIA 역할을 지원하지 않거나, 부분적으로만 지원하거나, 잘못된 기능을 가지고 있을 수 있습니다.

또 다른 중요한 점은, 보조 기술에 의존하는 사용자 일부가 컴퓨터 및 브라우저 상호작용 기능을 잃어버릴까 두려워 소프트웨어 업그레이드를 주저할 수 있다는 점을 인지하는 것입니다. 그러므로 가능한 한 보조 기술이 훨씬 넓게 지원하는, 의미를 가진 HTML 요소를 사용하는 편이 좋습니다.

마지막으로 작성한 ARIA을 실제 보조 기술로 시험하는 것도 필요합니다. 브라우저 에뮬레이터와 시뮬레이터가 전체 테스트에 효율적인 도구가 아니듯, 유사 보조 기술만으로는 완벽한 지원을 장담하기엔 부족합니다.

자습서
---

ARIA 소개 (en-US)

동적인 컨텐츠를 ARIA를 적용해 접근성을 갖추도록 하는 방법에 대한 소개한 글입니다. Gez Lemon이 2008년에 쓴 ARIA 분야의 고전인 ARIA intro도 참조하십시오.

스크린 리더기에서 ARIA를 어떻게 사용하는지에 대한 영상

ARIA "적용 전", "적용 후" 영상을 비롯하여, 웹에서 볼 수 있는 실제 사용 예제들과 그것보다 간략화된 예시들을 볼 수 있습니다.

ARIA 사용하기

개발자를 위한 실용 가이드를 제공하는 글입니다. HTML 요소에 어떤 ARIA 속성들을 써야 하는지에 대해 제안하는 내용을 담고 있습니다. 제안은 실제 구현 상황을 바탕으로 합니다.

간단한 ARIA 향상
-----------

ARIA 랜드마크를 사용하여 페이지 탐색 고도화

스크린 리더 사용자들을 위해 ARIA 랜드마크를 사용하여 웹 페이지의 탐색 기능을 향상시키는 법을 소개해주는 좋은 글입니다. 이와 더불어서 ARIA 구현 노트 및 실제 사이트에서의 활용 예시들을 참고하세요. (2011년 7월에 업데이트됨)

폼 접근성 향상하기 (en-US)

ARIA는 동적 콘텐츠만을 위한 것이 아닙니다! ARIA 특성을 사용해 HTML 폼의 접근성을 높이는 방법을 알아보세요.

스크립트 처리된 위젯을 위한 ARIA
--------------------

JavaScript 위젯에 키보드 탐색 및 초점 적용하기 (en-US)

`<input>` (en-US), `<button>` 등 내장 요소는 기본적으로 키보드를 지원합니다. `<div>` (en-US)와 ARIA로 특정 요소를 흉내 낸다면, 그 위젯도 키보드를 지원하도록 해야 합니다.

실시간 영역 (en-US)

실시간 영역은 페이지 콘텐츠에 가해지는 변경점을 접근성 보조 기술이 어떻게 처리해야 하는지 제안합니다.

ARIA 실시간 영역으로 콘텐츠 변경 알리기

JAWS 스크린 리더 소프트웨어의 개발진이 실시간 영역에 대해 요약한 글입니다.

표준화를 위한 노고
----------

WAI-ARIA 명세

W3C 명세입니다.

WAI-ARIA 작성 안내서

흔히 쓰이는 위젯을 ARIA스럽게 만드는 방법에 대한 공식 안내서로, 훌륭한 자원입니다.

비디오
---

다음 발표 비디오는 ARIA를 이해할 수 있는 훌륭한 방법입니다. ARIA, Accessibility APIs and coding like you give a damn! – Léonie Watson

버그 제출
-----

브라우저, 스크린 리더, JavaScript 라이브러리의 ARIA 버그 제출하기

관련 주제
-----

접근성, AJAX, JavaScript

* 웹 개발
* 접근성과 Mozilla


웹 컨텐츠 접근성 지침 이해하기 - 접근성

웹 컨텐츠 접근성 지침 이해하기
=================

이 문서에서는 W3C 웹 컨텐츠 접근성 지침 2.0 또는 2.1(이 글에서는 WCAG)에 설명된 권장 사항들을 준수하기 위한 단계들을 이해하는 데에 도움이 되는 간략한 설명을 제공합니다.

WCAG 2.0과 2.1은 다양한 장애를 가진 사람들이 웹 컨텐츠에 더 쉽게 접근할 수 있게 하는 자세한 지침을 제공합니다. 포괄적이지만 매우 구체적이며, 빠르게 이해하기엔 다소 어려울 수 있습니다. 이런 복잡하고 어려운 권장 사항들을 충족하기 위한 단계들을 요약해 놓았으며, 상세 정보가 필요한 경우 링크를 제공합니다.

4대 원칙
-----

WCAG는 크게 네 가지 원칙으로 분류할 수 있습니다. 이는 웹 컨텐츠의 접근성을 위해 **반드시** 고려해야 하는 사항들입니다 (WCAG의 정의는 접근성 4대 원칙의 이해 참조).

아래의 링크들을 클릭하면 해당 영역에 대해 더 자세히 설명하는 페이지로 이동하며, 각 원칙들을 더욱 세분화 한 WCAG 2.0과 2.1의 지침을 준수할 수 있는 실용적인 조언들을 통해 웹 컨텐츠를 작성할 수 있도록 합니다.

* 인식의 용이성: 사용자가 하나 또는 다수의 감각을 사용해 어떤 방식으로든 인지할 수 있어야 합니다.
* 운용의 용이성: 사용자가 UI 요소들을 컨트롤 할 수 있어야 합니다(예를 들어, 버튼은 마우스, 키보드, 음성 명령 등의 방식으로 클릭이 가능해야 합니다).
* 이해의 용이성: 컨텐츠를 사용자가 이해할 수 있어야 합니다.
* 견고성: 컨텐츠는 각기 다른 브라우저에서, 현재와 미래에 모두 동작할 수 있도록 널리 알려진 웹 표준을 준수하여 개발되어야 합니다.
WCAG 2.0과 2.1 중 어떤 것을 사용해야 하나요?
-------------------------------

WCAG 2.1 은 가장 최신화된 접근성 표준입니다. WCAG 2.1 을 사용해 장애를 가진 사람들을 돕고, 웹 사이트 소유자에게 생길 법적인 위험을 줄일 수 있습니다. 자원을 할당할 때에는 WCAG 2.0 을 목표로 하고, 단계적으로 WCAG 2.1로 나아가세요.

### WCAG 2.1이 뭔가요?

WCAG 2.1 은 2018년 6월 5일에 공식 권장 사항으로 발표되었습니다. 유럽 연합 (EU)은 디지털 접근성 표준으로 2018년 9월에 WCAG 2.1을 채택했습니다. W3C 는 WCAG 2.1 Adoption in Europe 라는 글을 발행했습니다.

WCAG 2.1 은 다음을 포함합니다.

* WCAG 2.0 의 모든 것 (문자 그대로)
* A / AA / AAA 수준의 17가지 새로운 기준은 주로 아래 사용자들의 요구 사항에 대한 내용입니다.
    + 모바일 접근성
    + 낮은 시력을 가진 사용자
    + 인지 장애를 가진 사용자
* WCAG 2.1 더 알아보기
    + Deque: WCAG 2.1: 접근성 지침의 다음 단계
    + TPG: 웹 컨텐츠 접근성 지침 (WCAG) 2.1
법적 유효성
------

이 가이드는 접근성이 높은 웹 사이트를 만들기 위한 실용적인 정보들을 제공하는 것을 목표합니다. 하지만 우리는 법조인이 아니기 때문에, 이 문서를 법률 자문으로 받아들여서는 안됩니다. 웹 접근성에 대한 법적 문제가 우려된다면, 해당 국가나 지역의 웹/공공 자원에 대한 접근성에 관련된 법률을 확인하고, 전문 변호사의 자문을 구하는 것이 좋습니다.

접근성이란 무엇인가? 와, 특히 접근성 지침과 관련 법률 섹션에서 관련된 추가 정보들을 제공합니다.


모바일 접근성 점검항목 - 접근성

모바일 접근성 점검항목
============

이 문서는 모바일 앱 개발자를 위해 접근성 요구 사항에 대한 간결한 체크리스트를 제공합니다. 이 문서는 다양한 패턴의 발생에 맞춰 지속적으로 진화하려는 의도로 작성되었습니다.

색
-

* 색상 대비는 반드시 WCAG 2.0 AA 레벨 요건을 준수해야 합니다.
    + 일반적인 크기의 텍스트(18pt 보다 작거나 14pt 볼드체)는 4.5:1
    + 큰 크기의 텍스트(적어도 18pt 보다 크거나 14pt 볼드체)는 3:1
* 색상을 통해 전달되는 정보는 반드시 다른 수단으로도 제공되어야 합니다(링크 텍스트의 밑줄 등).
가시성
---

* opacity:0, z-index 조정 및 화면 밖 배치와 같은 콘텐츠 숨기기 기법은 단순히 가시성을 처리하기 위해서만 사용되어서는 안 됩니다.
* 현재 보이는 화면 이외의 모든 것은 반드시 "진짜로" 보이지 않아야 합니다(특히 여러 개의 "카드" 가 있는 단일 페이지 앱에 관련됨).
    + `hidden` 속성 또는 `visibility` 또는 `display` 스타일 속성값을 이용하세요.
    + 불가피한 경우를 제외 하고 `aria-hidden` 속성을 사용하지 마세요.
포커스
---

* 활성화 가능한 모든 요소는 포커스가 가능해야 합니다.
    + 링크, 버튼 및 form 필드와 같은 표준 컨트롤들은 기본적으로 포커스가 가능합니다.
    + 비표준 컨트롤들은 반드시 `button`, `link` 또는 `checkbox`와 같은 적절한 ARIA Role (en-US) 이 할당되어야 합니다.
* 포커스는 논리적인 순서와 일관된 방식으로 다루어져야 합니다.
텍스트 동등성
-------

* 앱 내 엄격하게 표현되지 않은, 텍스트가 아닌 모든 요소에 대해 동일한 의미의 텍스트가 제공되어야 합니다.
    + *alt* 와 *title* 속성은 적절하게 사용되어야 합니다 (스티브 폴크너의 HTML의 제목 특성 사용하기 가 좋은 안내서가 될 것입니다).
    + 위 속성을 사용하기 어려운 경우 `aria-label`, `aria-labelledby`, or `aria-describedby` 등과 같은 적절한 ARIA 속성들을 사용하세요.
* 텍스트 이미지 사용은 가급적 자제 해야 합니다.
* 레이블 텍스트 (또는 텍스트 이미지) 의 모든 사용자 인터페이스 컴포넌트는 프로그램 이름으로 사용할 수 있는 것과 동일한 텍스트를 사용해야 합니다. WCAG 2.1: Label in Name
* 모든 form 컨트롤 요소는 스크린 리더 사용자를 위해 label (`<label>` elements) 을 가져야 합니다.
상태 다루기
------

* 라디오 버튼 및 체크박스와 같은 표준 컨트롤들은 운영체제가 처리합니다. 그러나 다른 사용자 정의 컨트롤의 경우, `aria-checked`, `aria-disabled`, `aria-selected`, `aria-expanded`, `aria-pressed`와 같은 ARIA States를 통해 상태 변경이 제공되어야 합니다.
방향
--

* 콘텐츠는 특수한 경우를 제외하고 가로 또는 세로의 단일 방향으로 제한되어서는 안됩니다. WCAG 2.1: Orientation
    + 방향이 제한되어야 하는 특수한 경우의 예시로는 피아노 앱이나 은행 수표 앱 같은 경우가 있습니다.
일반적인 지침들
--------

* 앱 이름은 반드시 제공되어야 합니다.
* 제목 요소들은 계층 구조를 지켜야 합니다.

```html
<h1>Top level heading</h1>
<h2>Secondary heading</h2>
<h2>Another secondary heading</h2>
<h3>Low level heading</h3>
```

* ARIA Landmark Roles 은 `banner`, `complementary`, `contentinfo`, `main`, `navigation`, `search`와 같이 앱이나 문서의 구조를 설명하기 위해서 사용되어야 합니다.
* 터치 이벤트의 발생 시에는, 아래 사항들 중 최소 하나 이상을 만족해야 합니다(WCAG 2.1: Pointer Cancellation).
    + 다운 이벤트는 다른 동작을 트리거 하는 데에 사용되어서는 안됩니다
    + 액션은 업 이벤트에 의해 실행되며, 액션의 완료 전 작업을 중단하는 옵션과 액션의 완료 후 작업을 취소하는 옵션을 사용할 수 있습니다
    + 업 이벤트는 다운 이벤트에 의해 발생한 모든 작업을 취소합니다
    + 다운 이벤트에 의해 액션이 실행되어야 합니다. 예시로는 게임 앱이나 피아노 앱이 있습니다.
* 터치 요소는 유저가 상호작용 할 수 있을 정도로 충분한 크기를 가져야 합니다(적절한 터치 요소 크기에 대한 지침들은 BBC 모바일 접근성 지침을 참고하세요).

**참고:** 이 문서 원문의 작성자는 Yura Zenevich입니다.


ARIA 상태와 속성 - 접근성

ARIA 상태와 속성
===========

이 문서는 MDN에서 논의된 모든 WAI-ARIA 속성들을 다루는 참조 페이지를 나열합니다.

ARIA 속성을 사용하면 접근성 트리에 정의된 대로 요소의 상태와 속성을 수정할 수 있습니다.

**참고:** ARIA는 접근성 트리만을 수정하여 보조 기술이 사용자에게 컨텐츠를 제공하는 방법을 수정합니다. ARIA는 요소의 기능이나 동작에 대해 아무것도 변경하지 않습니다. 의도된 목적과 기본 기능을 위해 시맨틱 HTML 요소를 사용하지 않을 때는 행동, 포커스 및 ARIA 상태를 관리하기 위해 JavaScript를 사용해야 합니다.

ARIA 속성 유형
----------

ARIA 상태와 속성에는 4가지 유형이 있습니다:

1. ### 위젯 속성

    * `aria-autocomplete` (en-US)
    * `aria-checked` (en-US)
    * `aria-disabled` (en-US)
    * `aria-errormessage` (en-US)
    * `aria-expanded` (en-US)
    * `aria-haspopup` (en-US)
    * `aria-hidden` (en-US)
    * `aria-invalid` (en-US)
    * `aria-label`
    * `aria-level` (en-US)
    * `aria-modal` (en-US)
    * `aria-multiline` (en-US)
    * `aria-multiselectable` (en-US)
    * `aria-orientation` (en-US)
    * `aria-placeholder` (en-US)
    * `aria-pressed` (en-US)
    * `aria-readonly` (en-US)
    * `aria-required` (en-US)
    * `aria-selected` (en-US)
    * `aria-sort` (en-US)
    * `aria-valuemax` (en-US)
    * `aria-valuemin` (en-US)
    * `aria-valuenow` (en-US)
    * `aria-valuetext` (en-US)
2. ### 실시간 영역 속성

    * `aria-busy` (en-US)
    * `aria-live` (en-US)
    * `aria-relevant` (en-US)
    * `aria-atomic` (en-US)
3. ### 드래그 & 드랍 속성

    * `aria-dropeffect` (en-US)
    * `aria-grabbed` (en-US)
4. ### 관계 속성

    * `aria-activedescendant` (en-US)
    * `aria-colcount` (en-US)
    * `aria-colindex` (en-US)
    * `aria-colspan` (en-US)
    * `aria-controls` (en-US)
    * `aria-describedby`
    * `aria-description` (en-US)
    * `aria-details` (en-US)
    * `aria-errormessage` (en-US)
    * `aria-flowto` (en-US)
    * `aria-labelledby` (en-US)
    * `aria-owns` (en-US)
    * `aria-posinset` (en-US)
    * `aria-rowcount` (en-US)
    * `aria-rowindex` (en-US)
    * `aria-rowspan` (en-US)
    * `aria-setsize` (en-US)
전역 ARIA 속성
----------

일부 상태 및 속성은 ARIA 역할 적용 여부와 관계없이 모든 HTML 요소에 적용됩니다. 이들은 "전역" 속성으로 정의됩니다. 전역 상태 및 속성은 모든 역할 및 기본 마크업 요소에 의해 지원됩니다.

아래 속성 중 대부분은 전역 속성으로 특별히 금지되지 않는 한 어떤 요소에든 포함될 수 있습니다:

* `aria-atomic` (en-US)
* `aria-busy` (en-US)
* `aria-controls` (en-US)
* `aria-current` (en-US)
* `aria-describedby`
* `aria-description` (en-US)
* `aria-details` (en-US)
* `aria-disabled` (en-US)
* `aria-dropeffect` (en-US)
* `aria-errormessage` (en-US)
* `aria-flowto` (en-US)
* `aria-grabbed` (en-US)
* `aria-haspopup` (en-US)
* `aria-hidden` (en-US)
* `aria-invalid` (en-US)
* `aria-keyshortcuts` (en-US)
* `aria-label`
* `aria-labelledby` (en-US)
* `aria-live` (en-US)
* `aria-owns` (en-US)
* `aria-relevant` (en-US)
* `aria-roledescription` (en-US)

"특뱔한 상황에서만 금지된다"는 의미에서 위의 모든 속성들은 전역 속성입니다. 단, `aria-label` 및 `aria-labelledby` 속성은 `presentation` (en-US) 역할 또는 동일한 의미의 `none` (en-US) 역할을 갖는 요소들에는 허용되지 않습니다.

MDN에 정의된 상태와 속성들
----------------

다음은 MDN에서 논의된 WAI-ARIA 상태 및 속성을 다루는 참조 페이지입니다.

aria-describedby전역 `aria-describedby` 속성은 속성이 설정된 요소를 설명하는 요소(혹은 요소들)를 식별합니다.

aria-label`aria-label` 속성은 상호작용되는 요소에 레이블된 문자열 값을 정의합니다.

같이 보기
-----

* Using ARIA: roles, states, and properties (en-US)


aria-label - 접근성

aria-label
==========

`aria-label` 속성은 상호작용되는 요소에 레이블된 문자열 값을 정의합니다.

설명
--

때때로 요소의 기본 접근자 이름이 없는 경우, 또는 그 콘텐츠를 명확하게 설명하지 못한 경우, 그리고 해당 요소에게 의미를 주기 위한 객체와 연관된 DOM 안에 보이는 콘텐츠가 없는 경우가 있습니다. 흔한 예로 SVG 또는 icon font (사용해서는 안되는 방법입니다).

상호작용을 하는 요소에 접근자 이름이 없거나, 접근자 이름이 부정확한 경우, 또는 `aria-labelledby` (en-US) 속성을 통해 참조되는 DOM 안에 보이는 콘텐츠가 없는 경우에 `aria-label` 속성은 이 속성이 부여된 상호작용 요소에 지정할 문자열을 정의하는데 사용될 수 있습니다. 이는 해당 요소에게 접근자 이름을 제공하게 됩니다.

```html
<button aria-label="Close" onclick="myDialog.close()">
  <svg
 aria-hidden="true"
 focusable="false"
 width="17"
 height="17"
 xmlns="http://www.w3.org/2000/svg">
    <path
 d="m.967 14.217 5.8-5.906-5.765-5.89L3.094.26l5.783 5.888L14.66.26l2.092 2.162-5.766 5.889 5.801 5.906-2.092 2.162-5.818-5.924-5.818 5.924-2.092-2.162Z"
 fill="#000" />
  </svg>
</button>
```

**참고:** `aria-label`은 레이블로 참조되어질 수 있는 DOM 안에 표시가능한 적당한 텍스트가 없을 때, 상호작용을 하는 요소들 또는 다른 ARIA 선언들을 통해 상호작용하도록 만들어진 요소에 사용하기 위한 것입니다.

대부분의 콘텐츠에는 이를 직접 감싸는 요소의 텍스트 콘텐츠로부터 생성된 접근자 이름이 있습니다. 또한, 접근자이름들은 특정 속성들 또는 연관된 요소들로부터 생성될 수 있습니다.

기본적으로, 버튼의 접근자 이름은 `<button>`의 여는 태그와, 닫는 태그 사이의 콘텐츠이고, image 요소의 접근자 이름은 `alt` 속성의 콘텐츠, 그리고 form input요소의 접근자 이름은 연결된 `<label>` 요소의 콘텐츠입니다.

만약 이러한 옵션들 중 가능한 것이 없거나, 초기 접근자 이름이 적합하지 않은 경우, `aria-label` 속성을 사용하여 요소의 접근자 이름을 정의합니다.

`aria-label`은 요소에 레이블할 수 있는 텍스트가 표기가능하지 *않은* 경우 사용할 수 있습니다. 만일 요소에 레이블할 수 있는 보이는 텍스트가 있다면, `aria-labelledby` (en-US)를 대신 사용하시기 바랍니다.

`aria-label`의 목적은 `aria-labelledby`와 같습니다. 둘 다 요소에 접근자 이름을 제공합니다. 만일 당신이 참조할 수 있는 요소에 대해 표시가능한 이름이 없다면, 사용자에게 인지가능하고 접근가능한 이름을 제공하기 위하여 `aria-label`을 사용하시기 바랍니다. 만약 레이블 텍스트가 DOM 안에 사용가능하고, DOM 콘텐츠 및 허용 가능한 사용자 경험을 참조하는 경우라면, `aria-labelledby`를 사용하는 것을 권장합니다. 둘 다 포함하여 사용하지 마시기 바랍니다. 둘 다 동일한 요소에 있다면, `aria-labelledby`가 `aria-label`보다 우선됩니다.

`aria-label` 속성은 일반적인 시멘틱 HTML요소들과 함께 사용될 수 있습니다. 이는 ARIA `roles` (en-US)이 할당된 요소에만 국한되지 않습니다.

`aria-label`을 "남용"하지 마십시오. 예를 들어, 추가적인 지침 또는 명확한 사용자 경험을 제공하기 위해 `aria-label`이 아닌 `aria-describedby` 또는 `aria-description`과 함께 표시가능한 텍스트를 사용하십시오. 오직 스크린 리더에만 지침을 지정하실 필요는 없음을 잊지 마십시오. 만일 지침이 필요하다면, 모두에게 제공하시기 바랍니다 (또는 가급적 사용자 인터페이스를 보다 직관적으로 만들어 주시기 바랍니다).

모든 요소에 접근자 이름을 지정할 수 있는 것은 아닙니다. `aria-label`과 `aria-labelledby` 둘 다 `code`, `term`, 또는 `emphasis`와 같은 비상호작용 요소 또는 인라인 구조적 역할과 함께 사용해서는 안되며, 의미체계가 `presentation`, `none`, `hidden`을 포함한 접근성 API에 사상되지 않는 역할들과 함께 사용해서는 안됩니다. `aria-label` 속성은 오직 상호작용 요소에만 사용됩니다. 접근자 이름을 확실하게 하기 위해 `aria-label`을 사용하십시오. links, videos, form 조절, 랜드마크 roles (en-US), 위젯 roles (en-US)과 같은 역할과 모든 상호작용 요소에 대하여 DOM에 아무것도 표시되지 않는 경우 접근자 이름이 제공되도록 `aria-label`을 사용하십시오.

만일 `<iframe>` (en-US)에 `title`, image에 `alt` 속성, 그리고 input과 연관된 `<label>`을 지정하면, `aria-label`은 필요하지 않습니다. 그러나, `aria-label`이 있는 경우 `iframe`과 image, `input`의 접근자 이름인 `title`과 `alt`, 그리고 `<label>` 보다 우선순위를 가지게 됩니다.

**참고:** `aria-label`은 오로지 "보이도록" 하는 보조적 기술입니다. 만일 사용자에게 추가하기에 충분히 중요한 정보인 경우 모든 사용자에게 표시되도록 하는 것이 좋습니다.

Values
------

`<string>`

객체에 접근가능한 이름이 될 문자열 값

ARIAMixin API
-------------

`Element.ariaLabel` (en-US)

`Element` (en-US) 인터페이스의 일부인 `ariaLabel` (en-US) 속성은 `aria-label` 속성의 값을 반영합니다.

`ElementInternals.ariaLabel` (en-US)

`ElementInternals` (en-US) 인터페이스의 일부인 `ariaLabel` (en-US) 속성은 `aria-label` 속성의 값을 반영합니다.

Associated roles
----------------

작성자에 의해 접근자 이름을 제공할 수 없는 역할을 **제외한** 거의 모든 역할에 사용됩니다.

`aria-label` 속성이 지원되지 **않는** 역할들:

* `code` (en-US)
* `caption` (en-US)
* `deletion` (en-US)
* `emphasis` (en-US)
* `generic` (en-US)
* `insertion` (en-US)
* `mark` (en-US)
* `paragraph` (en-US)
* `presentation` (en-US) / `none` (en-US)
* `strong` (en-US)
* `subscript` (en-US)
* `superscript` (en-US)
* `suggestion` (en-US)
* `term` (en-US)
* `time` (en-US)

**참고:** `aria-label` 속성은 오로지 상호작용 요소에서만 사용됩니다. 위에 나열된 것들과 같은 비 상호작용 요소에 사용할 경우 aria-label 속성 값은 읽히지 않거나, 비 상호작용 요소를 상호작용하는 요소처럼 작동하는 것으로 사용자를 혼동시킬 수 있습니다.

명세
--

| Specification |
| --- |
| Accessible Rich Internet Applications (WAI-ARIA) # aria-label |

같이 보기
-----

* `<label>` 요소
* `aria-labelledby` (en-US)


aria-describedby - 접근성

aria-describedby
================

전역 `aria-describedby` 속성은 속성이 설정된 요소를 설명하는 요소(혹은 요소들)를 식별합니다.

설명
--

`aria-describedby` 속성은 객체를 설명하는 요소의 `id`를 나열합니다. 위젯 또는 그룹과 이를 설명하는 텍스트 간의 관계를 설정하는데 사용됩니다.

`aria-describedby` 속성은 폼 컨트롤에만 제한되지 않습니다. 정적 텍스트를 위젯, 요소 그룹, 제목이 있는 영역, 정의 등과 연결하는 데에도 사용할 수 있습니다. `aria-describedby` 속성은 시맨틱 HTML 요소와 ARIA `role` (en-US)이 있는 요소와 함께 사용될 수 있습니다.

`aria-describedby` 속성은 `aria-labelledby` (en-US) 속성과 매우 유사합니다. `aria-labelledby`는 객체의 본질을 설명하는 레이블 혹은 요소의 `id`를 나열하는 반면, `aria-describedby`는 사용자가 필요할 수 있는 추가 정보를 제공하는 설명 혹은 요소의 `id`를 나열합니다. `aria-labelledby`와 `aria-describedby`는 모두 텍스트 대안을 계산하기 위해 다른 요소를 참조하지만, 레이블은 간결해야 하는 반면, 설명은 더 자세한 정보를 제공하기 위한 것입니다. 레이블은 객체의 본질을 설명하는 반면, 설명은 사용자가 필요할 수 있는 추가 정보를 제공합니다.

`aria-describedby`으로 연결된 요소는 표시할 필요가 없습니다. 해당 요소가 숨겨져 있어도 요소를 참조할 수 있습니다. 예를 들어 폼 컨트롤에 기본적으로 숨겨져 있는 설명이 "추가 정보" 아이콘과 같은 공개 위젯을 사용하여 요청할 때 표시되도록 할 수 있습니다. 일반 사용자는 아이콘을 클릭합니다. 보조 기술 사용자의 경우 설명은 해당 폼 필드에서 `aria-describedby`으로 직접 참조됩니다.

`aria-describedby` 속성은 관련 콘텐츠에 일반 텍스트로 표시되는 설명이 포함되는 경우에 적절합니다. 콘텐츠에 많은 양의 콘텐츠, 유용한 시멘틱이 포함되어 있거나 사용자 탐색을 요구하는 복잡한 구조인 경우 `aria-details` (en-US)를 사용합니다. `aria-details`는 보조 기술 사용자에게 관련 구조화된 콘텐츠를 방문하고 추가 탐색 명령을 제공해서 구조를 더 쉽게 이해하거나 정보를 더 작은 조각으로 경험할 수 있게 해줍니다.

**참고:** `aria-describedby` 콘텐츠는 텍스트 문자열이어야 합니다. 콘텐츠에 중요한 기본 시멘틱이 있는 경우 `aria-details` (en-US)를 사용하는 것이 좋습니다.

예제
--

```html
<button aria-describedby="trash-desc">휴지통으로 이동</button>
…
<p id="trash-desc">휴지통에 있는 항목은 30일 후에 영구적으로 삭제됩니다.</p>
```

**참고:** `aria-describedby` 속성은 외부 리소스로부터의 설명을 참조하도록 설계되지 않았습니다. 이 값은 하나 이상의 `id`(다수인 경우 공백으로 구분)이므로 동일한 DOM 문서에 있는 요소를 참조해야 합니다.

값
-

ID 참조 목록

현재 요소를 설명하는 `id` 혹은 공백으로 구분된 요소 `id` 목록입니다.

관련 역할
-----

**모든** 역할에 사용됩니다. 모든 HTML 요소에서도 사용할 수 있습니다.

명세서
---

| Specification |
| --- |
| Accessible Rich Internet Applications (WAI-ARIA) # aria-describedby |
| Accessible Rich Internet Applications (WAI-ARIA) # aria-describedby |

같이 보기
-----

* `<label>`
* `aria-labelledby` (en-US)
* `aria-description` (en-US)
* `aria-details` (en-US)
* Browser and AT support for `aria-describedby`


Transforming XML with XSLT - XSLT

Transforming XML with XSLT
==========================

### 개요

내용과 겉모양의 분리가 XML의 중요한 설계 특징입니다. XML 문서 구조는 결국 이 데이터를 어떻게 표시하는 게 좋을지에 관한 어떤 암시를 줄 필요로 방해받지 않은 내용 자체의 서로 다른 면(aspect) 사이의 중요한 관계를 반영하고 명확히 하기 위해 설계했습니다. 이 지적인 구조화는 데이터 전송이 더욱 자동화되는 것만큼 특히 중요하고 네트워크로 연결된 매우 이질적인 컴퓨터 사이에 일어난다.

아직은 결국 XML 문서에 저장된 많은 내용을 읽는 사람에게 표시할 필요가 있습니다. 왜냐하면 브라우저가 친근하고 유연성이 높은 인터페이스를 제공하기 때문에, 그것은 XML 내용의 표시 버전 같은 이상적인 전달 메커니즘입니다. 철저하게 아주 다양한 XML 기술을 이용하게 만들었기 때문에, Mozilla는 원 XML 문서와 스타일 입히기와 클라이언트 측 처리로 인한 서버 부담을 줄이기 위해 HTML 표시에 그들을 놓기로 쓰는 특수 스타일시트 둘 다를 처리할 필요가 있는 모든 메커니즘을 자체에 통합시킵니다.

오늘날, Gecko(the layout engine behind Mozilla와 Firefox)는 두 형태(form)의 XML 스타일시트를 지원합니다. 겉모습(글꼴, 색, 자리들)의 기본 조절을 위해 Gecko는 DHTML과 친근한 CSS를 씁니다. CSS1 전부와 CSS2 대부분을 지원합니다. 최근 생겨난 CSS3 표준 지원은 개발중입니다. CSS에 관한 추가 정보는 Eric Meyer's CSS pages를 보시기 바랍니다.

여기서 우리의 관심은 Gecko가 지원하는 스타일시트의 두 번째 형태인 XSLT 스타일시트에 대해서입니다. XSLT는 eXtensible Stylesheet Language/Transform을 나타내고 그 이름은 적절합니다. XSLT는 스타일시트 만든 이가 그러길 바란다면 컨텐트를 모조리 다시 정리하고 다른 형식으로 변환하는 것을 포함하는 컨텐트 조작(manipulating)과 정렬이라는 중요한 두 방식으로 본래 XML 문서를 변환하게 합니다(그리고 Mozilla의 경우에, 초점은 브라우저에 표시될 수 있는 HTML로 즉시 변환하는 데 있습니다).

### XSLT/XPath 참조

#### 요소

* xsl:apply-imports *(지원함)*
* xsl:apply-templates *(지원함)*
* xsl:attribute *(지원함)*
* xsl:attribute-set *(지원함)*
* xsl:call-template *(지원함)*
* xsl:choose *(지원함)*
* xsl:comment *(지원함)*
* xsl:copy *(지원함)*
* xsl:copy-of *(지원함)*
* xsl:decimal-format *(지원함)*
* xsl:element *(지원함)*
* xsl:fallback *(지원 안 함)*
* xsl:for-each *(지원함)*
* xsl:if *(지원함)*
* xsl:import *(대부분 지원)*
* xsl:include *(지원함)*
* xsl:key *(지원함)*
* xsl:message *(지원함)*
* xsl:namespace-alias *(지원 안 함)*
* xsl:number *(부분 지원)*
* xsl:otherwise *(지원함)*
* xsl:output *(부분 지원)*
* xsl:param *(지원함)*
* xsl:preserve-space *(지원함)*
* xsl:processing-instruction
* xsl:sort *(지원함)*
* xsl:strip-space *(지원함)*
* xsl:stylesheet *(부분 지원)*
* xsl:template *(지원함)*
* xsl:text *(부분 지원)*
* xsl:transform *(지원함)*
* xsl:value-of *(부분 지원)*
* xsl:variable *(지원함)*
* xsl:when *(지원함)*
* xsl:with-param *(지원함)*

#### 축

* ancestor
* ancestor-or-self
* attribute
* child
* descendant
* descendant-or-self
* following
* following-sibling
* namespace *(지원 안 함)*
* parent
* preceding
* preceding-sibling
* self

#### 함수

* boolean() *(지원함)*
* ceiling() *(지원함)*
* concat() *(지원함)*
* contains() *(지원함)*
* count() *(지원함)*
* current() *(지원함)*
* document() *(지원함)*
* element-available() *(지원함)*
* false() *(지원함)*
* floor() *(지원함)*
* format-number() *(지원함)*
* function-available() *(지원함)*
* generate-id() *(지원함)*
* id() *(부분 지원)*
* key() *(지원함)*
* lang() *(지원함)*
* last() *(지원함)*
* local-name() *(지원함)*
* name() *(지원함)*
* namespace-uri() *(지원함)*
* normalize-space() *(지원함)*
* not() *(지원함)*
* number() *(지원함)*
* position() *(지원함)*
* round() *(지원함)*
* starts-with() *(지원함)*
* string() *(지원함)*
* string-lenght() *(지원함)*
* substring() *(지원함)*
* substring-after() *(지원함)*
* substring-before() *(지원함)*
* sum() *(지원함)*
* system-property() *(지원함)*
* translate() *(지원함)*
* true() *(지원함)*
* unparsed-entity-url() *(지원 안 함)*
### 더 읽을 거리

* Books
* Online
    + The World Wide Web Consortium
    + Portals
    + Articles
    + Tutorials/Examples
    + Mailing Lists/Newsgroups
### 찾아보기

### 원본 문서 정보

* 저작권 정보: Copyright © 2001-2003 Netscape. All rights reserved.
* 주의: 이 재판 article은 원래 DevEdge 사이트 부분이었습니다.


Elements - XSLT

Elements
========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축
 여기에서 다루는 요소의 두 타입은 최상위 요소와 명령(instruction)입니다. 최상위 요소는 `<xsl:stylesheet>`나 `<xsl:transform>`의 자식으로 나타나야 합니다. 이에 반해, 명령은 템플릿과 관련이 있습니다. 스타일시트는 여러 템플릿을 포함할지도 모릅니다. 여기서 다루지 않는 세 번째 타입의 요소는 LRE(literal result element)입니다. LRE 또한 템플릿에 나타납니다. LRE는 예를 들어, HTML 변환 스타일시트 안의 `<hr>` 요소처럼 결과 문서에 복사되는게 좋은 어떤 비명령 요소로 이루어져 있습니다.
관련 기록에 따르면, LRE의 어떤 속성과 한정된 수의 XSLT 요소의 속성도 속성값 템플릿으로 알려진 것을 또한 포함할 수 있습니다. 속성값 템플릿은 단순히 속성값 지정에 쓰이는 임베드된 XPath 식을 포함하는 문자열입니다. 실행할 때 식을 평가하고 평가 결과는 XPath 식으로 바꾸어 놓습니다. 예를 들어, "`image-dir`" 변수를 다음처럼 정의했다고 하면,
```

<xsl:variable name="image-dir">/images</xsl:variable>
```

평가된 식은 중괄호 안에 놓입니다.
```

<img src="{$image-dir}/mygraphic.jpg"/>
```

이는 다음과 같은 결론에 다다릅니다.
```

<img src="/images/mygraphic.jpg"/>
```

뒤따르는 요소 주석은 설명과 문법 나열, 필수 속성과 선택 속성 목록, 타입과 자리 설명, W3C 권고안 속 요소 소스와 현 Gecko의 지원 정도에 대한 설명을 포함합니다.

* `<xsl:apply-imports>`
* `<xsl:apply-templates>`
* `<xsl:attribute>`
* `<xsl:attribute-set>`
* `<xsl:call-template>`
* `<xsl:choose>`
* `<xsl:comment>`
* `<xsl:copy>`
* `<xsl:copy-of>`
* `<xsl:decimal-format>`
* `<xsl:element>`
* `<xsl:fallback>` *(not supported)*
* `<xsl:for-each>`
* `<xsl:if>`
* `<xsl:import>` *(mostly supported)*
* `<xsl:include>`
* `<xsl:key>`
* `<xsl:message>`
* `<xsl:namespace-alias>` *(not supported)*
* `<xsl:number>` *(partially supported)*
* `<xsl:otherwise>`
* `<xsl:output>` *(partially supported)*
* `<xsl:param>`
* `<xsl:preserve-space>`
* `<xsl:processing-instruction>`
* `<xsl:sort>`
* `<xsl:strip-space>`
* `<xsl:stylesheet>` *(partially supported)*
* `<xsl:template>`
* `<xsl:text>` *(partially supported)*
* `<xsl:transform>`
* `<xsl:value-of>` *(partially supported)*
* `<xsl:variable>`
* `<xsl:when>`
* `<xsl:with-param>`


otherwise - XSLT

otherwise
=========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:otherwise>` 요소는 아무런 `<xsl:when>` 조건도 적용하지 않았을 때 취하면 좋을 동작을 정의하는 데 씁니다. 다른 프로그래밍 언어의 `else`나 `default` 경우와 비슷합니다.

### 문법
```

<xsl:otherwise>
  TEMPLATE
</xsl:otherwise>
```

### 필수 속성

없음.

### 선택 속성

없음.

### 타입

하위명령, 템플릿 안에서 `<xsl:choose>` 요소의 마지막 자식으로 나타나야 함.

### 정의

XSLT section 9.2, Conditional Processing with xsl:choose

### Gecko 지원

지원함.


message - XSLT

message
=======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:message>` 요소는 (NS에서 JavaScript 콘솔에) 메시지를 출력하고 선택에 따라 스타일시트 실행을 끝냅니다. 디버깅에 유용할 수 있습니다.

### 문법
```

<xsl:message terminate="yes" | "no" >
  TEMPLATE
</xsl:message>
```

### 필수 속성

없음.

### 선택 속성

`terminate`

"`yes`"로 설정하면, 실행을 끝마치는 게 좋겠다는 것을 나타냅니다. 기본값은 "`no`"이고 어느 경우에는 메시지가 출력하고 실행을 계속합니다.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 13, Messages

### Gecko 지원

지원함.


for-each - XSLT

for-each
========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:for-each>` 요소는 노드 집합을 선택하고 같은 방식으로 각 노드를 처리합니다. 노드 집합을 되풀이하(iterate)거나 현재 노드를 바꾸는데 자주 씁니다. 하나 이상의 `<xsl:sort>` 요소가 이 요소의 자식으로 나타나면, 처리에 앞서 정렬을 합니다. 그렇지 않으면, 노드는 문서 순으로 처리합니다.

### 문법
```

<xsl:for-each select=EXPRESSION>
  <xsl:sort> [optional]
  TEMPLATE
</xsl:for-each>
```

### 필수 속성

`select`

처리할 노드를 선택하기 위해 XPath 식을 씁니다.

### 선택 속성

없음.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 8, Repetition

### Gecko 지원

지원함.


number - XSLT

number
======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:number>` 요소는 숫자를 연속으로 셉니다. 또한 숫자를 빠르게 구성하는(format) 데도 쓸 수 있습니다.

### 구문

```xml
<xsl:number
 count=EXPRESSION
 level="single" | "multiple" | "any"
 from=EXPRESSION
 value=EXPRESSION
 format=FORMAT-STRING
 lang=XML:LANG-CODE
 letter-value="alphabetic" | "traditional"
 grouping-separator=CHARACTER
 grouping-size=NUMBER />
```

### 필수 속성

없음.

### 선택 속성

`count`

소스 트리에서 연속으로 셀 대상을 지정합니다. XPath 식을 씁니다.

`level`

일련번호를 만드는데 소스 트리의 수준을 어떻게 고려해야 하는 지를 정의합니다. 유효한 값은 `single`, `multiple`, `any` 세 가지. 기본값은 `single`입니다.

* `single` 목록의 항목대로 연속으로 형제 노드를 번호 매깁니다. 처리기는 `count` 속성과 일치하는 `ancestor-or-self` 축의 첫 번째 노드로 갑니다. 그리고 나서 역시 `count` 속성과 일치하는 앞선 형제(preceding siblings) 노드(있다면, 한 짝인 `from` 속성에 이르러 멈춤)를 모두 더하여 셉니다. 일치하지 않으면, sequence는 빈 목록입니다.
* `multiple` 노드의 계층 위치를 반영하는 복합 sequence로 노드를 셉니다. 예를 들어, 1.2.2.5 (포개진 형식은 `format` 속성(예, A.1.1)으로 지정할 수 있습니다). 처리기는 만약 있다면 `from` 속성에 이르러 멈추며 현재 노드와 현재 노드의 모든 `ancestors`를 조사합니다. 일치하지 않으면, sequence는 빈 목록입니다.
* `any` (이번에 지원 안 함.) 수준을 무시하고 연속으로 일치하는 모든 노드를 셉니다. `ancestor`, `self`, `preceding` 축을 모두 고려합니다. 처리기는 현재 노드에서 시작하여 `from` 속성과 일치할 때 멈추며 문서 역순으로 진행합니다. 발견한 `count` 속성과 일치하지 않으면, sequence는 빈 목록입니다. 이 수준은 이번에 지원하지 않습니다.

from

번호 매기기를 시작하거나 다시 시작하면 좋을 곳을 지정합니다. 순서는 `from` 특성과 일치하는 노드의 첫 번째 자손(descendant)에서 시작합니다.

value

숫자에 주어진 형식을 적용합니다. 이것이 사용자 제공 숫자(노드 sequence 숫자와는 반대로)를 표준 `<xsl:number>` 형식으로 구성하는 빠른 방법입니다.

format

만드는 숫자의 형식을 정의합니다.

format="1"

1 2 3 . . . (This is the only format supported at this time)

format="01"

01 02 03 . . . 09 10 11 . . .

format="a"

a b c . . .y z aa ab . . .

format="A"

A B C . . . Y Z AA AB . . .

format="i"

i ii iii iv v . . .

format="I"

I II III IV V . . .

lang (이번에는 지원 안 함)

문자에 기반을 둔 번호 매기기 형식에 쓰면 좋을 언어의 알파벳을 지정합니다.

letter-value

문자(letter)를 쓰는 번호 매김 열(sequence) 사이를 명확하게 합니다. 어떤 언어는 문자(letter)를 쓰는 하나 이상의 번호 매기기 시스템이 있습니다. 두 시스템이 같은 토큰으로 시작하면, 모호함이 생길 수 있습니다. 이 속성은 "`alphabetic`"나 "`traditional`" 값일 수 있습니다. 기본값은 "`alphabetic`"입니다.

grouping-separator

어떤 문자를 그룹(예로 천 단위) 구분자로 쓰면 좋을지를 지정합니다. 기본값은 쉼표(`,`)입니다.

grouping-size

숫자 그룹을 만드는 자릿수를 나타냅니다. 기본값은 "`3`"입니다.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 7.7, Numbering

### Gecko 지원

부분 지원. 위 해설을 보세요.


fallback - XSLT

fallback
========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:fallback>` 요소는 주어진 확장(이나 결국에는 새 버전) 요소에서 지원하지 않으면 쓸 템플릿을 지정합니다.

### 문법
```

<xsl:fallback>
  TEMPLATE
</xsl:fallback>
```

### 필수 속성

없음.

### 선택 속성

없음.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 15, Fallback

### Gecko 지원

이번에 지원 안 함.


decimal-format - XSLT

decimal-format
==============

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:decimal-format>` 요소는
 `format-number( )`
 함수를 써서 숫자를 문자열로 바꿀 때 쓰는 기호와 문자를 정의합니다.

### 문법
```

<xsl:decimal-format
  name=NAME
  decimal-separator=CHARACTER
  grouping-separator=CHARACTER
  infinity=STRING
  minus-sign=CHARACTER
  NaN=STRING
  percent=CHARACTER
  per-mille=CHARATER
  zero-digit=CHARACTER
  digit=CHARACTER
  pattern-separator=CHARACTER />
```

### 필수 속성

없음.

### 선택 속성

`name`

이 형식에 이름을 지정합니다.

`decimal-separator`

소숫점 문자를 지정합니다. 기본값은 (`.`)입니다.

`grouping-separator`

그룹 구분 문자를 지정합니다. 기본값은 (`,`)입니다.

`infinity`

무한대(infinity)를 나타내는데 쓰는 문자열을 지정합니다. 기본값은 "`Infinity`" 문자열입니다.

`minus-sign`

빼기 기호 문자를 지정합니다. 기본값은 (`-`)입니다.

`NaN`

값이 숫자가 아닐 때 쓰는 문자열을 지정합니다. 기본값은 "`NaN`" 문자열입니다.

`percent`

백분율(percentage) 기호 문자를 지정합니다. 기본값은 (`%`)입니다.

`per-mille`

천분율(per thousand) 문자를 지정합니다. 기본값은 (`‰`)입니다.

`zero-digit`

숫자 0으로 쓸 문자를 지정합니다. 기본값은 (`0`)입니다.

`digit`

형식 패턴에서 숫자(digit)를 나타내는데 쓰는 문자를 지정합니다. 기본값은 (`#`)입니다.

`pattern-separator`

형식 패턴에서 양수와 음수 부분패턴을 구분하는 문자를 지정합니다. 기본값은 (`;`)입니다.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식이어야 함.

### 정의

XSLT section 12.3, Number Formatting

### Gecko 지원

Mozilla 1.0과 Netscape 7.0 현재 지원함.


comment - XSLT

comment
=======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:comment>` 요소는 출력 문서에 주석을 작성합니다. 오직 텍스트만 포함해야 합니다.

### 문법
```

<xsl:comment>
  TEMPLATE
</xsl:comment>
```

### 필수 속성

없음.

### 선택 속성

없음.

### 타입

명령, 템플릿과 함께 나타남.

### 정의

XSLT section 7.4, Creating Comments

### Gecko 지원

지원함.


apply-templates - XSLT

apply-templates
===============

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:apply-templates>` 요소는 입력 트리 안 노드 집합을 선택하고 그 집합에 알맞은 템플릿을 적용하도록 처리기에게 지시합니다.

### 문법
```

<xsl:apply-templates select=EXPRESSION mode=NAME>
  <xsl:with-param> [optional]
  <xsl:sort> [optional]
</xsl:apply-templates>
```

### 필수 속성

없음.

### 선택 속성

`select`

처리할 노드를 지정하는 XPath 식을 씁니다. 별표(`*`)는 전체 노드 집합을 선택합니다. 이 속성이 없으면, 현재 노드의 모든 자식 노드를 선택합니다.

`mode`

같은 노드를 정의하는 다양한 처리 방법이 있다면, 그 방법들을 구별합니다.

### 타입

명령, 템플릿 안에 나타남

### 정의

XSLT section 5.4, Applying Template Rules

### Gecko 지원

지원함.


attribute - XSLT

attribute
=========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:attribute>` 요소는 스타일시트에서 접근할 수 있는 어떤 값을 써서 출력 문서에 속성을 만듭니다. 요소는 속성값을 자리 잡게 하는 출력 문서 요소 안에 정의한 것 가운데 처음이어야 합니다.

### 문법
```

<xsl:attribute name=NAME namespace=URI>
  TEMPLATE
</xsl:attribute>
```

### 필수 속성

`name`

출력 문서에 만들려는 속성에 이름을 지정합니다. 이름은 유효한 QName이어야 합니다.

### 선택 속성

`namespace`

출력 문서에 이 속성을 위한 이름공간(namespace) URI를 정의합니다. 이 요소와 관련된 이름공간 접두사를 설정할 수 없습니다.

### 타입

명령, 템플릿이나 `<xsl:attribute-set>` 요소 안에 나타남.

### 정의

XSLT section 7.1.3, Creating Attributes with xsl:attribute

### Gecko 지원

지원함.


variable - XSLT

variable
========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:variable>` 요소는 스타일시트에 전역 변수나 지역 변수를 선언하고 그 변수에 값을 줍니다. XSLT가 부작용(side-effect)을 허용하지 않기 때문에, 변수값을 한 번 주면 그 변수는 범위(scope)를 벗어날 때까지 같은 값입니다.

### 구문
```

<xsl:variable name=NAME select=EXPRESSION >
  TEMPLATE
</xsl:variable>
```

### 필수 속성

`name`

변수에 이름을 줍니다.

### 선택 속성

`select`

변수값을 XPath 식으로 정의합니다. 요소가 템플릿을 포함하면, 이 속성은 무시합니다.

### 타입

최상위 또는 명령. 최상위 요소로 나타나면, 변수의 범위는 전역이고 문서 전체에서 접근할 수 있습니다. 템플릿 안에 나타나면, 번수의 범위는 지역이고 나타난 템플릿 안에서만 접근할 수 있습니다.

### 정의

XSLT section 11, Variables and Parameters

### Gecko 지원

지원함.


text - XSLT

text
====

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:text>` 요소는 출력 트리에 리터럴(literal) 텍스트를 씁니다. `#PCDATA`, 리터럴 텍스트, 엔티티 참조를 포함할 지도 모릅니다.

### 구문
```

<xsl:text disable-output-escaping="yes" | "no">
  TEXT
</xsl:text>
```

### 필수 속성

없음.

### 선택 속성

`disable-output-escaping` (Netscape은 변환 결과를 "output" 아래에 직렬하지 않습니다. 그래서 이 속성은 본래 문맥에서는 무의미합니다. HTML 엔티티를 출력하기 위해서는, 대신 숫자값을 쓰세요. 보기 &`nbsp` 대신 `&#160`)

특수 문자를 출력에 쓸 때 해석할(escape) 지를 지정합니다. 가능한 값은 "`yes`"나 "`no`"입니다. 예를 들어, "`yes`"로 하면, 문자의 출력은 "`&gt`"가 아니라 `>`입니다.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 7.2, Creating Text

### Gecko 지원

적힌 대로 지원함


strip-space - XSLT

strip-space
===========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:strip-space>` 요소는 공백을 지웠으면 하는 소스 문서의 요소를 정의합니다.

### 문법
```

<xsl:strip-space elements=LIST-OF-ELEMENT-NAMES  />
```

### 필수 속성

`elements`

지우면 좋을 공백뿐인 텍스트 노드가 있는 소스의 요소 목록(빈칸으로 구분)을 지정합니다.

### 선택 속성

없음.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식이어야 함.

### 정의

XSLT section 3.4, Whitespace Stripping

### Gecko 지원

지원함.


transform - XSLT

transform
=========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:transform>` 요소는 `<xsl:stylesheet>` 요소와 정확히 같습니다.

### Gecko 지원

지원함.


apply-imports - XSLT

apply-imports
=============

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:apply-imports>` 요소는 꽤 불가사의하고 보통은 복잡한 스타일시트에 쓰입니다. 가져오기(import) 우선순위는 가져온 스타일시트 안 템플릿 규칙보다 주 스타일시트의 안 템플릿 규칙이 더 높기를 요구합니다. 그러나, 때로는 처리기(processor)가 주 스타일시트 안 규칙보다 (우선순위가 낮은) 가져온 스타일시트의 템플릿 규칙을 쓰도록 강제할 수 있는 게 유용합니다.

### 문법
```

<xsl:apply-imports/>
```

### 필수 속성

없음.

### 선택 속성

없음.

### 타입

명령, 템플릿 안에 나타남

### 정의

XSLT section 5.6, Overriding Template Rules

### Gecko 지원

지원함.


namespace-alias - XSLT

namespace-alias
===============

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:namespace-alias>` 요소는 스타일시트 이름공간을 출력 트리의 다른 이름공간으로 매기는(map) 데 드물게 쓰는 방안(device)입니다. 이 요소의 가장 평범한 쓰임은 다른 스타일시트로부터 스타일시트를 만드는 것입니다. 보통 `xsl:`가 접두사로 붙은 (결과 트리에 단순히 복사해도 좋을) LRE(literal result element)를 처리기가 오해하는 것을 막기 위해, 결과 트리의 XSLT 이름공간에 적당하게 도로 다시 바꿀 임시 이름공간을 할당합니다.

### 문법
```

<xsl:namespace-alias stylesheet-prefix=NAME result-prefix=NAME />
```

### 필수 속성

`stylesheet-prefix`

임시 이름공간을 지정합니다.

`result-prefix`

결과 트리에 사용하길 바라는 이름공간을 지정합니다.

### 선택 속성

없음.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식이어야 함.

### 정의

XSLT section 7.1.1, Literal Result Elements

### Gecko 지원

이번에 지원 안 함.


attribute-set - XSLT

attribute-set
=============

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:attribute-set>` 요소는 CSS 안에 이름 붙인 스타일과 비슷한 방식으로 이름 붙인 속성 집합을 만듭니다. 그러면, 출력 문서에 전체로서 적용할 수 있습니다.

### 문법
```

<xsl:attribute-set name=NAME use-attribute-sets=LIST-OF-NAMES>
  <xsl:attribute>
</xsl:attribute-set>
```

### 필수 속성

`name`

속성 집합에 이름을 지정합니다. 이름은 유효한 QName이어야 합니다.

### 선택 속성

`use-attribute-sets`

다른 속성 집합으로부터 속성 집합을 빌드합니다. 기여한 집합의 이름은 공백 문자로 구분해야 하고 직접 혹은 간접으로 서로 임베드하지 않아야 합니다.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식이어야 함.

### 정의

XSLT section 7.1.4, Named Attribute Sets

### Gecko 지원

지원함.


import - XSLT

import
======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:import>` 요소는 한 스타일시트의 컨텐트를 다른 스타일시트로 가져오는 역할을 하는 최상위 요소입니다. 대체로, 가져올 스타일시트의 컨텐트는 가져오는 스타일시트의 컨텐트보다 가져오기 우선순위가 낮습니다. 이는 포함되는 스타일시트의 컨텐트가 포함하는 스타일시트의 컨텐트와 우선순위가 정확히 같은 `<xsl:include>`와는 뚜렷이 다릅니다.

### 문법
```

<xsl:import href=URI  />
```

### 필수 속성

`href`

가져올 스타일시트의 URI를 지정합니다.

### 선택 속성

없음.

### 타입

최상위, 가져오는 스타일시트 안 `<xsl:stylesheet>`나 `<xsl:transform>`의 자식 가운데 가장 앞에 나타나야 함.

### 정의

XSLT section 2.6.2, Stylesheet Import

### Gecko 지원

Mozilla 1.0 현재 최상위 변수와 매개변수에 문제가 조금 있지만 대부분 지원함.


template - XSLT

template
========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:template>` 요소는 출력 생성 템플릿을 정의합니다. 이 요소는 match 속성이나 name 속성 집합이 있어야 합니다.

### 문법
```

<xsl:template
  match=PATTERN
  name=NAME
  mode=NAME
  priority=NUMBER>
  <xsl:param> [optional]
  TEMPLATE
</xsl:template>
```

### 필수 속성

없음.

### 선택 속성

`match`

이 템플릿을 쓰면 좋을 요소를 결정하는 패턴을 지정합니다. `name` 속성이 없다면, 필수 속성입니다.

`name`

`<xsl:call-template>` 요소가 호출할 수 있는 이 템플릿에 이름을 지정합니다.

`mode`

이 템플릿에 `<xsl:apply-templates>` 요소의 속성과 일치할 수 있는 특유한 모드를 지정합니다. 이는 같은 정보를 다양한 방식으로 처리하는데 유용합니다.

`priority`

이 템플릿에 숫자로 된 우선권을 지정합니다. 이는 `Infinity`와 다른 아무 숫자일 수 있습니다. 처리기는 하나 이상의 템플릿이 같은 노드와 일치할 때 이 숫자를 씁니다.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식이어야 함.

### 정의

XSLT section 5.3, Defining Template Rules

### Gecko 지원

지원함.


processing-instruction - XSLT

processing-instruction
======================

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:processing-instruction>` 요소는 출력 문서에 처리 명령을 씁니다.

### 문법

`<xsl:processing-instruction name=NAME> TEMPLATE </xsl:processing-instruction>`

### 필수 속성

`name`

처리 명령에 이름을 지정합니다.

### 선택 속성

없음.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 7.3, Creating Processing Instructions

### Gecko 지원

지원함.


if - XSLT

if
==

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:if>` 요소는 test 속성과 템플릿을 포함합니다. test 속성을 참으로 평가하면, 템플릿을 처리합니다. 이것은 다른 언어의 if 문과 비슷합니다. 그러나, `<tt>if-then-else</tt>` 문의 기능을 다하기 위해 `<xsl:when>`과 `<xsl:otherwise>` 자식이 하나씩 있는 `<xsl:choose>` 요소를 씁니다.

### 문법
```

<xsl:if test=EXPRESSION>
  TEMPLATE
</xsl:if>
```

### 필수 속성

`test`

Boolean 값으로 (필요하다면 `boolean( )`으로 정의한 규칙을 써서) 평가할 수 있는 XPath 식을 포함합니다. 값이 참이면 템플릿을 처리하고 거짓이면 아무 동작도 하지 않습니다.

### 선택 속성

없음.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 9.1, Conditional Processing with xsl:if

### Gecko 지원

지원함.


include - XSLT

include
=======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:include>` 요소는 한 스타일시트의 컨텐트를 다른 스타일시트에 합칩니다. `<xsl:import>`와는 달리, 포함되는 스타일시트의 컨텐트는 포함하는 스타일시트의 컨텐트와 우선순위가 정확히 같습니다.

### 문법
```

<xsl:include href=URI />
```

### 필수 속성

`href`

포함할 스타일시트의 URI를 지정합니다.

### 선택 속성

없음.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식으로 나타남.

### 정의

XSLT section 2.6.1, Stylesheet Inclusion

### Gecko 지원

지원함.


call-template - XSLT

call-template
=============

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:call-template>` 요소는 이름 붙인 템플릿을 호출합니다.

### 문법
```

<xsl:call-template name=NAME>
  <xsl:with-param> [optional]
</xsl:call-template>
```

### 필수 속성

`name`

호출하고 싶은 템플릿의 이름을 지정합니다.

### 선택 속성

없음.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 6, Named Templates

### Gecko 지원

지원함.


copy - XSLT

copy
====

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:copy>` 요소는 출력 문서에 현재 노드의 노드와 어떤 관련 이름공간 노드만을 얕게 복사(shallow copy) 전달합니다. 속성이나 자식은 복사하지 않습니다.

### 문법
```

<xsl:copy use-attribute-sets=LIST-OF-NAMES>
  TEMPLATE
</xsl:copy>
```

### 필수 속성

없음.

### 선택 속성

`use-attribute-sets`

요소이면, 출력 노드에 적용해도 좋을 속성 집합을 나열합니다. 집합의 이름은 공백 문자로 구분해야 합니다.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 7.5, Copying

### Gecko 지원

지원함.


stylesheet - XSLT

stylesheet
==========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:stylesheet>`(나 동등한 `<xsl:transform>`) 요소는 스타일시트의 최외곽 요소입니다.

### 이름공간 선언

pseudo 속성은 XSLT 스타일시트로 문서를 식별하기 위해 필요합니다. 대체로 이는 `xmlns:xsl="http://www.w3.org/1999/XSL/Transform"`입니다.

### 문법
```

<xsl:stylesheet
  version=NUMBER
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  id=NAME
  extension-element-prefixes=LIST-OF-NAMES
  exclude-result-prefixes=LIST-OF-NAMES>
    ENTIRE STYLESHEET
</xsl:stylesheet>
```

### 필수 속성

`version`

이 스타일시트에 필요한 XSLT의 버전을 지정합니다.

### 선택 속성

`id` (7.0 현재 오직 inline DTD가 명시하여 호출하는 경우만 지원함.)

이 스타일시트에 `id`를 지정합니다. 이는 스타일시트를 다른 XML 문서에 포함할 때 가장 자주 씁니다.

extension-element-prefixes (지원 안 함.)

이 문서의 확장 요소에 빈칸으로 구분한 이름공간 접두사를 지정합니다.

exclude-result-prefixes

이 문서에 쓸 출력 문서에 보내지 않았으면 하는 이름공간을 지정합니다. 목록은 공백으로 구분합니다.

### 타입

필수 최외곽 스타일시트 요소.

### 정의

XSLT section 2.2, Stylesheet Element

### Gecko 지원

조금 지원. 위 해설을 보세요.


output - XSLT

output
======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:output>` 요소는 출력 문서의 특성을 조절합니다. method 속성이 있는 이 요소가 Netscape에서 정확하게 기능하도록 쓸 수 있어야 합니다. 7.0 현재, `method="text"`는 기대한 대로 동작합니다.

### 문법
```

<xsl:output
  method="xml" | "html" | "text"
  version=STRING
  encoding=STRING
  omit-xml-declaration="yes" | "no"
  standalone="yes" | "no"
  doctype-public=STRING
  doctype-system=STRING
  cdata-section-elements=LIST-OF-NAMES
  indent="yes" | "no"
  media-type=STRING  />
```

### 필수 속성

없음.

### 선택 속성

`method`

출력 형식을 지정합니다.

`version`

출력 문서에 XML이나 HTML 선언의 version 속성값을 지정합니다. 이 속성은 `method="html"`나 `method="xml"`일 때만 씁니다.

`encoding`

출력 문서에 `encoding` 속성값을 지정합니다.

`omit-xml-declaration`

출력에 XML 선언을 포함할 지를 나타냅니다. 가능한 값은 "`yes`"나 "`no`"입니다.

`standalone` (지원 안 함.)

있으면, standalone 선언이 출력 문서에 나타나면 좋을 지를 나타내고 그 값을 줍니다. 가능한 값은 "yes"나 "no"입니다.

`doctype-public`

출력 문서에 `DOCTYPE` 선언의 `PUBLIC` 속성값을 지정합니다.

`doctype-system`

출력 문서에 `DOCTYPE` 선언의 `SYSTEM` 속성값을 지정합니다.

`cdata-section-elements`

`CDATA` 절에 써도 좋을 요소의 텍스트 컨텐트를 나열합니다. 요소는 공백으로 구분해야 합니다.

`indent` (지원 안 함.)

출력에 계층 구조를 나타내도록 하면 좋을 지를 지정합니다.

`media-type` (지원 안 함.)

출력 문서의 MIME 타입을 지정합니다.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식이어야 함.

### 정의

XSLT section 16, Output

### Gecko 지원

부분 지원. 위 해설을 보세요.


key - XSLT

key
===

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:key>` 요소는 `key( )` 함수가 있는 스타일시트 어디서나 쓸 수 있는 이름 붙은 키를 선언합니다.

### 문법
```

<xsl:key name=NAME match=EXPRESSION
  use=EXPRESSION />
```

### 필수 속성

`name`

이 키에 이름을 지정합니다. QName이어야 합니다.

`match`

이 키를 적용할 수 있는 노드를 정의합니다.

`use`

적용가능한 각 노드에 키값을 결정하는데 쓸 수 있는 XPath 식을 지정합니다.

### 선택 속성

없음.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식이어야 함.

### 정의

XSLT section 12.2, Keys

### Gecko 지원

지원함.


sort - XSLT

sort
====

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:sort>` 요소는 `<xsl:apply-templates>`나 `<xsl:for-each>`가 선택한 노드에 정렬키를 정의하고 노드를 처리할 순서를 결정합니다.

### 문법
```

<xsl:sort
  select=EXPRESSION
  order="ascending" | "descending"
  case-order="upper-first"| "lower-first"
  lang=XML:LANG-CODE
  data-type="html" | "xml" | "text" />
```

### 필수 속성

없음.

### 선택 속성

`select`

정렬할 노드를 지정하는 XPath 식을 씁니다.

`order`

"`ascending`"나 "`descending`"으로 처리하면 좋을 노드를 지정합니다. 기본값은 "`ascending`"입니다.

`case-order`

처음에 오는 게 대문자인지 소문자인지를 나타냅니다. 가능한 값은 "`upper-first`"와 "`lower-first`"입니다.

`lang`

어떤 언어를 정렬에 쓸지를 지정합니다.

`data-type`

어떤 항목을 알파벳순이나 숫자순으로 순서 매길지를 정의합니다. 가능한 값은 "`text`"와 기본값인 "`text`"가 있는 "`number`"입니다.

### 타입

하위명령, 항상 `<xsl:for-each>`의 자식으로 나타나고 고유(proper) 템플릿이나 `<xsl:apply-templates>` 앞에 나타나야 함.

### 정의

XSLT section 10, Sorting

### Gecko 지원

지원함.


when - XSLT

when
====

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:when>` 요소는 항상 case 문처럼 동작하는 `<xsl:choose>` 요소 안에 나타납니다.

### 문법
```

<xsl:when test=EXPRESSION>
  TEMPLATE
</xsl:when>
```

### 필수 속성

`test`

평가할 boolean 식을 지정합니다. 참이면, 요소의 컨텐트는 처리하고 거짓이면, 무시합니다.

### 선택 속성

없음.

### 타입

하위명령, 항상 `<xsl:choose>` 요소 안에 나타남.

### 정의

XSLT section 9.2, Conditional Processing with xsl:choose

### Gecko 지원

지원함.


value-of - XSLT

value-of
========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:value-of>` 요소는 XPath 식을 평가하여 그것을 문자열로 바꾸고 문자열을 결과 트리에 씁니다.

### 구문
```

<xsl:value-of select=EXPRESSION disable-output-escaping="yes" | "no"  />
```

### 필수 속성

`select`

평가하고 출력 트리에 쓸 XPath 식을 지정합니다.

### 선택 속성

`disable-output-escaping` (Netscape은 변환 결과를 "output" 아래에 직렬하지 않습니다. 그래서 이 속성은 본래 문맥에서는 무의미합니다. HTML 엔티티를 출력하기 위해서는, 대신 숫자값을 쓰세요. 보기 &`nbsp` 대신 `&#160`)

특수 문자를 출력에 쓸 때 해석할(escape) 지를 지정합니다. 가능한 값은 "`yes`"나 "`no`"입니다. 예를 들어, "`yes`"로 하면, 문자의 출력은 "`&gt`"가 아니라 `>`입니다.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 7.6.1, Generating Text with xsl:value-of

### Gecko 지원

위 경우를 빼고는 지원함.


preserve-space - XSLT

preserve-space
==============

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:preserve-space>` 요소는 공백을 보존하면 좋을 소스 문서의 요소를 정의합니다. 하나 이상의 요소가 있으면, 공백 문자로 이름을 구분하세요. 공백 보존하기가 기본 설정이므로 이 요소는 오직 `<xsl:strip-space>` 요소와 거꾸로 동작하기 위해 쓸 필요가 있습니다.

### 문법
```

<xsl:preserve-space elements=LIST-OF-ELEMENT-NAMES  />
```

### 필수 속성

`elements`

공백을 보존하면 좋을 요소를 지정합니다.

### 선택 속성

없음.

### 타입

최상위, `<xsl:stylesheet>`나 `<xsl:transform>`의 자식이어야 함.

### 정의

XSLT section 3.4, Whitespace Stripping

### Gecko 지원

지원함.


element - XSLT

element
=======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:element>` 요소는 출력 문서에 요소를 만듭니다.

### 문법
```

<xsl:element name=NAME namespace=URI use-attribute-sets=LIST-OF-NAMES >
  TEMPLATE
</xsl:template>
```

### 필수 속성

`name`

출력 요소에 바라는 이름을 지정합니다. 이름은 유효한 QName이어야 합니다.

### 선택 속성

`namespace`

출력 요소에 이름공간을 지정합니다.

`use-attribute-sets`

출력 요소에 쓸 이름 붙인 속성 집합을 나열합니다. 이름은 공백 문자로 구분해야 합니다.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 7.1.2, Creating Elements with xsl:element

### Gecko 지원

지원함.


with-param - XSLT

with-param
==========

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:with-param>` 요소는 템플릿에 건네는 매개변수 값을 지정합니다.

### 문법
```

<xsl:with-param name=NAME select=EXPRESSION>
  TEMPLATE
</xsl:with-param>
```

### 필수 속성

`name`

이 매개변수에 이름을 줍니다.

### 선택 속성

`select`

XPath 식을 거치는 매개변수 값을 정의합니다. 요소가 템플릿을 포함하면, 이 속성은 무시합니다.

### 타입

하위명령, 항상 `<xsl:apply-templates>`이나 `<xsl:call-template>` 요소 안에 나타남.

### 정의

XSLT section 11.6, Passing Parameters to Templates

### Gecko 지원

지원함.


copy-of - XSLT

copy-of
=======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:copy-of>` 요소는 select 속성이 출력 문서에 무엇을 지정하든지 (자손 노드를 포함하여) 깊게 복사(deep copy)합니다.

### 문법
```

<xsl:copy-of select=EXPRESSION />
```

### 필수 속성

`select`

복사할 대상을 지정하는 XPath 식을 씁니다.

### 선택 속성

없음.

### 타입

명령, 템플릿 안에 나타남.

### 정의

XSLT section 11.3, Using Values of Variables and Parameters with xsl:copy-of

### Gecko 지원

지원함.


choose - XSLT

choose
======

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:choose>` 요소는 많은 선택 가운데 하나를 정의합니다. 그리고 절차형 언어(procedural language)의 스위치 문처럼 동작합니다.

### 문법
```

<xsl:choose>
  <xsl:when>
  <xsl:otherwise> [optional]
</<xsl:choose>
```

### 필수 속성

없음.

### 선택 속성

없음.

### 타입

명령, 템플릿과 함께 나타남. 하나 이상의 `<xsl:when>` 요소를 포함하고 선택에 따라 마지막에 `<xsl:otherwise>` 요소를 포함합니다.

### 정의

XSLT section 9.2, Conditional Processing with xsl:choose

### Gecko 지원

지원함.


param - XSLT

param
=====

**XSLT/XPath 참고 문서**: XSLT 요소, XPath 함수, XPath 축

`<xsl:param>` 요소는 이름과 선택에 따라 기본값으로 매개변수를 설정합니다. 최상위 요소로 쓸 때, 매개변수는 전역입니다. `<xsl:template>` 요소 안에서 쓰면, 매개변수는 그 템플릿에 대해 지역입니다. 이 경우에 요소는 템플릿의 첫 자식 요소여야 합니다.

### 문법
```

<xsl:param name=NAME select=EXPRESSION>
  TEMPLATE
</xsl:param>
```

### 필수 속성

`name`

파라미터에 이름을 붙입니다. 이름은 QName이어야 합니다.

### 선택 속성

`select`

none으로 지정하면 기본값을 제공하는 XPath 식을 씁니다.

### 타입

명령, 최상위 요소나 템플릿 안에 나타날 수 있음.

### 정의

XSLT section 11, Variables and Parameters

### Gecko 지원

지원함.


The Netscape XSLT/XPath Reference - XSLT

The Netscape XSLT/XPath Reference
=================================

다음은 W3C의 XSLT 1.0 권고안뿐만 아니라 XPath 권고안의 알맞은 절로부터 알파벳순으로 주석을 단 요소, 축, 함수 목록입니다. XSLT 처리기 개발이 진행중이고 이 문서는 기능을 확장하는 대로 갱신할 것입니다.

### Elements

* xsl:apply-imports *(supported)*
* xsl:apply-templates *(supported)*
* xsl:attribute *(supported)*
* xsl:attribute-set *(supported)*
* xsl:call-template *(supported)*
* xsl:choose *(supported)*
* xsl:comment *(supported)*
* xsl:copy *(supported)*
* xsl:copy-of *(supported)*
* xsl:decimal-format *(supported)*
* xsl:element *(supported)*
* xsl:fallback *(not supported)*
* xsl:for-each *(supported)*
* xsl:if *(supported)*
* xsl:import *(mostly supported)*
* xsl:include *(supported)*
* xsl:key *(supported)*
* xsl:message *(supported)*
* xsl:namespace-alias *(not supported)*
* xsl:number *(partially supported)*
* xsl:otherwise *(supported)*
* xsl:output *(partially supported)*
* xsl:param *(supported)*
* xsl:preserve-space *(supported)*
* xsl:processing-instruction
* xsl:sort *(supported)*
* xsl:strip-space *(supported)*
* xsl:stylesheet *(partially supported)*
* xsl:template *(supported)*
* xsl:text *(partially supported)*
* xsl:transform *(supported)*
* xsl:value-of *(partially supported)*
* xsl:variable *(supported)*
* xsl:when *(supported)*
* xsl:with-param *(supported)*
### Axes

* ancestor
* ancestor-or-self
* attribute
* child
* descendant
* descendant-or-self
* following
* following-sibling
* namespace *(not supported)*
* parent
* preceding
* preceding-sibling
* self
### Functions

* boolean() *(supported)*
* ceiling() *(supported)*
* concat() *(supported)*
* contains() *(supported)*
* count() *(supported)*
* current() (en-US) *(supported)*
* document() *(supported)*
* element-available() *(supported)*
* false() *(supported)*
* floor() *(supported)*
* format-number() *(supported)*
* function-available() *(supported)*
* generate-id() *(supported)*
* id() *(partially supported)*
* key() *(supported)*
* lang() *(supported)*
* last() *(supported)*
* local-name() *(supported)*
* name() *(supported)*
* namespace-uri() *(supported)*
* normalize-space() *(supported)*
* not() *(supported)*
* number() *(supported)*
* position() *(supported)*
* round() *(supported)*
* starts-with() *(supported)*
* string() *(supported)*
* string-length() *(supported)*
* substring() *(supported)*
* substring-after() *(supported)*
* substring-before() *(supported)*
* sum() *(supported)*
* system-property() *(supported)*
* translate() *(supported)*
* true() *(supported)*
* unparsed-entity-url() *(not supported)*


프로그레시브 웹 앱 소개 - 프로그레시브 웹 앱

프로그레시브 웹 앱 소개
=============

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

이 문서는 프로그레시브 웹 앱(PWA)의 소개입니다. PWA가 무엇이고 일반 웹 앱에 어떤 이점을 가져다주는지 설명합니다.

프로그레시브 웹 앱이 무엇인가요?
------------------

PWA는 웹과 네이티브 앱의 기능 모두의 이점을 갖도록 수 많은 특정 기술과 표준 패턴을 사용해 개발된 웹 앱입니다.

예를 들어, 웹 앱은 발견이 쉽습니다 — 어플리케이션을 설치하는 것보다 웹사이트에 방문하는 것이 훨씬 쉽고 빠르며, 링크로 웹 앱을 공유할수도 있습니다.

반면에, 네이티브 앱은 운영체제와 보다 잘 통합되므로 더 부드러운 사용자 경험을 제공할 수 있습니다. 네이티브 앱은 설치할 수 있으므로 오프라인에서 동작하며, 사용자는 홈 화면의 아이콘을 탭하여 브라우저를 사용하여 이동하는 것보다 선호하는 앱에 더 쉽게 접근할 수 있습니다.

PWA는 이들과 동일한 이점을 즐길 수 있는 웹 앱을 생성하는 능력을 제공합니다.

완전히 새로운 개념은 아닙니다 — 이런 아이디어는 과거에 다양한 접근 방법으로 웹 플랫폼상에서 여러번 재검토되었습니다. 점진적인 향상과 반응형 디자인은 이미 우리가 모바일 친화적인 웹사이트를 구축할 수 있게 해주고 있습니다. 오프라인에서 동작하는 것과 앱을 설치하는 것은 몇 년 전 Firefox OS 생태계에서 이미 가능했었습니다.

하지만, PWA는 웹을 훌륭하게 만드는 이미 존재하는 어떤 기능도 제거하지 않은 상태로 이 모든 것 그리고 그 이상을 제공합니다.

앱을 PWA로 만드는 것은 무엇인가요?
---------------------

위에서 암시했듯이, PWA는 하나의 기술로 생성된 것이 아닙니다. 이는 일부 특정 패턴, API 및 다른 기능들을 포함하는 웹 앱을 구축하는 하나의 새로운 철학을 나타냅니다. 첫눈에 웹 앱이 PWA인이 아닌지 구분하기는 쉽지 않습니다. 앱이 특정 요구 사항을 만족하거나 다음 기능들이 구현되었을 때 PWA라고 볼 수 있습니다: 오프라인에서 동작, 설치가 가능, 쉬운 동기화, 푸시 알림, 등.

게다가, 앱의 완성도를 퍼센트로 측정하는 도구들도 있습니다. (Lighthouse가 현재 가장 유명합니다.) 다양한 기술적 이점을 구현함으로써, 앱을 더 점진적이게 만들 수 있고, 더 높은 Lighthouse 점수를 받을 수 있습니다. 하지만 이는 대략적인 지표일뿐입니다.

다음은 웹 앱을 PWA로 식별되기 위해 확인해야 하는 몇 가지 핵심 원칙입니다.

* 발견 가능, 따라서 컨텐츠를 검색 엔진을 통해 찾을 수 있습니다.
* 설치 가능, 따라서 기기의 홈 화면에서 사용할 수 있습니다.
* 연결 가능, 따라서 간단하게 URL을 전송해 공유할 수 있습니다.
* 네트워크 독립적, 따라서 오프라인이나 불안한 네트워크 연결에서 동작합니다.
* 점진적, 따라서 최신 브라우저의 모든 기능은 사용할 수 없지만 이전 브라우저의 기본 기능은 여전히 사용할 수 있습니다.
* 재 참여 가능(Re-engageable), 따라서 새 컨텐츠가 사용 가능할 때마다 알림을 보낼 수 있습니다.
* 반응형, 따라서 모든 기기의 화면이나 브라우저에서 사용할 수 있습니다 — 모바일 폰, 태블릿, 노트북, TV, 냉장고, 등.
* 안전, 따라서 여러분과 앱 사이의 연결이 여러분의 민감한 데이터에 접근하려는 모든 제3자로부터 안전합니다.
### 이 모든 것들을 할만한 가치가 있나요?

물론입니다! 비교적 적은 노력으로 PWA 핵심 기능들을 구현할 수 있으며, 그 이점은 거대합니다. 예를 들면:

* Service Workers 를 사용한 캐싱 덕분에 앱을 설치한 후에 로딩 시간이 줄어들어 소중한 데이터와 시간을 절약.
* 앱 업데이트가 있을 때 변경된 컨텐츠만 업데이트 할 수 있음. 반면, 네이티브 앱의 경우, 아주 작은 수정에도 사용자가 어플리케이션 전체를 다시 다운로드하도록 강제함.
* 네이티브 플랫폼에 보다 통합된 외관과 느낌 — 홈 화면의 앱 아이콘, 전체 화면으로 실행되는 앱, 등.
* 시스템 알림 및 푸시 메시지를 통한 사용자의 재 참여. 참여율이 높은 사용자와 더 나은 전환율을 이끌어 냄.

PWA 라우트를 시도하고 네이티브 앱 보다 더 향상된 웹 사이트 경험을 선택하여 측정 가능한 의미있는 이득을 본 회사들의 성공 스토리가 많습니다. PWA Stats 웹 사이트는 이러한 이점을 나타내는 많은 사례 연구들을 공유합니다.

가장 잘 알려진 성공 스토리는 아마 Flipkart Lite 일 것입니다 — 2015년에 프로그레시브 웹 앱으로 사이트를 재구축해 전환율을 70% 상승시킨 인도의 가장 큰 전자 상거래 사이트입니다. AliExpress PWA 역시 새로운 사용자에 대한 전환율을 104% 상승시키는 것으로 웹이나 네이티브 앱보다 훨씬 더 나은 결과를 보였습니다. 이윤 증가 및 PWA로 전환을 위해 상대적으로 적은 양의 작업을 놓고 봤을 때, 이점은 분명합니다.

더 많은 예제는 pwa.rocks 의 목록에서 확인하시기 바랍니다. hnpwa.com 페이지는 특별히 언급할 가치가 있습니다 — 여기에는 일반적인 TodoMVC 앱 대신 다양한 프론트엔드 프레임워크의 사용을 볼 수 있는 Hacker News 웹사이트의 구현 예제가 나열되어 있습니다.

심지어 PWABuilder 웹사이트를 사용해 PWA를 온라인에서 생성할수도 있습니다.

Service worker와 푸시에 관련된 정보는 최신 사이트에서 service worker를 사용하는 예제를 모아둔 Service Worker Cookbook을 확인하시기 바랍니다.

PWA 접근은 시도해볼만한 가치가 있으며, 여러분의 앱에서 동작하는지 스스로 확인해보시기 바랍니다.

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

앞서 언급했듯이, PWA는 하나의 API에 의존하지 않고, 가능한 최고의 웹 경험을 전달하기 위한 목표를 달성하기 위해 다양한 기술들을 사용합니다.

PWA를 위해 요구되는 핵심 요소는 service worker 지원입니다. 고맙게도 service worker는 현재 데스크탑 및 모바일의 모든 주요 브라우저에서 지원됩니다.

웹 앱 Manifest, 푸시, 알림, 홈 화면에 추가 (en-US) 기능과 같은 다른 기능들도 널리 지원되고 있습니다. 현재 Safari에서는 웹 앱 Manifest 및 홈 화면에 추가에 지원이 제한적이며 웹 푸시 알림은 지원하지 않습니다. 반면, 다른 주요 브라우저에서는 이 모든 기능들을 지원합니다.

이러한 API의 일부는 실험중이며 문서도 여전히 완성되지 않았지만, Flipkart 와 AliExpress와 같은 성공 스토리를 보면 여러분의 웹 앱에 PWA 기능의 일부를 시도하고 구현하는 것에 대해 이미 납득이 되었을것입니다.

무엇보다도 여러분은 프로그레시브 향상 규칙을 따라야 합니다 — 이러한 향상을 제공하는 기술들은 지원이 되는 경우에만 사용하고, 그렇지 않은 경우에도 여전히 기본 기능을 제공하시기 바랍니다. 이 방법으로 모든 사용자가 앱을 사용할 수 있지만, 최신 브라우저를 사용하는 사용자는 PWA 기능으로부터 더 많은 이점을 얻을 수 있습니다.

예시 어플리케이션
---------

이 문서 시리즈에서는 js13kGames 2017 대회의 A-Frame 카테고리에 제출된 게임에 대한 정보를 나열하는 아주 간단한 웹사이트의 소스코드를 살펴볼 것입니다. 여러분은 웹 사이트의 실제 컨텐츠가 무엇인지에 대해서는 생각할 필요가 없습니다 — 중요한 점은 여러분의 프로젝트에 PWA 기능을 어떻게 사용하는지를 배우는 것입니다.

온라인 버전은 mdn.github.io/pwa-examples/js13kpwa (소스 코드도 확인하세요)에서 확인하실 수 있으며, 다음 몇 가지 문서에서 자세히 설명할 것입니다.

이제, 우리의 예제 앱의 구조에 대해 살펴볼 이 시리즈의 두 번째 파트로 이동합시다.

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


알림과 푸시를 사용해 PWA를 재참여(re-engageable)가능하게 만드는 방법 - 프로그레시브 웹 앱

알림과 푸시를 사용해 PWA를 재참여(re-engageable)가능하게 만드는 방법
==============================================

* 이전  (en-US)
* Overview: Progressive (en-US)

앱을 오프라인에서 동작하도록 컨텐츠를 캐싱하는 능력은 훌륭한 기능입니다. 사용자가 홈 화면에 웹 앱을 설치하도록 허용하는 것은 더 좋습니다. 하지만, 사용자의 동작에 의존하는 대신 푸시 메시지와 알림을 사용해 새로운 컨텐츠가 있을때 이를 전달하여 사용자를 자동으로 다시 참여하도록 할 수 있습니다.

두 개의 API, 하나의 목적
----------------

Push API와 Notifications API는 두 개의 독립된 API이지만, 여러분의 앱에 재참여 기능을 제공하려고 할 때 함께 잘 동작합니다. Push는 클라이언트 사이드의 관여 없이 서버로부터 앱으로 새로운 컨텐츠를 전달하는데 사용되며, 이 작업은 앱의 service worker에 의해 처리됩니다. Notification은 service worker에 의해 사용자에게 새로운 정보를 보여주거나 무언가 업데이트 되었음을 알리는데 사용됩니다.

두 API는 service worker와 마찬가지로 브라우저 창의 바깥에서 동작하기때문에 앱의 페이지를 보고 있지 않거나 심지어 종료되었을 때도 업데이트 푸시를 보내거나 알림을 보여줄 수 있습니다.

Notifications
-------------

알림으로 시작해봅시다. 알림은 푸시 없이도 동작하지만, 푸시와 결합했을 때 매우 유용합니다. 먼저 독립적으로 보도록하겠습니다.

### 권한 요청

알림을 보여주려면 먼저 권한을 요청해야 합니다. 즉시 알림을 보여주는대신 사용자가 버튼을 클릭하여 팝업을 요청할 때 요청 팝업을 보여주는 것이 좋은 사용법입니다.

```js
var button = document.getElementById("notifications");
button.addEventListener("click", function (e) {
  Notification.requestPermission().then(function (result) {
    if (result === "granted") {
      randomNotification();
    }
  });
});
```

팝업은 운영체제가 가진 알림 서비스를 사용해 보여집니다.

![Notification of js13kPWA.](/ko/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Re-engageable_Notifications_Push/js13kpwa-notification.png)

사용자가 알림 수신을 확인하면 앱이 알림을 보여줄 수 있습니다. 사용자는 기본, 승인 또는 거절을 선택할 수 있습니다. 기본 옵션은 사용자가 선택할 수 없을 때 사용되며, 다른 두 옵션은 사용자가 예 또는 아니오를 선택했을 때 사용됩니다.

승인이 되면, 권한은 알림과 푸시 모두에 대해 동작합니다.

### 알림 생성

예시 앱은 사용가능한 데이터를 알림으로 생성합니다. 게임은 무작위로 선택되며, 선택된 것은 게임의 이름을 title로, 제작자를 body로, 이미지를 아이콘으로 보여주는 컨텐츠를 알림으로 제공합니다.

```js
function randomNotification() {
  var randomItem = Math.floor(Math.random() \* games.length);
  var notifTitle = games[randomItem].name;
  var notifBody = "Created by " + games[randomItem].author + ".";
  var notifImg = "data/img/" + games[randomItem].slug + ".jpg";
  var options = {
    body: notifBody,
    icon: notifImg,
  };
  var notif = new Notification(notifTitle, options);
  setTimeout(randomNotification, 30000);
}
```

새로운 무작위 알림은 사용자가 너무 귀찮아 비활성화 하기 전까지는 매 30초마다 생성됩니다. (실제 앱에서는 알림이 너무 잦아선 안되며 더 유용해야합니다.) Notifications API의 이점은 운영체제의 알림 기능을 사용한다는 것입니다. 이는 사용자가 웹 앱을 보고있지않더라도 알림을 보여줄 수 있으며, 알림이 네이티브 앱에서 표시하는 것과 유사하다는 것을 의미합니다.

Push
----

푸시는 알림보다 더 복잡합니다. 우리는 앱으로 데이터를 다시 전송해줄 서버를 구독해야합니다. 앱의 Service Worker는 푸시 서버로부터 데이터를 수신하며 알림 시스템 또는 원하는 경우 다른 메커니즘을 사용해 이를 보여줄 수 있습니다.

이 기술은 여전히 아주 초기 단계에 있습니다. 몇몇 동작하는 예제들은 Google Cloude Messaging 플랫폼을 사용하지만, VAPID(자발적 어플리케이션 식별, Voluntary Application Identification)를 지원하도록 재작성되어 앱을 위한 부가적인 보안 계층을 제공합니다. Service Workers Cookbook examples를 확인하고, Firebase를 사용하는 푸시 메시징 서버를 설정하거나, 여러분만의 서버(예제에서는 Node.js를 사용)를 구축해보시기 바랍니다.

앞서 언급듯이, 푸시 알림을 수신하려면 service worker가 있어야 합니다. 이를 위한 기본적인 내용은 Service worker를 사용해 PWA를 오프라인에서 동작하게 만들기 (en-US) 문서에서 이미 설명했습니다. Service worker 안에서 푸시 서비스 구독 메커니즘이 생성됩니다.

```js
registration.pushManager.getSubscription().then(/\* ... \*/);
```

사용자가 구독을 하기 시작하면, 서버로부터 푸시 알림을 받을 수 있습니다.

서버사이드에서는 보안적인 이유로 전체 프로세스를 공개키와 비공개키를 사용하여 암호화해야 합니다. 모든 사람들이 앱을 사용하여 안전하지 않은 푸시 메시지를 보내도록 허용하는 것은 끔찍할 것입니다. 서버는 사용자가 구독했을 때 받은 모든 정보를 저장하므로 이 후 필요할 때 메시지를 보낼 수 있습니다.

푸시 메시지를 수신하려면, Service Worker 파일에서 `push`이벤트를 사용하면됩니다.

```js
self.addEventListener("push", function (e) {
  /\* ... \*/
});
```

데이터는 반환되어 알림으로 사용자에게 즉시 보여집니다. 예를 들어, 이는 사용자에게 무언가를 다시 알려주거나, 앱에서 사용 가능한 새로운 컨텐츠에 대해 알려주는데 사용할 수 있습니다.

### 푸시 예제

푸시는 동작을 위해 서버 파트가 필요하므로, 정적인 파일의 호스팅만 제공하는 GitHub Pages에 호스팅된 js13kPWA 예제를 포함 할 수 없습니다. 이는 Service Worker Cookbook에 모두 설명되어 있습니다. Push Payload 데모를 확인하시기 바랍니다.

이 데모는 세 파일을 포함하고 있습니다.

* index.js, 앱의 소스 코드를 포함합니다
* server.js, 서버 파트(Node.js로 작성됨)를 포함합니다
* service-worker.js, Service Worker 관련 코드를 포함합니다.

이 모든 것들에 대해 확인해봅시다

#### index.js

`index.js` 파일은 service worker를 등록하는 것으로 시작합니다.

```js
navigator.serviceWorker
  .register("service-worker.js")
  .then(function (registration) {
    return registration.pushManager
      .getSubscription()
      .then(async function (subscription) {
        // registration part
      });
  })
  .then(function (subscription) {
    // subscription part
  });
```

js13kPWA 데모에서 봤던 service worker보다 조금 더 복잡합니다. 이 특정 케이스에서는, 등록한 후에 등록 객체를 사용해 구독하며, 그 후 구독 객체를 사용해 전체 프로세스를 완료합니다.

등록 파트의 코드는 다음과 같습니다.

```js
if (subscription) {
  return subscription;
}
```

사용자가 이미 구독했을경우, 구독 객체를 반환하며 구독 파트로 이동합니다. 그렇지 않을 경우 새로운 구독을 초기화합니다.

```js
const response = await fetch("./vapidPublicKey");
const vapidPublicKey = await response.text();
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
```

앱은 서버의 공개 키를 패치하고 응답을 텍스트로 변환합니다. 그 후 Uint8Array(Chrome 지원을 위해)로 변환이 필요합니다. VAPID 키에 대한 자세한 내용은 Sending VAPID identified WebPush Notifications via Mozilla's Push Service 블로그 포스트를 읽어보시기 바랍니다.

앱은 이제 새로운 사용자를 구독하기 위해 `PushManager` (en-US)를 사용합니다. 두 옵션이 `PushManager.subscribe()` (en-US) 메소드로 전달됩니다. 첫 번째는 `userVisibleOnly: true`이며 사용자에게 전송되는 모든 알림이 보여진다는 것을 의미하며, 두 번째 것은 `applicationServerKey`이며 성공적으로 획득하고 변환된 VAPID 키를 포함합니다.

```js
return registration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: convertedVapidKey,
});
```

이제 구독 파트로 이동해봅시다. 앱은 Fetch를 사용해 먼저 서버로 JSON으로 된 구독 상세 정보를 전송합니다.

```js
fetch("./register", {
  method: "post",
  headers: {
    "Content-type": "application/json",
  },
  body: JSON.stringify({
    subscription: subscription,
  }),
});
```

그 다음 *구독* 버튼의 `GlobalEventHandlers.onclick`이 정의됩니다.

```js
document.getElementById("doIt").onclick = function () {
  const payload = document.getElementById("notification-payload").value;
  const delay = document.getElementById("notification-delay").value;
  const ttl = document.getElementById("notification-ttl").value;

  fetch("./sendNotification", {
    method: "post",
    headers: {
      "Content-type": "application/json",
    },
    body: JSON.stringify({
      subscription: subscription,
      payload: payload,
      delay: delay,
      ttl: ttl,
    }),
  });
};
```

버튼이 클릭되면, `fetch`는 제공된 파라미터를 사용해 서버로 알림을 전송합니다. `payload`는 알림에 표시될 텍스트이고, `delay`는 알림이 보여질 때 까지의 지연 시간을 정의하며, `ttl`은 지정된 시간(초 단위로도 정의됨)동안 서버에서 알림을 사용할 수 있게하는 time-to-live 설정입니다.

이제, 다음 JavaScript 파일로 넘어갑니다.

#### server.js

서버 파트는 Node.js로 작성되었으며 어딘가 적합한 곳에 호스팅되어야 합니다. 이는 완전히 다른 문서의 주제입니다. 여기에서는 높은 수준의 개요만 제공합니다.

web-push 모듈은 VAPID 키를 설정하기 위해 사용되며, 존재하지 않을 경우 선택적으로 생성합니다.

```js
const webPush = require("web-push");

if (!process.env.VAPID\_PUBLIC\_KEY || !process.env.VAPID\_PRIVATE\_KEY) {
  console.log(
    "You must set the VAPID\_PUBLIC\_KEY and VAPID\_PRIVATE\_KEY " +
      "environment variables. You can use the following ones:",
  );
  console.log(webPush.generateVAPIDKeys());
  return;
}

webPush.setVapidDetails(
  "https://github.com/mdn/serviceworker-cookbook/",
  process.env.VAPID\_PUBLIC\_KEY,
  process.env.VAPID\_PRIVATE\_KEY,
);
```

그 다음, 모듈은 앱이 처리해야할 모든 라우트(VAPID 공개 키 얻기, 등록 후 알림 보내기)를 정의하고 내보냅니다. `index.js` 파일에서 사용중인 `payload`, `delay`, `ttl` 변수를 볼 수 있습니다.

```js
module.exports = function (app, route) {
  app.get(route + "vapidPublicKey", function (req, res) {
    res.send(process.env.VAPID\_PUBLIC\_KEY);
  });

  app.post(route + "register", function (req, res) {
    res.sendStatus(201);
  });

  app.post(route + "sendNotification", function (req, res) {
    const subscription = req.body.subscription;
    const payload = req.body.payload;
    const options = {
      TTL: req.body.ttl,
    };

    setTimeout(function () {
      webPush
        .sendNotification(subscription, payload, options)
        .then(function () {
          res.sendStatus(201);
        })
        .catch(function (error) {
          console.log(error);
          res.sendStatus(500);
        });
    }, req.body.delay \* 1000);
  });
};
```

#### service-worker.js

마지막으로 살펴볼 파일은 service worker입니다.

```js
self.addEventListener("push", function (event) {
  const payload = event.data ? event.data.text() : "no payload";
  event.waitUntil(
    self.registration.showNotification("ServiceWorker Cookbook", {
      body: payload,
    }),
  );
});
```

이 모든 것은 `push` 이벤트에 리스너를 추가하고, 데이터로부터 받은 텍스트로 구성된 payload 변수를 생성한 후(또는 데이터가 비어있을 경우 사용할 문자열을 생성), 사용자에게 보여줄 알림을 보여줄 때까지 기다립니다.

Service Worker Cookbook 예제의 나머지 부분의 동작 방법도 자유롭게 살펴보시기 바랍니다. 전체 소스 코드는 GitHub에서 사용 가능합니다. 일반적인 사용과 웹 푸시, 캐싱 전략, 성능, 오프라인 동작 등을 보여주는 동작 예제가 많이 있습니다.

결론
--

이것이 튜토리얼 시리즈의 전부입니다. js13kPWA 예제 앱의 소스 코드를 살펴봤으며 소개 (en-US), PWA 구조 (en-US), Service Worker를 사용한 오프라인 기능 (en-US), 설치 가능한 PWA (en-US) 그리고 마지막으로 알림을 포함해 프로그레시브 웹 앱의 기능의 사용에 대해 배웠습니다. 또한 Service Worker Cookbook의 도움으로 푸시에 대해서도 설명했습니다.

코드를 실험해보시고, 여러분의 앱을 PWA 기능으로 개선하거나, 완전히 새로운 무언가를 구축해 보세요. PWA는 일반 웹 앱에 비해 큰 이점을 제공합니다.

* 이전  (en-US)
* Overview: Progressive (en-US)


Service worker를 사용해 PWA를 오프라인에서 동작하게 만들기 - 프로그레시브 웹 앱

Service worker를 사용해 PWA를 오프라인에서 동작하게 만들기
========================================

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

우리는 js13kPWA의 구조와 기본적인 shell을 만들고 실행하는 것에 대해 살펴보았습니다. 이제 Service Worker를 사용해 오프라인 기능을 구현하는 방법에 대해 살펴봅시다. 이 문서에서는 js13kPWA 예제(소스 코드도 있습니다)에서 어떻게 사용되었는지와 오프라인 기능을 추가하는 방법을 살펴봅니다.

Service worker 설명
-----------------

Service Worker는 브라우저와 네트워크 사이의 가상 프록시입니다. 이는 프론트엔드 개발자들이 수년간 어려움을 겪었던 문제들을 결국 해결하였습니다(특히 웹 사이트의 자원을 적절히 캐싱하는 방법과, 사용자의 기기가 오프라인일 때 이를 사용할 수 있도록 하는 것 등).

이는 페이지의 메인 JavaScript 코드와 독립된 스레드에서 실행되며, DOM 구조에 대한 어떠한 접근도 갖지 않습니다. 이는 전통적인 웹 프로그래밍과 다른 접근법을 소개합니다. API는 비차단형(non-blocking)이며 여러 컨텍스트 사이에 커뮤니케이션을 주고 받을 수 있습니다. 여러분은 Service Worker에 어떤 작업을 전달할 수 있으며, Promise 기반 접근법을 사용해 결과가 준비될때마다 전달받을 수 있습니다.

Service Worker는 "단지" 오프라인 기능을 제공하는 것 이상으로 알림 처리, 독립된 스레드에서의 복잡한 계산 등 많은 것들을 할 수 있습니다. Service worker는 네트워크 요청을 제어하고 수정하며, 캐시로부터 반환된 커스텀 응답을 제공하거나 응답을 완전히 가공할 수도 있으므로 매우 강력합니다.

### 보안

Service Worker는 매우 강력하기때문에 안전한 컨텍스트(HTTPS를 의미)에서만 실행됩니다. 코드를 상용으로 푸시하기전에 먼저 테스트하길 원하신다면, localhost에서 테스트하거나 GitHub Pages를 설정하면 됩니다. 둘 다 HTTPS를 지원합니다.

오프라인 우선
-------

"오프라인 우선" — 또는 "캐시 우선" — 패턴은 사용자에게 컨텐츠를 제공하는 가장 유명한 전략입니다. 리소스가 캐싱되었고 오프라인 사용이 가능한 경우, 서버로부터 다운로드를 시도하기전에 캐시를 먼저 반환합니다. 캐시에 없는 경우, 다음 사용을 위해 다운로드하고 캐싱합니다.

PWA의 "점진적"
----------

점진적인 향상으로써 제대로 구현이 되면, service worker는 오프라인 지원을 제공하여 API를 지원하는 최신 브라우저를 사용하는 사용자에게 유용하지만, 구형 브라우저를 사용하는 사람들에게도 사이트 사용에 아무런 문제가 없습니다.

js13kPWA 앱의 Service worker
--------------------------

이론은 충분합니다. 소스 코드를 봅시다!

### Service Worker 등록

app.js 파일에서 새로운 Service Worker를 등록하는 코드를 살펴보는 것으로 시작할 것입니다.

```js
if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/pwa-examples/js13kpwa/sw.js");
}
```

브라우저에서 Service worker API를 지원한다면, `ServiceWorkerContainer.register()` (en-US) 메소드를 사용해 사이트에대해 등록됩니다. 컨텐츠는 sw.js 파일안에 있으며 등록이 성공한 후에 실행됩니다. 이것이 app.js 파일안에 있는 Service Worker 코드의 유일한 부분입니다. Service Worker에 대한 다른 모든 것들은 sw.js 파일에 작성되어 있습니다.

### Service Worker의 수명 주기

등록이 완료되면, sw.js 파일은 자동으로 다운로드된 후 설치되고 마지막으로 활성화됩니다.

#### 설치

API는 우리가 관심있는 주요 이벤트에 대한 이벤트 리스너를 추가할 수 있게 해줍니다. 첫 번째 것은 `install` 이벤트 입니다.

```js
self.addEventListener("install", function (e) {
  console.log("[Service Worker] Install");
});
```

`install` 리스너에서 캐시를 초기화하고 오프라인 사용을 위한 파일들을 추가할 수 있습니다. js13kPWA 앱도 정확히 그런 작업을 합니다.

먼저, 캐시 이름을 저장할 변수를 생성하고, app shell 파일들을 하나의 배열에 나열합니다.

```js
var cacheName = "js13kPWA-v1";
var appShellFiles = [
  "/pwa-examples/js13kpwa/",
  "/pwa-examples/js13kpwa/index.html",
  "/pwa-examples/js13kpwa/app.js",
  "/pwa-examples/js13kpwa/style.css",
  "/pwa-examples/js13kpwa/fonts/graduate.eot",
  "/pwa-examples/js13kpwa/fonts/graduate.ttf",
  "/pwa-examples/js13kpwa/fonts/graduate.woff",
  "/pwa-examples/js13kpwa/favicon.ico",
  "/pwa-examples/js13kpwa/img/js13kgames.png",
  "/pwa-examples/js13kpwa/img/bg.png",
  "/pwa-examples/js13kpwa/icons/icon-32.png",
  "/pwa-examples/js13kpwa/icons/icon-64.png",
  "/pwa-examples/js13kpwa/icons/icon-96.png",
  "/pwa-examples/js13kpwa/icons/icon-128.png",
  "/pwa-examples/js13kpwa/icons/icon-168.png",
  "/pwa-examples/js13kpwa/icons/icon-192.png",
  "/pwa-examples/js13kpwa/icons/icon-256.png",
  "/pwa-examples/js13kpwa/icons/icon-512.png",
];
```

다음으로, data/games.js 파일의 컨텐츠와 함께 로딩될 이미지 링크가 두 번째 배열에 생성됩니다. 그런 다음, `Array.prototype.concat()` 함수를 사용해 두 배열을 병합합니다.

```js
var gamesImages = [];
for (var i = 0; i < games.length; i++) {
  gamesImages.push("data/img/" + games[i].slug + ".jpg");
}
var contentToCache = appShellFiles.concat(gamesImages);
```

그러면 `install` 이벤트 자체를 관리할 수 있게 됩니다.

```js
self.addEventListener("install", function (e) {
  console.log("[Service Worker] Install");
  e.waitUntil(
    caches.open(cacheName).then(function (cache) {
      console.log("[Service Worker] Caching all: app shell and content");
      return cache.addAll(contentToCache);
    }),
  );
});
```

여기서 두 가지에 대한 설명이 필요합니다: `ExtendableEvent.waitUntil` (en-US)이 무엇을 하는지, 그리고 `Caches` (en-US) 객체가 무엇인지.

Service worker는 `waitUntil` 안의 코드가 실행되기전까지 설치되지 않습니다. 이는 promise를 반환합니다. 설치에 약간의 시간이 걸릴 수 있으므로 완료될 때까지 기다려야하기 때문에 이 접근법이 필요합니다.

`Caches` 는 데이터를 저장할 수 있도록 주어진 Service Worker의 범위 내에서 사용할 수 있는 특별한 객체입니다. 웹 저장소는 동기적이므로 웹 저장소로의 저장은 동작하지 않을 것입니다. Service Worker는 Cache API를 대신 사용합니다.

여기에 주어진 이름을 갖는 캐시를 열고 캐시에서 사용할 앱의 모든 파일을 추가하여 다음 로딩에서 사용할 수 있게됩니다(요청 URL로 식별됨).

#### 활성화

`install`과 같은 방식으로 사용되는 `activate` 이벤트도 있습니다. 이 이벤트는 일반적으로 더 이상 필요하지 않은 파일을 제거하고 앱이 끝난 후 정리하는데 사용됩니다. 우리 앱에서는 사용하지 않으므로 생략하겠습니다.

### 패치 응답

 처리를 위한 `fetch` 이벤트도 있습니다. 이는 앱으로부터 HTTP 요청이 출발할 때 마다 발생합니다. 이는 요청을 가로채 커스텀 응답으로 응답할 수 있어 매우 유용합니다.
 다음은 간단한 사용 예시입니다.

```js
self.addEventListener("fetch", function (e) {
  console.log("[Service Worker] Fetched resource " + e.request.url);
});
```

응답은 파일 요청, 캐시된 사본, 또는 특정 작업을 수행하는 JavaScript 코드 조각 등 원하는 어떠한것도 될 수 있습니다. 가능성은 무한합니다.

예제 앱에서 우리는 리소스가 실제로 캐시에 있는한 네트워크 대신 캐시로부터 컨텐츠를 제공합니다. 앱이 온라인이든 오프라인이든간에 이렇게 수행합니다. 파일이 캐시에 없을 경우, 이를 제공하기 전에 먼저 캐시에 추가합니다.

```js
self.addEventListener("fetch", function (e) {
  e.respondWith(
    caches.match(e.request).then(function (r) {
      console.log("[Service Worker] Fetching resource: " + e.request.url);
      return (
        r ||
        fetch(e.request).then(function (response) {
          return caches.open(cacheName).then(function (cache) {
            console.log(
              "[Service Worker] Caching new resource: " + e.request.url,
            );
            cache.put(e.request, response.clone());
            return response;
          });
        })
      );
    }),
  );
});
```

여기에서 우리는 리소스를 찾고 존재할 경우 응답을 반환하는 함수로 패치 이벤트에 응답합니다. 응답이 없을 경우 다른 패치 요청을 사용해 네트워크로부터 패치한 후 캐시에 응답을 저장하여 다음 요청에서 사용할 수 있도록 합니다.

`FetchEvent.respondWith` (en-US) 메소드가 제어를 대신합니다. 이는 앱과 네트워크 사이의 프록시 서버로서 기능하는 부분입니다. 이는 Service Worker에 의해 준비되고, 캐시로부터 가져와, 필요한 경우 수정하여 모든 요청에 대해 우리가 원하는 응답을 할 수 있게 해줍니다.

이게 다입니다! 우리 앱은 설치에서 자원을 캐싱하고 캐시로부터 이를 패치하여 전달함으로 사용자가 오프라인인 경우에도 동작합니다. 새로운 컨텐츠가 추가되면 역시 캐싱합니다.

업데이트
----

다뤄야 할 하나가 더 남았습니다. 새 자원을 포함하는 앱의 새 버전이 사용가능할 때 어떻게 Service Worker를 업그레이드하나요? 캐시 이름안의 버전 넘버가 핵심입니다.

```js
var cacheName = "js13kPWA-v1";
```

v2로 업데이트했을 때, 새 캐시에 모든 파일(새 파일들을 포함)을 추가할 수 있습니다.

```js
contentToCache.push("/pwa-examples/js13kpwa/icons/icon-32.png");

// ...

self.addEventListener("install", function (e) {
  e.waitUntil(
    caches.open("js13kPWA-v2").then(function (cache) {
      return cache.addAll(contentToCache);
    }),
  );
});
```

새 service worker가 백그라운드에서 설치되고 이전의 것(v1)이 사용하는 페이지가 없을 때까지 올바르게 동작합니다. 새로운 Service Worker는 그 후 활성화되고 이전의 것으로부터 페이지의 관리를 넘겨받습니다.

캐시 지우기
------

생략했던 `activate` 이벤트를 기억하시나요? 더 이상 필요하지 않은 오래된 캐시를 지우는데 사용할 수 있습니다.

```js
self.addEventListener("activate", function (e) {
  e.waitUntil(
    caches.keys().then(function (keyList) {
      return Promise.all(
        keyList.map(function (key) {
          if (cacheName.indexOf(key) === -1) {
            return caches.delete(key);
          }
        }),
      );
    }),
  );
});
```

이는 캐시에 우리가 필요한 파일만 있도록 보장하여, 불필요한 파일을 남기지 않게 됩니다. 브라우저에서 사용가능한 캐시 공간은 제한적 (en-US)이므로 이를 지우는 것은 우리 스스로를 위한 좋은 아이디어입니다.

다른 유즈 케이스
---------

캐시로부터 파일들을 전달하는 것은 Service Worker가 제공하는 유일한 기능이 아닙니다. 복잡한 계산을 해야하는 경우, 메인 스레드로부터 이를 분리하여 worker에서 수행하도록 하고 결과가 나오는대로 받을 수 있습니다. 성능 측면에서 볼 때, 지금 당장 필요하지는 않지만 가까운 미래에 필요할 수도 있는 리소스를 미리 패치하여 실제로 그 리소스들을 필요로할 때 앱이 더 빨라집니다.

요약
--

이 문서에서는 service worker를 사용해 PWA가 오프라인에서 동작하도록 만드는 방법에 대해 간략히 살펴보았습니다. Service Worker API의 개념과 사용 방법에 대한 더 자세한 내용을 배우시려면 우리의 추가 문서를 확인하시기 바랍니다.

Service Worker는 푸시 알림을 처리할 때에도 사용됩니다. 이는 이어지는 문서에서 설명할 것입니다.

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


PWA를 설치가능하게 만드는 방법 - 프로그레시브 웹 앱

PWA를 설치가능하게 만드는 방법
==================

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

이전 문서에서는 service worker의 도움으로 js13kPWA 을 오프라인에서 동작하는 방법에 대해 알아보았습니다. 그런데 우리는 더 나아가 모바일 브라우저를 지원하는 웹 앱을 네이티브 앱처럼 설치할 수 있게 할수도 있습니다. 이 문서에서는 웹 manifest를 사용해 홈 화면에 추가라고 불리는 기능을 구현하는 방법에 대해 설명합니다.

이러한 기술들은 앱을 URL을 수동으로 브라우저에 입력하는 대신 기기의 홈 화면에서 바로 실행할 수 있도록 해줍니다. 여러분의 웹 앱을 네이티브 어플리케이션 바로 옆 가장 좋은 자리에 놓을 수 있습니다. 따라서 접근이 더 쉽고, 브라우저 주변 기능이 없는 전체 화면에서 실행되도록 지정하여 더욱 더 네이티브 앱과 같은 느낌을 줄 수 있습니다.

요구 사항
-----

웹 사이트를 설치가능하게 하려면 다음과 같은 것들이 필요합니다.

* 올바른 값들로 채워진 웹 manifest
* 보안 (HTTPS) 도메인에서 제공되는 웹 사이트
* 기기에서 앱을 나타낼 아이콘
* 앱을 오프라인에서 동작하게 하기 위한 service worker 등록(현재 Android용 Chrome에서만 요구됩니다)
### manifest 파일

핵심 요소는 JSON 형식으로 웹 사이트에 대한 모든 정보를 나열한 웹 manifest 파일입니다.

파일은 일반적으로 웹 앱의 루트 폴더에 위치합니다. 앱의 title, 모바일 OS에서 앱을 나타내는데 사용(예를 들어, 홈 화면 아이콘)되는 다른 크기의 아이콘들의 경로, 로딩 또는 스플래시 화면에서 사용할 배경 색상과 같은 유용한 정보들을 포함합니다. 이는 브라우저가 웹 앱을 설치할 때 그리고 홈 화면에서 웹 앱을 적절히 표현하기 위해 필요한 정보입니다.

js13kPWA 웹 앱의 `js13kpwa.webmanifest` 파일은 코드의 다음 라인을 통해 `index.html` 파일의 `<head>` 섹션에 포함됩니다.

```html
<link rel="manifest" href="js13kpwa.webmanifest" />
```

**참고:** 과거에 manifest로 사용되던 몇 가지 흔한 확장자들이 있습니다: `manifest.webapp` 은 Firefox OS 웹 manifest로 유명하며, 많은 사람들이 JSON 구조로 내용이 구성된 `manifest.json`을 사용합니다. 하지만, `.webmanifest` 확장자는 W3C manifest 명세에 명시적으로 언급되고 있으므로 이를 그대로 사용하도록 하겠습니다.

파일의 내용은 다음과 같습니다.

```json
{
  "name": "js13kGames Progressive Web App",
  "short\_name": "js13kPWA",
  "description": "Progressive Web App that lists games submitted to the A-Frame category in the js13kGames 2017 competition.",
  "icons": [
    {
      "src": "icons/icon-32.png",
      "sizes": "32x32",
      "type": "image/png"
    },
    // ...
    {
      "src": "icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start\_url": "/pwa-examples/js13kpwa/index.html",
  "display": "fullscreen",
  "theme\_color": "#B12A34",
  "background\_color": "#B12A34"
}
```

항목은 대부분은 스스로를 설명하고있지만, 문서를 분석하고 자세한 내용에 대해 설명해드리겠습니다.

* `name`: 웹 앱의 이름입니다.
* `short_name`: 홈 화면에 표시할 약식 이름입니다.
* `description`: 앱이 무엇을 하는지 설명하는 간략한 문장입니다.
* `icons`: 아이콘들의 정보(URL, 크기, 타입)입니다. 사용자의 기기에 적합한 것을 선택할 수 있도록 여러 개를 추가하시기 바랍니다.
* `start_url`: 앱이 시작할 때 실행할 초기 문서입니다.
* `display`: 앱을 표시하는 방식입니다(전체 화면, 독립형(standalone), 최소 UI, 또는 브라우저).
* `theme_color`: 운영 체제에 의해 사용될 UI를 위한 주요 색상입니다.
* `background_color`: 스플래시 화면과 설치하는 동안 사용될 배경 색상입니다.

웹 manifest를 위한 최소 요구 사항은 `name`과 적어도 하나(`src`, `size`, `type`을 포함)의 아이콘입니다. `description`, `short_name`, `start_url`은 권장사항입니다. 위에서 나열한 항목 외 더 많은 항목들이 있습니다. Web App Manifest 레퍼런스에서 자세한 내용에 대해 확인하시기 바랍니다.

홈 화면에 추가
--------

"홈 화면에 추가"(또는 간단히 a2hs)는 모바일 브라우저에서 구현된 기능으로, 앱의 웹 manifest에서 찾은 정보를 사용해 아이콘과 이름 정보로 기기의 홈 화면에서 앱을 나타냅니다. 이는 앱이 위에서 설명한 모든 필수 요구조건을 만족할때만 동작합니다.

사용자가 모바일 브라우저를 지원하는 PWA에 방문할 때, PWA로써 앱 설치를 가능하게하는 배너가 나타나야합니다.

![Add to Home screen popup of js13kPWA.](/ko/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-icon.png)

사용자가 이 배너를 클릭하면 설치 배너가 나타납니다. 배너는 브라우저에의해 자동으로 생성되며, manifest 파일의 정보(프롬프트에 보여질 이름, 아이콘)를 기반으로합니다.

![Install banner of js13kPWA.](/ko/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-banner.png)

사용자가 버튼을 클릭하면 앱이 어떻게 표시될지를 보여주며, 사용자에게 정말 앱 추가를 원하는지 선택하도록 하는 마지막 단계가 있습니다.

![Add to Home screen popup of js13kPWA.](/ko/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-add.png)

확인을 하면 앱이 홈 화면에 설치됩니다.

![](/ko/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-installed.png)

그 후, 즉시 아이콘을 사용해 이를 실행하여 시작할 수 있습니다. PWA가 가끔(여러분이 사용하는 브라우저나 운영체제에 따라) 아이콘의 우측 하단에 작은 브라우저 이미지가 있어 사용자에게 웹 특성에 대한 정보를 줍니다.

### 스플래시 화면

일부 브라우저에서, PWA가 실행될 때 보여지는 스플래시 화면 역시 manifest의 정보로부터 생성됩니다.

![](/ko/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-splash.png)

아이콘과 테마 그리고 배경 색상은 이 화면을 생성하기 위해 사용됩니다.

요약
--

이 문서에서는 웹 manifest와 홈 화면에 추가를 사용해 PWA를 설치가능하게 하는 방법에 대해 배웠습니다.

홈 화면에 추가에 대한 자세한 내용은 홈 화면에 추가 가이드 (en-US)를 읽어보시기 바랍니다. 브라우저 지원은 현재 Android 용 Firefox 58+, 모바일 Chrome 및 Android 웹 뷰 31+, Android 32+ 용 Opera로 제한되어 있지만 가까운 장래에 개선 될 것입니다.

이제 PWA 퍼즐의 마지막 조각(푸시 알림을 통한 재참여)으로 이동해봅시다.

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