로컬 글꼴로 고급 서체 사용

Local Fonts Access API를 사용하여 사용자의 로컬에 설치된 글꼴에 액세스하고 글꼴에 관한 하위 수준 세부정보를 가져오는 방법을 알아보세요.

웹 안전 글꼴

웹 개발을 오랫동안 해 왔다면 웹 안전 글꼴이라는 용어를 기억할 수 있습니다. 이러한 글꼴은 가장 많이 사용되는 운영체제(예: Windows, macOS, 가장 일반적인 Linux 배포판, Android, iOS)의 거의 모든 인스턴스에서 사용할 수 있는 것으로 알려져 있습니다. 2000년대 초, Microsoft는 '해당 글꼴을 지정하는 웹사이트를 방문할 때마다 사이트 디자이너가 의도한 대로 페이지를 보게 된다'는 목표로 이러한 글꼴을 무료로 다운로드할 수 있도록 하는 웹용 TrueType 핵심 글꼴이라는 프로젝트를 주도하기도 했습니다. 예. 여기에는 Comic Sans MS로 설정된 사이트도 포함됩니다. 다음은 기존의 웹 안전 글꼴 스택 (어떤 sans-serif 글꼴이든 최종 대체 글꼴 포함)의 예입니다.

body {
  font-family: Helvetica, Arial, sans-serif;
}

웹 글꼴

웹 보안 글꼴이 정말 중요한 시절은 이미 지났습니다. 오늘날에는 웹 글꼴이 있으며, 그중 일부는 노출된 다양한 축의 값을 변경하여 추가로 조정할 수 있는 가변 글꼴입니다. CSS 시작 시 다운로드할 글꼴 파일을 지정하는 @font-face 블록을 선언하여 웹 글꼴을 사용할 수 있습니다.

@font-face {
  font-family: 'FlamboyantSansSerif';
  src: url('flamboyant.woff2');
}

그런 다음 평소와 같이 font-family를 지정하여 맞춤 웹 글꼴을 사용할 수 있습니다.

body {
  font-family: 'FlamboyantSansSerif';
}

지문 벡터로 사용되는 로컬 글꼴

대부분의 웹 글꼴은 웹에서 가져옵니다. 하지만 흥미로운 사실은 @font-face 선언의 src 속성이 url() 함수 외에도 local() 함수도 허용한다는 것입니다. 이렇게 하면 맞춤 글꼴을 로컬에 로드할 수 있습니다. 사용자가 운영체제에 FlamboyantSansSerif를 설치한 경우 다운로드되지 않고 로컬 사본이 사용됩니다.

@font-face {
  font-family: 'FlamboyantSansSerif';
  src: local('FlamboyantSansSerif'), url('flamboyant.woff2');
}

이 접근 방식은 대역폭을 절약할 수 있는 유용한 대체 메커니즘을 제공합니다. 안타깝게도 인터넷에서는 좋은 일이 항상 일어나지 않습니다. local() 함수의 문제는 브라우저 지문 식별에 악용될 수 있다는 점입니다. 사용자가 설치한 글꼴 목록은 사용자를 식별하는 데 매우 유용합니다. 많은 회사가 직원의 노트북에 자체 회사 글꼴을 설치합니다. 예를 들어 Google은 Google Sans라는 기업 폰트를 사용합니다.

Google Sans 글꼴의 미리보기를 보여주는 macOS Font Book 앱
Google 직원의 노트북에 설치된 Google Sans 글꼴

공격자는 Google Sans와 같은 알려진 기업 서체가 다량 있는지 테스트하여 사용자가 어느 회사에서 근무하는지 파악하려고 시도할 수 있습니다. 공격자는 이러한 글꼴에 설정된 텍스트를 캔버스에서 렌더링하고 글리프를 측정하려고 합니다. 글리프가 알려진 기업 서체의 도형과 일치하면 공격자가 일치를 발견한 것입니다. 글리프가 일치하지 않으면 공격자는 회사 글꼴이 설치되지 않았으므로 기본 교체 글꼴이 사용되었음을 알 수 있습니다. 이 공격과 기타 브라우저 지문 공격에 관한 자세한 내용은 Laperdix et al.설문조사 논문을 참고하세요.

회사 글꼴 외에도 설치된 글꼴 목록만으로도 식별이 가능합니다. 이 공격 벡터의 상황이 매우 나빠서 최근에 WebKit팀은 '사용 가능한 글꼴 목록에 운영체제와 함께 제공되는 웹 글꼴과 글꼴만 포함하고 로컬에 사용자가 설치한 글꼴은 포함하지 않는' 결정을 내렸습니다. (로컬 글꼴에 대한 액세스 권한 부여에 관한 도움말을 준비했습니다.)

Local Font Access API

이 기사의 도입부로 인해 부정적인 기분이 들었을 수 있습니다. 정말 좋은 걸 먹지 않아도 될까요? 걱정하지 마세요. YouTube는 모든 것이 절망적인 것은 아닙니다. 하지만 먼저 고객님께서 궁금해하실 수 있는 질문에 답변해 드리겠습니다.

웹 글꼴이 있는데 Local Fonts Access API가 필요한 이유는 무엇인가요?

이전에는 웹에서 전문가 수준의 디자인 및 그래픽 도구를 제공하기가 어려웠습니다. 한 가지 문제는 디자이너가 로컬에 설치한 다양한 전문적으로 구성되고 힌트가 적용된 글꼴에 액세스하고 이를 사용할 수 없다는 것입니다. 웹 글꼴은 일부 게시 사용 사례를 지원하지만 래스터라이저가 글리프 윤곽선을 렌더링하는 데 사용하는 벡터 글리프 도형 및 글꼴 테이블에 대한 프로그래매틱 액세스를 지원하지 않습니다. 마찬가지로 웹 글꼴의 바이너리 데이터에 액세스할 방법도 없습니다.

  • 디자인 도구는 자체 OpenType 레이아웃 구현을 실행하고 디자인 도구가 글리프 도형에서 벡터 필터 또는 변환을 실행하는 등의 작업을 위해 하위 수준에서 후크를 사용할 수 있도록 글꼴 바이트에 액세스해야 합니다.
  • 개발자는 웹에 가져오는 애플리케이션에 대한 기존 글꼴 스택을 보유하고 있을 수 있습니다. 이러한 스택을 사용하려면 일반적으로 웹 글꼴에서 제공하지 않는 글꼴 데이터에 직접 액세스해야 합니다.
  • 일부 글꼴은 웹을 통한 전송에 라이선스가 부여되지 않았을 수 있습니다. 예를 들어 Linotype에는 데스크톱 사용만 포함된 일부 글꼴에 대한 라이선스가 있습니다.

Local Font Access API는 이러한 문제를 해결하기 위한 시도입니다. 다음 두 부분으로 구성됩니다.

  • 사용자가 사용 가능한 모든 시스템 글꼴에 대한 액세스 권한을 부여할 수 있는 글꼴 열거 API
  • 각 열거 결과에서 전체 글꼴 데이터가 포함된 하위 수준 (바이트 지향) SFNT 컨테이너 액세스를 요청하는 기능

브라우저 지원

브라우저 지원

  • Chrome: 103.
  • Edge: 103.
  • Firefox: 지원되지 않음
  • Safari: 지원되지 않음

소스

Local Fonts Access API 사용 방법

특성 감지

Local Font Access API가 지원되는지 확인하려면 다음을 사용합니다.

if ('queryLocalFonts' in window) {
  // The Local Font Access API is supported
}

로컬 글꼴 열거

로컬에 설치된 글꼴 목록을 가져오려면 window.queryLocalFonts()를 호출해야 합니다. 처음에는 사용자가 승인하거나 거부할 수 있는 권한 메시지가 표시됩니다. 사용자가 로컬 글꼴을 쿼리하도록 승인하면 브라우저는 루프할 수 있는 글꼴 데이터가 포함된 배열을 반환합니다. 각 글꼴은 family(예: "Comic Sans MS"), fullName (예: "Comic Sans MS"), postscriptName (예: "ComicSansMS"), style (예: "Regular") 속성이 포함된 FontData 객체로 표시됩니다.

// Query for all available fonts and log metadata.
try {
  const availableFonts = await window.queryLocalFonts();
  for (const fontData of availableFonts) {
    console.log(fontData.postscriptName);
    console.log(fontData.fullName);
    console.log(fontData.family);
    console.log(fontData.style);
  }
} catch (err) {
  console.error(err.name, err.message);
}

글꼴의 하위 집합에만 관심이 있는 경우 postscriptNames 매개변수를 추가하여 PostScript 이름을 기준으로 글꼴을 필터링할 수도 있습니다.

const availableFonts = await window.queryLocalFonts({
  postscriptNames: ['Verdana', 'Verdana-Bold', 'Verdana-Italic'],
});

SFNT 데이터에 액세스

전체 SFNT 액세스는 FontData 객체의 blob() 메서드를 통해 사용할 수 있습니다. SFNT는 PostScript, TrueType, OpenType, Web Open Font Format (WOFF) 글꼴 등 다른 글꼴을 포함할 수 있는 글꼴 파일 형식입니다.

try {
  const availableFonts = await window.queryLocalFonts({
    postscriptNames: ['ComicSansMS'],
  });
  for (const fontData of availableFonts) {
    // `blob()` returns a Blob containing valid and complete
    // SFNT-wrapped font data.
    const sfnt = await fontData.blob();
    // Slice out only the bytes we need: the first 4 bytes are the SFNT
    // version info.
    // Spec: https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font
    const sfntVersion = await sfnt.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('Outline format:', outlineFormat);
  }
} catch (err) {
  console.error(err.name, err.message);
}

데모

아래 데모에서 로컬 글꼴 액세스 API가 작동하는 모습을 확인할 수 있습니다. 소스 코드도 확인해야 합니다. 이 데모에서는 로컬 글꼴 선택기를 구현하는 <font-select>라는 맞춤 요소를 보여줍니다.

개인정보 보호 고려사항

"local-fonts" 권한은 지문 식별이 용이한 노출 영역을 제공하는 것으로 보입니다. 그러나 브라우저는 원하는 것은 무엇이든 반환할 수 있습니다. 예를 들어 익명성을 중시하는 브라우저는 브라우저에 내장된 기본 글꼴 세트만 제공하도록 선택할 수 있습니다. 마찬가지로, 브라우저에서는 디스크에 표시되는 것과 동일한 테이블 데이터를 제공할 필요가 없습니다.

Local Font Access API는 가능하면 언급된 사용 사례를 사용 설정하는 데 필요한 정보만 정확하게 노출하도록 설계되었습니다. 시스템 API는 무작위 또는 정렬된 순서가 아닌 글꼴 설치 순서로 설치된 글꼴 목록을 생성할 수 있습니다. 이러한 시스템 API에서 제공하는 설치된 글꼴 목록을 정확하게 반환하면 지문 식별에 사용될 수 있는 추가 데이터가 노출될 수 있으며, 사용하려는 사용 사례는 이 순서를 유지해도 도움이 되지 않습니다. 따라서 이 API는 반환된 데이터를 반환하기 전에 정렬해야 합니다.

보안 및 권한

Chrome팀은 사용자 제어, 투명성, 인체공학을 비롯하여 강력한 웹 플랫폼 기능에 대한 액세스 제어에 정의된 핵심 원칙을 사용하여 로컬 글꼴 액세스 API를 설계하고 구현했습니다.

사용자 제어

사용자의 글꼴에 대한 액세스는 사용자가 완전히 제어하며 권한 레지스트리에 나열된 "local-fonts" 권한이 부여되지 않으면 허용되지 않습니다.

투명성

사이트에 사용자의 로컬 글꼴에 대한 액세스 권한이 부여되었는지 여부는 사이트 정보 시트에 표시됩니다.

권한 유지

"local-fonts" 권한은 페이지를 새로고침해도 유지됩니다. 사이트 정보 시트를 통해 취소할 수 있습니다.

의견

Chrome팀은 Local Font Access API 사용 경험에 관한 의견을 듣고자 합니다.

API 설계에 대해 알려주세요.

API에서 예상대로 작동하지 않는 부분이 있나요? 아니면 아이디어를 구현하는 데 필요한 메서드나 속성이 누락되었나요? 보안 모델에 관해 질문이나 의견이 있으신가요? 해당 GitHub 저장소에서 사양 문제를 제출하거나 기존 문제에 의견을 추가합니다.

구현 문제 신고

Chrome 구현에서 버그를 발견했나요? 아니면 구현이 사양과 다른가요? new.crbug.com에서 버그를 신고합니다. 간단한 재현 안내를 포함하여 최대한 많은 세부정보를 포함하고 Components 상자에 Blink>Storage>FontAccess를 입력합니다. Glitch는 빠르고 간편한 재현을 공유하는 데 적합합니다.

API 지원 표시

Local Font Access API를 사용할 계획인가요? 공개 지원은 Chrome팀이 기능의 우선순위를 정하는 데 도움이 되며 다른 브라우저 공급업체에 이러한 기능을 지원하는 것이 얼마나 중요한지 보여줍니다.

#LocalFontAccess 해시태그를 사용하여 @ChromiumDev에 트윗을 보내 사용 위치와 사용 방법을 알려주세요.

감사의 말씀

Local Font Access API 사양은 에밀 A. Eklund, Alex Russell, Joshua Bell, Olivier Yiptong. 이 도움말은 조 메들리, 도미니크 뢰셱스, 올리비에 이프통이 검토했습니다. Unsplash브렛 조던님이 제공한 히어로 이미지