1. 소개
이 명세서는 웹 브라우저를 위한 폰트 열거 API를 설명하며, 사용자가 전체 시스템 폰트 세트에 대한 접근을 허용할 수 있도록 선택적으로 제공합니다. 각 폰트에 대해 SFNT [SFNT] 컨테이너 또는 동등한 것에 바이트 단위(저수준) 접근을 통해 전체 폰트 데이터를 제공합니다.
웹 개발자는 역사적으로 페이지 콘텐츠의 스타일링에 사용할 수 있는 로컬 폰트에 대해 휴리스틱 이상의 정보를 얻기 어려웠습니다. 웹 개발자는 종종 복잡한 font-family
값 목록을 CSS에 포함시켜 휴리스틱 방식으로 폰트 폴백을 제어합니다. 좋은 폰트 폴백을 생성하는 작업은 디자이너에게 매우 복잡하기 때문에, 가능한 로컬 매치를 "눈대중"으로 찾기 위한 도구가
만들어지기도 했습니다.
폰트 열거는 다음에 도움이 됩니다:
-
사용자가 생성한 콘텐츠의 스타일링 옵션 개선
-
기존 콘텐츠에서 선언된 폰트를 매칭
웹은 텍스트 중심 매체로 시작되었으며 사용자 에이전트가 매우 높은 품질의 타이포그래피 지원을 제공하지만, 일부 웹 기반 애플리케이션에는 몇 가지 한계가 있습니다:
-
시스템 폰트 엔진(및 브라우저 스택)이 특정 글리프를 다르게 표시할 수 있습니다. 이러한 차이는 일반적으로 기본 OS와의 일관성을 유지하기 위해 필요(웹 콘텐츠가 "이상하게" 보이지 않게끔)하며, 여러 플랫폼에 걸친 애플리케이션의 일관성(예: 픽셀 정확한 레이아웃 및 렌더링 필요 시)을 저하시킵니다.
-
디자인 도구는 플랫폼에 독립적으로 자체적으로 레이아웃을 수행하거나, 글리프 모양에 벡터 필터나 변형을 적용하는 등의 작업을 위해 폰트 데이터 접근이 필요합니다.
-
개발자는 메트릭이나 테마 기반의 폰트 선택 UI 또는 메트릭 및 기타 데이터를 바탕으로 하는 자동 폰트 매칭을 제공할 수 있으며, 이는 폰트 데이터에 대한 직접 접근을 필요로 합니다.
-
일부 폰트는 웹상에서 제공되는 라이선스가 아닐 수 있습니다. 예를 들어, Linotype은 일부 폰트의 라이선스를 데스크톱 용도로만 제공합니다.
전문적인 품질의 디자인 및 그래픽 도구는 전통적으로 웹에서 제공하기가 어려웠습니다. 이런 도구들은 광범위한 타이포그래피 기능과 제어를 핵심으로 제공합니다.
이 API는 브라우저의 레이아웃 및 래스터화 엔진이 텍스트를 그릴 때 사용하는 것과 동일한 기본 폰트 데이터를 이러한 도구에 제공합니다. 예시로는 OpenType glyf 테이블(글리프 벡터 데이터), GPOS 테이블(글리프 배치), GSUB 테이블(이음 및 글리프 대체)이 있습니다. 이러한 정보는 결과물의 플랫폼 독립성(코드포인트 대신 벡터 설명 포함)을 보장하고, 폰트 기반 아트(폰트를 변형된 형태의 기반으로 활용)를 가능하게 하는 데 필요합니다.
2. 목표
API는 다음을 제공해야 합니다:
-
메인 스레드를 차단하지 않고 모든 로컬 폰트를 효율적으로 열거합니다
-
UA가 원하는 대로 결과를 반환할 수 있도록 보장합니다. 브라우저 구현에 따라 브라우저 내장 기본 폰트 세트만 제공할 수도 있습니다.
-
Worker에서도 사용 가능합니다
-
다양한 수준의 개인정보 보호를 허용합니다. 예를 들어, "신뢰된" 사이트에는 전체 접근을 제공하고, 신뢰할 수 없는 시나리오에는 제한된 접근을 제공합니다
-
Permissions API에서 로컬 폰트 접근 상태를 반영합니다
-
가족 및 인스턴스("bold", "italic"과 같은 변형 포함) 고유 식별(PostScript 이름 포함)을 제공합니다
-
설계상 메모리 누수 및 복사를 방지하여 메모리 효율적으로 동작합니다
-
기본적으로 Permissions Policy 명세에 따라 Secure Context 및 최상단 프레임에서만 로컬 폰트 데이터 접근을 제한합니다
-
결과 목록을 폰트 이름별로 정렬하여 지문 추출 위험을 줄입니다. 예시: .queryLocalFonts()는 이름으로 정렬된 iterable을 반환합니다
-
폰트 데이터의 원시 바이트에 접근을 제공합니다. 대부분의 API 사용례는 전체 폰트 파일을 소비하는 기존 라이브러리에 폰트 전체 데이터를 전달하는 것입니다. 파싱된 폰트 테이블만 제공하면 개발자가 모든 데이터를 포함한 Blob을 재조립해야 할 수도 있습니다.
위에서 Worker에서의 지원이 목표로 언급되었으나, 현재 명세된 API는 Window 컨텍스트에서만 노출됩니다.
3. 예시
이 섹션은 규범적인 내용이 아닙니다.
3.1. 로컬 폰트 열거
API를 통해 각 폰트에 대한 속성을 포함해 로컬 폰트를 열거할 수 있습니다.
showLocalFontsButton. onclick= async function () { try { const array= await self. queryLocalFonts(); array. forEach( font=> { console. log( font. postscriptName); console. log( ` full name: ${ font. fullName} ` ); console. log( ` family: ${ font. family} ` ); console. log( ` style: ${ font. style} ` ); }); } catch ( e) { // 에러 처리, 예: 사용자가 동작을 취소한 경우. console. warn( `Local font access not available: ${ e. message} ` ); } };
3.2. 로컬 폰트로 스타일링
고급 제작 도구는 사용 가능한 모든 로컬 폰트로 텍스트를 스타일링할 수 있습니다. 이 경우 로컬 폰트 이름에 접근하면 사용자가 더 다양한 선택을 고를 수 있습니다:
아래 코드는 사용 가능한 로컬 폰트로 드롭다운 선택 폼을 채우며, 편집 애플리케이션의 UI 일부로 활용될 수 있습니다.
useLocalFontsButton. onclick= async function () { try { // 허용된 로컬 폰트 쿼리. const array= await self. queryLocalFonts(); // 스타일링할 요소 생성. const exampleText= document. createElement( "p" ); exampleText. id= "exampleText" ; exampleText. innerText= "The quick brown fox jumps over the lazy dog" ; exampleText. style. fontFamily= "dynamic-font" ; // 선택용 폰트 리스트와 선택 핸들러 생성. const textStyle= document. createElement( "style" ); const fontSelect= document. createElement( "select" ); fontSelect. onchange= e=> { const postscriptName= fontSelect. value; console. log( "selected:" , postscriptName); // @font-face src: local을 사용한 스타일링 예시. textStyle. textContent= ` @font-face { font-family: "dynamic-font"; src: local(" ${ postscriptName} "); }` ; }; // 사용 가능한 폰트로 리스트를 채움. array. forEach( font=> { const option= document. createElement( "option" ); option. text= font. fullName; // postscriptName은 @font-face src: local과 함께 스타일링에 사용됨. option. value= font. postscriptName; fontSelect. append( option); }); // 모든 요소를 페이지에 추가. document. body. appendChild( textStyle); document. body. appendChild( exampleText); document. body. appendChild( fontSelect); } catch ( e) { // 에러 처리, 예: 사용자가 작업을 취소한 경우. console. warn( `Local font access not available: ${ e. message} ` ); } };
3.3. 폰트 데이터 접근
API는 스크립트가 폰트 데이터를 요청할 수 있도록 합니다.
여기서는 열거를 이용해 특정 로컬 폰트 데이터에 접근합니다. 이를 통해 특정 테이블을 파싱하거나 WASM 버전 HarfBuzz 또는 Freetype 등에 전달할 수 있습니다:
useLocalFontsButton. onclick= async function () { try { const array= await self. queryLocalFonts(); array. forEach( font=> { // blob()은 폰트의 바이트를 담은 Blob을 반환합니다. const bytes= await font. blob(); // SFNT의 첫 네 바이트를 검사하여 포맷을 정의합니다. // 참고: https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font const sfntVersion= await bytes. slice( 0 , 4 ). text(); let outlineFormat= "UNKNOWN" ; switch ( sfntVersion) { case '\x00\x01\x00\x00' : case 'true' : case 'typ1' : outlineFormat= "truetype" ; break ; case 'OTTO' : outlineFormat= "cff" ; break ; } console. log( ` ${ font. fullName} outline format: ${ outlineFormat} ` ); } } catch ( e) { // 에러 처리. 권한 오류일 수도 있습니다. console. warn( `Local font access not available: ${ e. message} ` ); } };
예를 들어 폰트 파일 내 테이블을 열거하는 등 더 자세히 파싱하는 것은 본 명세의 범위를 벗어납니다.
3.4. 특정 폰트 요청
경우에 따라 웹 애플리케이션은 특정 폰트에 대한 접근을 요청할 수 있습니다. 예를 들면, 미리 작성된 콘텐츠에서 폰트 이름을 내장한 경우가 해당됩니다.
queryLocalFonts() 호출에는 postscriptNames 옵션이 있어, PostScript 이름으로 식별된 폰트로 요청 범위를
제한합니다. 리스트에 정확하게 일치하는 이름의 폰트만 반환됩니다.
사용자 에이전트(UAs)는 이를 지원하기 위한 별도의 UI를 제공할 수 있습니다. 예를 들어 지문 추출 위험이 적다고 판단되면, 권한 요청 없이 바로 응답할 수 있습니다. 아니면, 요청된 폰트만 포함하는 선택기를 보여줄 수도 있습니다.
// 사용자 활성화가 필요합니다. requestFontsButton. onclick= async function () { try { const array= await self. queryLocalFonts({ postscriptNames: [ 'Verdana' , 'Verdana-Bold' , 'Verdana-Italic' ]}); array. forEach( font=> { console. log( `Access granted for ${ font. postscriptName} ` ); }); } catch ( e) { // 에러 처리. 권한 오류일 수도 있습니다. console. warn( `Local font access not available: ${ e. message} ` ); } };
4. 개념
사용자 언어는 가능한 언어 또는 사용자가 가장 선호하는 언어를 나타내는 유효한 BCP 47 언어 태그입니다. [BCP47]
4.1. 폰트 표현
폰트 표현은 폰트의 구체적 표현입니다. 예시로 OpenType, TrueType, 비트맵 폰트, Type1 폰트, SVG 폰트, 그리고 향후의 폰트 포맷 등이 있습니다. 본 명세는 폰트 표현의 속성을 다음과 같이 정의합니다:
-
데이터 바이트는 폰트의 직렬화가 담긴 바이트 시퀀스입니다.
참고: 폰트 표현의 데이터 바이트는 일반적으로 사용자의 파일 시스템에 있는 폰트 파일의 바이트 단위 그대로의 표현이어야 합니다. UA는 폰트 데이터를 정규화하지 않으므로, 같은 사용자 및 특정 OS 환경에서 에이전트 간에 폰트 표현이 달라지지 않습니다. 정규화를 하지 않는 것은 전체 품질의 폰트로 웹앱에서 텍스트 렌더링(콘텐츠 제작 포함) 작업을 할 수 있도록 지원합니다.
-
PostScript 이름은 name table의 nameID = 6에서 찾을 수 있고, 여러 지역 버전이 있으면 미국 영어를, 없으면 첫 번째 버전을 사용합니다.
-
풀 네임은 name table의 nameID = 4에서 찾으며, 여러 지역 버전이 있으면 사용자 언어 버전을, 없으면 첫 번째 버전을 사용합니다.
-
패밀리 이름은 name table의 nameID = 1에서 여러 지역 버전이 있으면 사용자 언어 버전을, 없으면 첫 번째 버전을 사용합니다.
-
스타일 이름은 name table의 nameID = 2에서 여러 지역 버전이 있으면 사용자 언어 버전을, 없으면 첫 번째 버전을 사용합니다.
이러한 이름 속성은 [CSS-FONTS-4]의 속성 사용과 일치하도록 공개됩니다. 예를 들어 @font-face, font-family 등. PostScript 이름은 새 콘텐츠 작성 시 폰트 지정 또는 기존 콘텐츠와의 폰트 매칭 등에서 고유 키로 활용될 수 있습니다. 풀 네임 또는 패밀리 이름은 사용자 UI 폰트 선택에, 스타일 이름은 구체적 선택에 사용할 수 있습니다.
유효한 PostScript 이름은 스칼라 값 문자열로, 길이가 64 미만이며 U+0021(!) ~ U+007E(~) 범위 문자로 구성되고, 아래 10개 코드 유닛을 제외합니다. U+005B ([), U+005D (]), U+0028 (, U+0029 ), U+007B ({), U+007D (}), U+003C (<), U+003E (>), U+002F (/), 그리고 U+0025 (%).
참고: 이는 nameID = 6의 요구사항과 일치하도록 합니다. [OPENTYPE].
4.2. 시스템 폰트
시스템 폰트는 운영체제에서 전체 시스템에 제공하는 폰트입니다.
시스템 폰트를 폰트 표현으로 읽는다란 해당 폰트와 동등한 폰트 표현을 제공하는 것으로, 폰트 표현의 속성을 모두 제공하는 것을 의미합니다:
-
PostScript 이름, 유효해야 합니다.
-
풀 네임.
이 작업은 폰트 표현을 제공할 수 없을 때 실패할 수 있습니다.
사용자 에이전트는 시스템 폰트에 대한 폰트 표현을 어떤 알고리즘으로도 제공할 수 있습니다. 실제로 최근 운영체제와 시스템 API는 SFNT [SFNT] 폰트 파일 포맷(예: OpenType, TrueType, Web Open Font Format 등)으로 폰트를 저장하고, 각 폰트에 공통 이름 속성들을 효율적으로 열거할 수 있습니다.
5. 권한 통합
로컬 폰트 열거에는 권한이 필요합니다.
5.1. 권한
Local Font Access API는 기본 강력 기능으로, 이름
"local-fonts"로 식별됩니다.
queryLocalFonts()
API가 호출되면 사용자 에이전트는 폰트 선택 목록, 예/아니오 선택 또는 기타 인터페이스를 보여줄 수 있습니다. 선택 결과는 권한 상태와 적절히 연동돼야 합니다. 예시로 사용자가 노출할 폰트
세트를 선택했고 후속 API 호출에 같은 폰트만 반환할 경우 "granted" 상태가 될 수 있습니다. 사용자가 반복해서 안내를 받는다면 "prompt" 상태일 수 있습니다.
navigator.permissions
API에서 쿼리할 수 있습니다:
// 이 코드는 현재 권한 상태만 쿼리하고, 이를 변경하지 않습니다. const status= await navigator. permissions. query({ name: "local-fonts" }); if ( status. state=== "granted" ) console. log( "permission was granted 👍" ); else if ( status. state=== "prompt" ) console. log( "permission will be requested" ); else console. log( "permission was denied 👎" );
5.2. 권한 정책
본 명세는 정책 제어 기능을 "local-fonts" 문자열로 정의합니다. 기본 허용 목록은 'self'입니다.
'self'는 동일 출처의 중첩
프레임은 기본 허용하지만, 타사 콘텐츠의 접근은 차단합니다.
타사 컨텐츠에서 이 기능을 사용하고 싶다면 allow="local-fonts" 속성을
iframe
요소에 추가하면 됩니다:
또는, HTTP 응답 헤더에서 권한 정책을 명시하면 1차 출처에서 기능을 완전히 비활성화할 수 있습니다:
자세한 내용은 [PERMISSIONS-POLICY]를 참조하세요.
6. API
6.1. 폰트 태스크 소스
폰트 태스크 소스 는 이 명세에서 모든 태스크 소스에 사용되는 새로운 일반 태스크입니다.
6.2. 폰트 관리자
- await self .
queryLocalFonts()- await self .
queryLocalFonts({postscriptNames: [ ... ] }) - await self .
-
사용 가능/허용된 폰트들을 비동기적으로 쿼리합니다. 성공하면 반환된 프라미스는
FontData객체의 배열로 해결됩니다.이 메서드가 문서가 일시적 활성화(예: 클릭 이벤트) 상태에서 호출되지 않으면, 반환된 프라미스는 거부됩니다.
사용자는 로컬 폰트 접근 또는 사이트에 제공할 폰트 선택 권한을 요청받게 됩니다. 권한이 부여되지 않으면, 반환된 프라미스는 거부됩니다.
postscriptNames옵션이 있으면 일치하는 PostScript 이름의 폰트만 결과에 포함됩니다.
[SecureContext ]partial interface Window {Promise <sequence <FontData >>queryLocalFonts (optional QueryOptions = {}); };options dictionary {QueryOptions sequence <DOMString >; };postscriptNames
queryLocalFonts(options) 메서드 단계:
-
promise를 새 프라미스로 둡니다.
-
descriptor를
PermissionDescriptor로 두고name을"local-fonts"로 설정합니다. -
this의 관련 설정 객체의 origin이 불투명 origin이면 SecurityError
DOMException으로 promise를 거부하고 반환합니다. -
this의 관련 글로벌 객체의 연결된 Document가 해당 정책 제어 기능 이름
"local-fonts"을 사용할 수 없다면, SecurityErrorDOMException으로 promise를 거부하고 반환합니다. -
this의 관련 글로벌 객체에 일시적 활성화가 없으면, SecurityError
DOMException으로 promise를 거부하고 반환합니다. -
그 외의 경우, 다음 단계를 병렬로 실행합니다:
-
system fonts를 모든 시스템 폰트 표현 얻기의 결과로 둡니다.
-
selectable fonts를 새 리스트로 둡니다.
-
각 폰트 representation에 대해 system fonts에서 다음을 실행:
-
postscriptName을 representation의 PostScript 이름으로 둡니다.
-
확인: postscriptName은 유효한 PostScript 이름입니다.
-
options[
"postscriptNames"]이 존재하고 options["postscriptNames"]이 포함하지 않으면 postscriptName, continue. -
새
FontData인스턴스를 representation과 연결해 selectable fonts에 추가합니다.
-
-
사용자가 선택하도록 안내를 selectable fonts에서 실행하며, descriptor와 allowMultiple를 true로 설정해서 그 결과를 result로 둡니다. 사용자 에이전트는 목록이 아닌 예/아니오 선택만 보여줄 수도 있으며, 이 경우 result를 selectable fonts로 설정해야 합니다.
-
result가
"denied"인 경우 NotAllowedErrorDOMException으로 promise를 거부하고 단계를 중단합니다. -
result를
postscriptName기준으로 오름차순 정렬하여 다시 result로 저장합니다. -
폰트 태스크 소스에서 태스크를 대기열에 넣어 promise를 result로 해결합니다.
-
-
promise를 반환합니다.
WindowOrWorkerGlobalScope
로 이동 및 권한 문제 정리 필요.
6.3. FontData
인터페이스
FontData
는 폰트 페이스에 대한 상세 정보를 제공합니다. 각각의 FontData는
연결된 폰트 표현을 갖습니다.
- fontdata .
postscriptName -
해당 폰트의 PostScript 이름. 예: "
Arial-Bold". - fontdata .
fullName -
전체 폰트 이름(가족, 서브패밀리 이름 포함). 예: "
Arial Bold" - fontdata .
family -
폰트 패밀리 이름. CSS font-family 속성과 대응됨. 예: "
Arial" - fontdata .
style -
폰트 스타일(서브패밀리) 이름. 예: "
Regular", "Bold Italic"
[Exposed =Window ]interface {FontData Promise <Blob >blob (); // Namesreadonly attribute USVString postscriptName ;readonly attribute USVString fullName ;readonly attribute USVString family ;readonly attribute USVString style ; };
postscriptName getter 단계:
-
postscriptName을 this의 PostScript 이름으로 둡니다.
-
확인: postscriptName은 유효한 PostScript 이름입니다.
-
postscriptName을 반환합니다.
fullName getter 단계는 this의
연결된 폰트 표현의 풀 네임을 반환합니다.
FontData
를 serializable objects로 만들어 queryLocalFonts()
결과를 Workers로 전달할 수 있게 할지 고려하세요.
blob() 메서드 단계:
7. 국제화 고려사항
문자열 현지화 이외의 국제화 고려사항 문서화, 예: https://github.com/WICG/local-font-access/issues/72, https://github.com/WICG/local-font-access/issues/59 등.
7.1. 폰트 이름
OpenType 폰트의
`name` 테이블은 이름(패밀리, 서브패밀리 등)에 대해 플랫폼별 숫자 언어 식별자 또는 [BCP47]에 따라 언어 태그 문자열을 사용하여 다국어 문자열을 지정할
수 있도록 허용합니다. 예를 들어, 하나의 폰트에 `en-US`와 `zh-Hant-HK` 모두에 대한 패밀리 이름 문자열을 정의할 수 있습니다.
FontData
속성인 postscriptName,
fullName,
family,
style
등은 이 API를 통해 단순 문자열로 제공되며, 이름마다 미국 영어 현지화 또는 사용자 언어로 현지화된 값을 사용하거나, 첫 번째 현지화 값을 기본값으로 사용합니다.
다른 언어로 폰트 이름을 제공해야 하는 웹 애플리케이션은 `name` 테이블을 직접 요청하고 파싱할 수 있습니다.
queryLocalFonts()
메서드에 원하는 언어(예: {lang: 'zh'})를 지정하는 옵션을 정의하고, 해당 언어가 없으면 `en-US`로 폴백하도록 할지, 또는 [BCP47] 언어 태그별로
이름을 맵(map) 형태로 모두 제공할지 정의해야 할까요? [Issue
#69]
8. 접근성 고려사항
이 기능에는 알려진 접근성 영향이 없습니다.
9. 보안 고려사항
이 기능에는 알려진 보안 영향이 없습니다.
10. 개인정보 보호 고려사항
10.1. 지문 추출(fingerprinting)
폰트 데이터에는 다음이 포함됩니다:
-
운영체제에 기본 포함된 폰트
-
시스템에 설치된 특정 애플리케이션(예: 오피스 프로그램 등)이 설치한 폰트
-
시스템 관리자 또는 최종 사용자에 의해 직접 설치된 폰트
-
시스템에 설치된 폰트의 버전(폰트 데이터를 통해 확인)
이 내용은 사용자를 식별할 수 있는 여러 “엔트로피 비트”를 제공합니다.
사용자 에이전트는 특정 경우(예: 권한 거부 시, 프라이빗 브라우징/숨김 모드)에는 내장 고정 폰트 목록만 제공함으로써 이를 완화할 수 있습니다.
사용자 에이전트는 사용자가 API로 제공 가능한 폰트 집합을 직접 선택하도록 허용할 수도 있습니다.
폰트에 여러 현지화된 폰트 이름이 제공되는 경우, 사용자의 로캘이 이름을 통해 노출될 수 있습니다. 사용자 에이전트는 이름 현지화로 노출되는 로캘이
navigator.
와 동일하게 노출되도록 해야 합니다.
language
10.2. 식별
특정 조직 사용자는 특수 폰트가 설치되어 있을 수 있습니다. 예를 들어 "Example Co." 직원들은 시스템 관리자가 설치한 "Example Corporate Typeface"를 모두 가지고 있으며, 이런 폰트로 사이트 사용자를 직원으로 구별할 수 있습니다.
필적 샘플로 폰트를 만들어주는 서비스도 있습니다. 폰트 이름에 개인 식별 정보를 포함(예: "Alice의 손글씨 폰트")하는 경우, 개인 정보가 노출될 수 있습니다. 이 정보가 폰트 이름이 아닌 폰트 속성에 들어 있는 경우엔 사용자에게 명확하게 인지되지 않을 수 있습니다.
11. 감사의 글
기여자들에게 감사의 뜻을 전합니다:
-
이전 로컬 폰트 접근 제안에 기여한 Daniel Nishi, Owen Campbell-Moore, Mike Tsao
-
Figma의 Evan Wallace, Biru, Leah Cassidy, Katie Gregorio, Morgan Kennedy, Noah Levin(야심찬 웹 제품 요구 분석)
-
초기 제안서 초안을 작성한 Alex Russell
-
API 형태의 초기 구현 및 반복 개발을 제공한 Olivier Yiptong
-
Tab Atkins, Jr. 및 CSS 워킹 그룹(기초 클래스와 확장 제공)
-
유익한 피드백을 준 Dominik Röttsches, Igor Kopylov
-
2020년에 작고한 전 편집자 Emil A. Eklund에게도 깊은 감사를 표합니다. Emil은 제안 추진, 기술적 가이던스, 사용자 및 개발자 필요 옹호에 있어 중요한 역할을 했습니다.
그리고 이 문서 작성에 사용된 명세 저작 도구 Bikeshed 개발 및 유지에 다시 한 번 Tab Atkins, Jr.에게 특별히 감사드립니다.
아울러 Anne van Kesteren, Chase Phillips, Domenic Denicola, Dominik Röttsches, Igor Kopylov, Jake Archibald, Jeffrey Yasskin 등 여러 분께 제안, 리뷰, 피드백을 주셔서 감사드립니다.