다운로드된 폰트가 사용되지 않는 이유는 CSS가 다른 서체를 선택하거나, 텍스트가 해당 폰트의 지원 범위를 벗어나거나, 표시 시간이 이미 지났기 때문일 수 있습니다. Mac에서는 먼저 라벨 하나를 실제로 렌더링하는 폰트를 확인한 다음, 선택과 로딩 과정을 역추적하세요.

성공적인 폰트 요청이 보이는데도 대체 글꼴 텍스트가 표시되는 웹페이지를 관리하는 사람을 위한 안내서입니다. 검사 단계에서는 macOS에서 Chrome을 사용하세요. 아래의 가상 라벨 Panel 204와 패밀리 이름 Sample Sans는 진단 과정을 설명하기 위한 예시이며, 특정 웹사이트를 가리키지 않습니다.

다운로드가 성공했다는 사실로 실제로 무엇을 알 수 있나요?

진단을 네 가지 질문으로 나누세요. 리소스를 가져왔나요? 사용할 수 있는 서체가 등록되었나요? 이 텍스트에 CSS가 해당 서체를 선택했나요? 렌더러가 그 서체로 글자를 그렸나요? 폰트 프리로드는 일찍 가져오기를 시작하지만, 이것만으로 화면에 보이는 텍스트에 어떤 폰트가 쓰였는지는 알 수 없습니다. MDN: rel="preload"

폰트 매칭은 다운로드된 파일만이 아니라 텍스트를 기준으로 이루어집니다. 브라우저는 요청된 패밀리와 폰트 속성을 고려한 다음, 문자 지원 여부를 확인합니다. 따라서 라벨 하나에 여러 폰트가 쓰일 수 있고, 페이지의 다른 부분에서 폰트 다운로드를 유발해도 확인하려는 라벨에 대해서는 유용한 정보를 얻지 못할 수 있습니다. W3C: CSS Fonts Module Level 4, 폰트 매칭

다음 진단 표에서 다음에 확인할 항목을 선택하세요. 이는 문서에 설명된 로딩 및 매칭 경계를 바탕으로 만든 진단 보조 자료이며, 브라우저 측정 결과를 기록한 것이 아닙니다.

관찰 결과 다음 확인 항목 구분에 도움이 되는 문제
계산된 패밀리가 의도한 패밀리와 다름 우선 적용된 CSS 선언 추적 캐스케이드 또는 대상 지정 문제
계산된 패밀리는 맞지만 렌더링된 폰트가 다름 서체 설명자와 문자 지원 범위 확인 선택 또는 대체 문제
JavaScript에서 서체가 로드되었다고 보고하지만 문서의 폰트 세트에는 없음 등록 코드 확인 등록되지 않은 로딩
다시 로드한 뒤에는 폰트가 나타나지만 첫 방문 때는 나타나지 않음 font-display 및 로딩 시점 확인 표시 시간 동작
일반 텍스트는 바뀌지만 캔버스 텍스트는 그대로임 그리기 순서와 캔버스 폰트 설정 확인 별도의 그리기 작업

대상 라벨을 실제로 그리는 폰트는 무엇인가요?

문제가 있는 페이지에서 Command + Shift + C를 누르고 텍스트를 선택하세요. Elements에서 문제가 있는 라벨을 포함하는 가장 작은 요소를 선택합니다. Computed를 열고 Rendered Fonts까지 스크롤하세요. Chrome 문서에 따르면 렌더링된 텍스트에 사용된 폰트를 확인하는 곳이 바로 이 뷰입니다. Chrome DevTools: CSS 기능 참조, Chrome DevTools: 기타 효과 적용

렌더링된 서체와 그 출처가 로컬인지 네트워크 리소스인지 기록하세요. 계산된 font-family, font-weight, font-style도 기록합니다. 계산된 패밀리는 요청된 폰트 스택을 나타내고, 렌더링된 폰트 결과는 실제 글자를 그린 폰트를 보여줍니다. 익숙해 보이는지만으로 판단하는 것은 근거가 약합니다. 두 서체의 모양이 비슷할 수 있기 때문입니다. Chrome DevTools: 어떤 폰트인가요?

문제가 있는 텍스트에 의도한 서체가 표시된다면 굵기나 글꼴 기능 등 모양 차이의 원인을 조사하세요. 표시되지 않는다면 아래 단계를 계속 진행합니다. 각 관찰 결과를 비교할 수 있도록 테스트하는 동안 원래 텍스트와 뷰포트는 그대로 유지하세요.

실제 CSS가 의도한 서체를 요청하나요?

Computed에서 실제 적용된 폰트 속성을 확인한 다음 Styles에서 해당 속성의 선언을 찾으세요. Chrome은 두 뷰를 구분합니다. Styles에는 재정의된 선언이 포함되고, Computed에는 실제 적용된 값이 표시됩니다. 카드에 라벨이 여러 개 있다면 텍스트를 포함하는 자식 요소를 확인하세요. 부모의 폰트 선언만으로는 자식 요소에 대한 근거가 되지 않습니다. Chrome DevTools: CSS 기능 참조

우선 적용된 font 단축 속성과 개별 속성을 모두 확인하세요. 예를 들어 font: 16px sans-serif는 일반 패밀리를 선택하고, 굵기와 스타일을 포함해 단축 속성에서 생략된 구성 요소를 초기화합니다. font-feature-settings 및 font-variation-settings 같은 속성도 초기화됩니다. 예상과 다른 값을 만든 선언을 수정한 다음 다시 확인하세요. MDN: font

그다음 요청된 패밀리와 관련 @font-face 규칙의 font-family 설명자를 비교하세요. 이 설명자는 서체를 참조하는 데 사용하는 CSS 패밀리 이름을 정의합니다. 폰트 스택에 넣어야 하는 이름은 파일명이 아닙니다. src, 굵기, 스타일, 선언된 범위 등 브라우저에 전달된 규칙을 확인하세요. MDN: @font-face

가변 폰트는 지원하는 굵기 범위를 두 값으로 지정할 수 있지만, 정적 서체는 굵기 하나를 선언할 수 있습니다. 해당 리소스에 맞게 설명자를 설정하세요. 설명자가 일치하지 않는다면 조사할 필요가 있지만, 그렇다고 해서 자동으로 대체 글꼴의 원인이 되는 것은 아닙니다. 정확히 일치하는 스타일이 없을 때도 폰트 매칭은 대체 서체를 고려합니다. MDN: @font-face, W3C: 폰트 스타일 매칭

로컬 폰트가 우선 적용될 수 있나요?

src에서 local() 대체 항목이 있는지 확인하세요. 해당 폰트가 설치된 Mac에서는 별도로 프리로드된 웹폰트가 사용되지 않고 브라우저가 로컬 사본을 사용할 수 있습니다. Chrome에서 이 조건을 분리해 확인하려면 Rendering 패널을 열고 Disable local fonts를 활성화한 뒤 다시 로드하세요. 설정을 켜기 전후의 Rendered Fonts를 비교한 다음 설정을 원래대로 되돌리세요. 이 테스트는 @font-face 규칙의 local() 소스를 대상으로 합니다. Chrome DevTools: 기타 효과 적용

올바른 문서에서 서체가 로드되고 등록되었나요?

new FontFace()로 만든 서체는 폰트 세트에 추가되기 전에 로딩을 마칠 수 있습니다. 문서 렌더링에 사용하려면 document.fonts에 추가해야 합니다. 애플리케이션의 로딩 경로에서 두 작업이 모두 이루어지는지 확인하세요. 서체의 로드 프라미스가 완료되는 것만으로는 등록이 끝나지 않습니다. MDN: CSS Font Loading API

아래의 완전한 콘솔 진단 코드는 현재 문서에 등록된 서체를 나열합니다. 문제가 발생한 페이지의 콘솔 컨텍스트에서 실행하세요. 스타일을 변경하거나 로드를 시작하지 않고 세트를 읽습니다. 렌더링된 글자를 식별하지는 않습니다. 브라우저에 따라 달라질 수 있는 이 코드는 여기서 실행하지 않았습니다.

(() => {
  const faces = Array.from(document.fonts, face => ({
    family: face.family,
    weight: face.weight,
    style: face.style,
    stretch: face.stretch,
    unicodeRange: face.unicodeRange,
    status: face.status
  }));

  console.table(faces);
  console.log("Registered face count:", faces.length);
})();

이 목록을 사용해 등록 누락과 등록되었지만 사용되지 않는 서체를 구분하세요. 상태가 error인 항목은 타이포그래피를 조정하기 전에 로딩 실패를 조사하세요. loaded 항목은 로딩 상태를 보여줄 뿐이며, 서체 선택은 여전히 요소와 텍스트에 따라 달라집니다. MDN: CSS Font Loading API

document.fonts.check()을 렌더링의 증거로 취급하지 마세요. 존재하지 않는 패밀리에 대해서도 true을 반환할 수 있습니다. 선택적 텍스트 인수는 선언된 유니코드 범위를 기준으로 매칭 범위를 좁히며, 개별 글리프의 지원 여부를 테스트하지 않습니다. 마찬가지로 document.fonts.ready는 사용된 폰트의 로딩과 레이아웃이 끝난 뒤 해결되지만, 선언된 모든 서체가 렌더링되었음을 보장하지는 않습니다. MDN: FontFaceSet.check(), MDN: Document.fonts

테스트 중인 문자를 폰트가 지원하나요?

CSS unicode-range와 실제 폰트 리소스를 모두 확인하세요. 설명자는 어떤 문자를 해당 서체로 표시할 수 있는지 제어합니다. 설명자 범위를 넓혀도 파일에 없는 글리프를 만들어낼 수는 없습니다. 폰트의 문자 맵은 여전히 매칭 과정의 일부입니다. MDN: unicode-range, W3C: 폰트 스타일 매칭

U+0030-0039로 제한된 예시 규칙을 생각해 보세요. Panel 204에서 2, 0, 4만 이 범위에 포함됩니다. 글자와 공백은 포함되지 않습니다. 따라서 숫자 때문에 다운로드가 발생해도 폰트가 라벨 전체를 렌더링할 수 있다는 뜻은 아닙니다. MDN 문서에 따르면 사용 가능한 문자가 나타나면 전체 폰트 리소스가 다운로드될 수 있습니다. MDN: unicode-range

이 독립형 JavaScript 예제는 그 차이를 보여줍니다. 별도의 설정 없이 브라우저 콘솔이나 Node.js에서 실행할 수 있습니다. 표시된 예제의 결정적 범위 계산은 실행했습니다.

const text = "Panel 204";
const rows = Array.from(text, character => {
  const value = character.codePointAt(0);
  return {
    character,
    codePoint: "U+" + value.toString(16).toUpperCase().padStart(4, "0"),
    inDeclaredRange: value >= 0x30 && value <= 0x39
  };
});

console.table(rows);

범위에서 필요한 문자가 제외된다면 잘못된 설명자를 수정하거나 필요한 문자를 포함하는 서브셋을 제공하세요. 결과를 확인할 때 원래 문제가 발생한 텍스트를 그대로 사용하세요. 문자열 순회가 셰이핑 테스트라고 가정하지 마세요. 결합 시퀀스에는 클러스터 처리가 필요하며, 표준에서는 필요한 경우 셰이핑 정보를 고려합니다. 렌더링 결과를 비교할 때 시퀀스를 그대로 유지하세요. W3C: 폰트 매칭 및 클러스터 매칭

폰트의 표시 시간이 지났나요?

패밀리와 지원 범위가 올바른 것 같다면 font-display을 확인하세요. optional는 블록 기간이 매우 짧고 스왑 기간이 없습니다. fallback에는 짧은 스왑 기간이 있습니다. 따라서 해당 기간이 지난 뒤 리소스가 도착하면 그 페이지 로드에서는 대체 글꼴이 계속 표시될 수 있습니다. swap은 초기 블록 기간이 지나면 스왑 기간을 무제한으로 허용합니다. MDN: font-display

통제된 진단을 위해 제공되는 스타일시트에서 문제가 있는 규칙을 임시로 font-display: swap으로 변경하고 초기 로드 조건을 다시 적용하세요. 로드가 끝난 뒤 서체가 나타난다면 로딩 시점이 원인이라는 설명을 뒷받침합니다. 이 설정을 유지하기 전에 이후 발생하는 화면 변화를 페이지에 적용해도 괜찮은지 판단하세요. 초기 로드와 캐시된 재로드를 모두 반복하세요. 캐시된 결과만으로는 처음 리소스가 도착한 시점을 재현할 수 없습니다.

라이브러리나 캔버스가 텍스트를 그리면 무엇이 달라지나요?

페이지에서 이미 Font Face Observer를 사용한다면 관찰 대상 패밀리와 weight, style, stretch 옵션을 확인하세요. 문서에 따르면 이 라이브러리는 로더이자 모니터이며, 일반적인 @font-face 규칙이 필요하고 폰트에 기본 테스트 문자가 없을 때는 사용자 지정 테스트 문자열이 필요합니다. 기본 제한 시간은 3초입니다. 옵서버 시간 초과와 브라우저의 font-display 시간은 별개의 조건입니다. Font Face Observer 문서

진단을 통해 추론하면, 옵서버의 성공 메시지 뒤에는 대상 요소를 확인해야 합니다. 한 서체의 사용 가능 여부를 모니터링한다고 해서 요소에 우선 적용되는 CSS가 해당 서체를 요청한다는 뜻은 아닙니다. 어느 서체가 렌더링되었는지가 아직 밝혀지지 않은 상황이라면 로더를 하나 더 설치해도 도움이 되지 않습니다.

캔버스에는 별도의 그리기 경계가 있습니다. 그리기 컨텍스트에는 자체 font 설정이 있으며 초기값은 10px sans-serif입니다. 유효하지 않은 값은 무시됩니다. 따라서 캔버스 요소에 CSS 패밀리를 설정하는 것만으로는 컨텍스트가 해당 폰트를 사용한다고 볼 수 없습니다. 그리기 컨텍스트에 할당된 값과 로딩 및 그리기 작업의 순서를 확인하세요. WHATWG: Canvas 텍스트 스타일

캔버스 텍스트의 경우 의도한 등록 서체가 로드될 때까지 기다린 다음 컨텍스트의 폰트를 설정하고 애플리케이션의 일반적인 그리기 루틴을 사용해 문제가 있는 장면을 다시 그리세요. 이미 그려진 픽셀은 폰트가 도착해도 새 서체로 바뀌지 않습니다. 캔버스 텍스트 준비 과정에서는 가상 무한 너비 줄 상자를 사용하므로 캔버스 테스트에서 성공해도 너비가 제한된 웹페이지 라벨이 같은 방식으로 줄바꿈된다는 뜻은 아닙니다. WHATWG: 텍스트 준비 및 텍스트 그리기

수정 사항을 어떻게 확인하나요?

처음 문제를 발견한 원래 라벨로 돌아가 동일한 관찰을 반복하세요. 원래 로드 조건에서 계산된 요청, 렌더링된 서체, 관련 문자가 올바른지 확인합니다. 캔버스의 경우 비교 전에 다시 그리세요. 요소, 요청된 속성, 실제 렌더링된 서체, 리소스, 성공한 변경 사항을 간단히 기록하세요. 이렇게 하면 진단을 재현할 수 있습니다.

폰트가 사용되지 않은 이유를 설명하고 문제가 있는 텍스트에 의도한 결과가 표시되는 것을 확인할 수 있으면 마무리하세요. 올바른 패밀리 선언, 정확한 서브셋, 등록된 서체, 적절한 표시 정책, 적시에 실행되는 다시 그리기는 각각 서로 다른 경계를 해결합니다. 관찰 결과가 뒷받침하는 수정 방법을 선택하세요.

출처