한국어 웹 폰트 최적화: CLS·LCP를 확실히 잡는 실전 전략

한국어 폰트는 11,172자의 한글 조합 때문에 최적화 없이는 15MB가 넘습니다. font-display, 서브셋, WOFF2, size-adjust, 가변 폰트로 CLS·LCP를 개선하는 2026년 최신 실전 가이드입니다.

한국어 웹 폰트 최적화 가이드 2026: CLS·LCP 해결

앞선 가이드에서 CLS(레이아웃 시프트), LCP(로딩 성능), 리소스 힌트, 서드파티 스크립트 최적화를 차례로 다뤘습니다. 이번에는 많은 개발자가 간과하지만 Core Web Vitals에 막대한 영향을 미치는 요소, 바로 웹 폰트를 깊이 파헤쳐 보겠습니다.

솔직히, 웹 폰트 하나가 성능에 얼마나 영향을 줄까 싶으시죠? 저도 예전엔 그렇게 생각했습니다. 그런데 2025년 Web Almanac 데이터를 보면 상당히 충격적입니다. 분석 대상 웹사이트의 82%가 웹 폰트를 사용하고, 단일 폰트 패밀리 하나가 500KB 이상인 경우도 허다합니다. 특히 한국어 폰트는 11,172자의 한글 조합을 포함해야 하기 때문에, 최적화 없이는 15MB~17MB에 달하는 폰트 파일을 브라우저가 통째로 다운로드해야 합니다.

15메가바이트요. 이미지도 아니고 폰트 하나가요.

이건 단순히 "좀 느려지는" 수준이 아닙니다. LCP를 수백 밀리초에서 수 초까지 지연시키고, 폰트 스왑 과정에서 CLS를 발생시키며, 메인 스레드를 차단해 INP까지 악화시킬 수 있습니다. 2026년 현재 Google이 페이지 경험 신호의 가중치를 높인 상태라서, 웹 폰트 최적화는 선택이 아니라 필수입니다.

웹 폰트가 Core Web Vitals에 미치는 영향

웹 폰트가 성능에 미치는 영향을 제대로 이해하려면, 브라우저가 폰트를 어떻게 처리하는지부터 알아야 합니다. HTML을 파싱하고 CSS를 발견한 브라우저는 폰트 파일을 요청하는데, 이 과정에서 두 가지 렌더링 문제가 발생합니다.

FOIT(Flash of Invisible Text)와 FOUT(Flash of Unstyled Text)

FOIT는 웹 폰트가 로딩될 때까지 텍스트를 아예 보여주지 않는 현상입니다. Chromium 기반 브라우저와 Firefox는 기본적으로 최대 3초간 텍스트 렌더링을 차단하고, Safari는 폰트가 로딩될 때까지 무한정 차단합니다. 사용자 입장에서는 빈 화면을 멍하니 보고 있는 거죠.

FOUT는 폴백 폰트로 먼저 텍스트를 보여준 뒤, 웹 폰트가 로딩되면 교체하는 현상입니다. 텍스트는 즉시 보이지만, 폰트가 바뀌면서 글자 크기와 줄 간격이 달라져 레이아웃이 흔들립니다. 개인적으로 이 "덜컹" 하는 경험이 사용자 체감 품질을 꽤 떨어뜨린다고 봅니다.

이 두 현상이 Core Web Vitals에 미치는 영향을 정리하면 이렇습니다:

  • LCP 악화: 텍스트가 LCP 요소인 경우(히어로 제목, 본문 등), FOIT로 인해 텍스트 렌더링이 지연되면 LCP가 직접적으로 늦어집니다
  • CLS 발생: FOUT로 폰트가 스왑될 때, 폴백 폰트와 웹 폰트의 메트릭(글자 크기, 줄 높이, 자간)이 다르면 텍스트가 리플로우되면서 주변 요소가 밀려납니다
  • FCP 지연: 폰트가 렌더 블로킹 리소스로 작동하면 첫 번째 콘텐츠 페인트 자체가 늦어집니다

font-display: 폰트 렌더링 전략의 핵심

CSS의 font-display 속성은 웹 폰트 로딩 중 브라우저의 동작을 제어하는 가장 기본적이면서 강력한 도구입니다. 각 값의 동작 방식과 성능 영향을 하나씩 살펴보겠습니다.

font-display 속성값 비교

auto는 브라우저 기본 동작에 맡기는 것으로, 대부분의 브라우저에서 FOIT처럼 동작합니다. 예측 불가능하므로 쓸 이유가 없습니다.

block은 최대 3초간 텍스트를 숨기고 그 후에 폴백 폰트로 전환합니다. FOIT를 유발하므로 LCP에 매우 불리합니다.

swap은 즉시 폴백 폰트로 텍스트를 보여주고, 웹 폰트가 로딩되면 교체합니다. LCP에는 유리하지만 CLS 위험이 있습니다.

fallback은 약 100ms간 텍스트를 숨기고, 폴백 폰트로 전환한 뒤 약 3초 내에 웹 폰트가 로딩되면 교체합니다. swap과 optional의 중간 지점이라고 보면 됩니다.

optional은 약 100ms간 텍스트를 숨기고, 그 시간 내에 웹 폰트가 로딩되지 않으면 현재 페이지에서는 폴백 폰트만 사용합니다. CLS가 거의 없는 대신, 첫 방문 시 커스텀 폰트가 안 보일 수 있습니다.

/* 권장: 본문 텍스트에는 optional, 제목에는 swap */
@font-face {
  font-family: 'Noto Sans KR';
  src: url('/fonts/NotoSansKR-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: optional; /* CLS 방지 우선 */
}

@font-face {
  font-family: 'Noto Sans KR';
  src: url('/fonts/NotoSansKR-Bold.woff2') format('woff2');
  font-weight: 700;
  font-display: swap; /* 제목은 스왑해도 CLS 영향 적음 */
}

실전 팁 하나 드리자면, 본문 텍스트처럼 긴 텍스트 블록에는 font-display: optional을 사용하세요. 폰트가 스왑되면 여러 줄에 걸쳐 리플로우가 발생해 CLS 영향이 생각보다 큽니다. 반면 제목이나 한 줄짜리 요소에는 swap을 써도 레이아웃 시프트가 거의 없습니다.

한국어 폰트의 특수한 도전 과제

한국어 웹 폰트 최적화가 영문 폰트보다 훨씬 까다로운 이유는 명확합니다. 영문 알파벳은 26자(대소문자 포함 52자)이지만, 한글은 자음 14개 × 모음 10개 × 받침 28개(+없음)의 조합으로 총 11,172자가 됩니다.

이 차이가 파일 크기에 고스란히 반영됩니다:

  • 영문 폰트(예: Inter): WOFF2 기준 약 20~100KB
  • 한국어 폰트(예: Noto Sans KR): 최적화 없이 4.7MB~17MB
  • 차이: 50배~170배

3G 네트워크(약 1.5Mbps)에서 5MB 폰트를 다운로드하려면 약 26초가 걸립니다. 4G에서도 2~3초고요. 이러면 아무리 서버 사이드를 최적화해도 의미가 없어집니다.

서브셋 폰트: 용량을 90% 이상 줄이는 핵심 전략

서브셋(Subset) 폰트는 전체 글리프 중 실제로 필요한 문자만 추출한 경량 폰트입니다. 한국어 폰트 최적화에서 가장 효과가 큰 기법이고, 솔직히 이것 하나만 적용해도 체감 차이가 큽니다.

KS X 1001 기반 서브셋

한국산업표준 KS X 1001에는 자주 사용되는 한글 2,350자가 정의되어 있습니다. 11,172자에서 2,350자로 줄이면 파일 크기가 극적으로 감소합니다:

  • Noto Sans KR Regular 원본: 4.7MB (OTF)
  • KS X 1001 서브셋 + WOFF2: 200~400KB
  • 절감률: 약 92~95%

4.7MB가 200KB로 줄어드는 겁니다. 이 정도면 안 할 이유가 없죠.

pyftsubset으로 서브셋 만들기

fontTools의 pyftsubset은 폰트 서브셋 생성에 가장 널리 쓰이는 도구입니다:

# fontTools 설치
pip install fonttools brotli

# KS X 1001 기반 서브셋 + WOFF2 변환
pyftsubset NotoSansKR-Regular.otf \
  --text-file=korean-chars.txt \
  --output-file=NotoSansKR-Regular-subset.woff2 \
  --flavor=woff2 \
  --layout-features='*' \
  --desubroutinize

--desubroutinize 옵션은 WOFF2 압축 효율을 높여주는데, 이거 빼먹으면 좀 아깝습니다. 이 옵션만으로 파일 크기가 5~15% 추가로 줄어듭니다.

unicode-range로 온디맨드 로딩

unicode-range는 CSS @font-face에서 폰트가 적용될 유니코드 범위를 지정하는 속성입니다. 여기서 핵심은 페이지에 해당 범위의 문자가 없으면 브라우저가 폰트 파일을 아예 다운로드하지 않는다는 점입니다. 꽤 똑똑하죠?

/* 한글 음절만 포함하는 서브셋 */
@font-face {
  font-family: 'Noto Sans KR';
  src: url('/fonts/NotoSansKR-subset-hangul.woff2') format('woff2');
  unicode-range: U+AC00-D7AF; /* 한글 음절 블록 */
  font-display: swap;
}

/* 라틴 문자용 서브셋 */
@font-face {
  font-family: 'Noto Sans KR';
  src: url('/fonts/NotoSansKR-subset-latin.woff2') format('woff2');
  unicode-range: U+0020-007E; /* 기본 라틴 */
  font-display: swap;
}

Google Fonts는 이 원리를 극대화합니다. 머신러닝으로 한국어 웹 문서의 글자 사용 패턴을 분석한 뒤, 17,388개 글리프를 약 120개 그룹으로 나눠서 unicode-range 기반으로 제공하거든요. 페이지에 실제 사용된 글자 그룹만 다운로드되니까 전체 폰트 대비 약 90%의 전송량 절감 효과가 있습니다.

WOFF2: 2026년의 표준 폰트 포맷

2026년 기준으로 WOFF2는 전 세계 브라우저의 97% 이상에서 지원됩니다. IE11 지원을 완전히 종료한 지금, WOFF2 하나만 써도 됩니다. 진지하게, 다른 포맷은 이제 필요 없습니다.

WOFF2가 다른 포맷보다 나은 이유:

  • Brotli 기반 압축으로 WOFF 대비 약 30% 더 작은 파일 크기
  • OTF/TTF 대비 50~70% 용량 절감
  • 브라우저 디코딩 속도도 빠름
/* 2026년 권장: WOFF2 단일 포맷 */
@font-face {
  font-family: 'Noto Sans KR';
  src: local('Noto Sans KR'),
       url('/fonts/NotoSansKR-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}

/* WOFF 폴백이 필요한 경우 (매우 드묾) */
@font-face {
  font-family: 'Noto Sans KR';
  src: local('Noto Sans KR'),
       url('/fonts/NotoSansKR-Regular.woff2') format('woff2'),
       url('/fonts/NotoSansKR-Regular.woff') format('woff');
  font-weight: 400;
  font-display: swap;
}

local()을 먼저 선언하면, 사용자 시스템에 해당 폰트가 이미 설치되어 있을 때 네트워크 요청 자체를 건너뜁니다. 작은 디테일이지만 효과적입니다.

가변 폰트(Variable Fonts)로 HTTP 요청 줄이기

전통적인 방식에서는 Regular, Bold, Light 등 각 굵기(weight)마다 별도의 폰트 파일이 필요합니다. 4개 굵기를 쓴다면 HTTP 요청 4번에 다운로드 용량도 4배죠.

가변 폰트(Variable Font)는 이 문제를 근본적으로 해결합니다. 하나의 파일에 모든 굵기·너비·기울기 변형이 포함되어 있어서, 파일 하나로 거의 무한한 스타일을 표현할 수 있습니다.

가변 폰트의 성능 이점

  • HTTP 요청 감소: 4~6개 파일 → 1개 파일
  • 총 용량 절감: 개별 파일 합계보다 가변 폰트 1개가 더 작은 경우가 많음
  • 디자인 유연성: font-weight를 100 단위가 아닌 1 단위로 세밀하게 조절 가능
/* 가변 폰트 선언 */
@font-face {
  font-family: 'Noto Sans KR Variable';
  src: url('/fonts/NotoSansKR-VF.woff2') format('woff2-variations');
  font-weight: 100 900; /* 가변 범위 지정 */
  font-display: swap;
}

/* 사용 시 원하는 굵기를 자유롭게 지정 */
body {
  font-family: 'Noto Sans KR Variable', sans-serif;
  font-weight: 350; /* 전통 폰트에서는 불가능한 세밀한 조절 */
}

h1 {
  font-weight: 800;
}

/* font-variation-settings로 더 세밀한 제어 */
.custom-text {
  font-variation-settings: 'wght' 450, 'wdth' 95;
}

다만, 한국어 가변 폰트는 영문 가변 폰트보다 파일 크기가 여전히 크다는 점을 기억하세요. 그래서 서브셋 + 가변 폰트 조합이 현실적으로 가장 효과적입니다.

size-adjust와 폰트 메트릭 오버라이드: CLS 제로를 향해

font-display: swap을 쓰면 텍스트가 즉시 보여서 좋은데, 문제가 하나 있습니다. 폴백 폰트에서 웹 폰트로 교체될 때 두 폰트의 메트릭 차이 때문에 레이아웃이 덜컹거립니다. 이걸 해결하는 게 CSS 폰트 메트릭 디스크립터입니다.

핵심 디스크립터 4가지

  • size-adjust: 글리프의 전체 크기를 스케일링하는 백분율. 폴백 폰트의 글자 크기를 웹 폰트에 맞춥니다
  • ascent-override: 베이스라인 위 글리프 높이를 재정의. 웹 폰트의 ascender 값에 맞춥니다
  • descent-override: 베이스라인 아래 글리프 높이를 재정의
  • line-gap-override: 줄 간격(line gap)을 재정의
/* 웹 폰트 선언 */
@font-face {
  font-family: 'Noto Sans KR';
  src: url('/fonts/NotoSansKR-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}

/* 폴백 폰트에 메트릭 오버라이드 적용 */
@font-face {
  font-family: 'Noto Sans KR Fallback';
  src: local('Apple SD Gothic Neo'), local('Malgun Gothic');
  size-adjust: 100.5%;
  ascent-override: 105%;
  descent-override: 30%;
  line-gap-override: 0%;
}

/* 폰트 스택에서 함께 사용 */
body {
  font-family: 'Noto Sans KR', 'Noto Sans KR Fallback', sans-serif;
}

이렇게 하면 폴백 폰트(Apple SD Gothic Neo 또는 맑은 고딕)의 메트릭이 Noto Sans KR과 거의 일치하게 조정되어, 폰트 스왑 시 레이아웃 시프트가 크게 줄어듭니다.

정확한 size-adjust 값을 구하려면 두 폰트의 unitsPerEm과 ascender/descender 값을 비교해야 합니다. 예를 들어 웹 폰트의 unitsPerEm = 1000이고 ascender = 1068이면, ascent-override: 106.8%로 설정하면 됩니다. (수학이 좀 필요하지만 한 번만 계산하면 되니까 참으세요.)

폰트 프리로딩: LCP를 수백 밀리초 단축하기

<link rel="preload">는 브라우저에게 "이 리소스를 최우선으로 다운로드하라"고 지시합니다. 폰트는 보통 CSS가 파싱된 후에야 발견되는데, 프리로딩을 사용하면 HTML 파싱 단계에서 즉시 다운로드를 시작하니까 꽤 유의미한 시간을 아낄 수 있습니다.

<!-- 가장 중요한 폰트만 프리로드 (1~2개 권장) -->
<link
  rel="preload"
  href="/fonts/NotoSansKR-Regular.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>

여기서 꼭 주의할 점들:

  • crossorigin 속성을 반드시 추가하세요. 폰트는 항상 CORS 모드로 요청되는데, 이 속성이 빠지면 폰트가 두 번 다운로드되는 황당한 상황이 발생합니다
  • 프리로드는 가장 중요한 1~2개 폰트에만 적용하세요. 욕심부려서 이것저것 프리로드하면 오히려 다른 중요 리소스의 로딩이 밀립니다
  • ATF(Above-The-Fold) 콘텐츠에 사용되는 폰트를 우선적으로 프리로드하세요

셀프 호스팅 vs Google Fonts: 2026년의 최적 선택

Google Fonts를 CDN에서 바로 쓰는 것과 셀프 호스팅하는 것, 어떤 게 나을까요? 결론부터 말하면, 상황에 따라 다릅니다. (뻔한 답처럼 들리겠지만, 이번엔 진짜 그렇습니다.)

셀프 호스팅이 유리한 이유

  • 연결 비용 제거: Google Fonts 서버(fonts.googleapis.com, fonts.gstatic.com)에 대한 DNS 조회, TCP 연결, TLS 핸드셰이크 비용이 사라집니다. 이것만으로 200~500ms를 절약할 수 있습니다
  • HTTP/2·HTTP/3 활용: 같은 도메인에서 폰트를 제공하면 기존 연결을 재사용할 수 있습니다
  • 캐싱 제어: 브라우저 캐시 정책을 직접 설정할 수 있습니다. Cache-Control: public, max-age=31536000, immutable로 1년간 캐싱이 가능하죠
  • 프라이버시: 사용자 데이터가 Google 서버로 전송되지 않습니다. GDPR 준수 측면에서 훨씬 편합니다

Google Fonts API가 유리한 경우

  • 한국어 동적 서브셋: Google Fonts는 머신러닝 기반으로 한국어 폰트를 약 120개 그룹으로 분할합니다. 이 수준의 정밀한 unicode-range 분할을 직접 구현하는 건 솔직히 꽤 고된 작업입니다
  • Incremental Font Transfer: Google Fonts 팀이 W3C와 함께 개발 중인 차세대 기술로, 화면에 표시되는 글리프만 스트리밍 방식으로 로드합니다. 이 기술이 브라우저에 탑재되면 Google Fonts API 사용자가 자동으로 혜택을 받게 됩니다

제가 실무에서 추천하는 전략은 이렇습니다. 영문 폰트는 셀프 호스팅, 한국어 폰트는 Google Fonts CSS API v2를 사용하되 font-display=swap 파라미터를 추가하는 하이브리드 접근법입니다.

<!-- Google Fonts CSS API v2 + font-display 설정 -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;700&display=swap"
  rel="stylesheet"
/>

셀프 호스팅을 선택한다면 korsubset이나 font-range 같은 오픈소스 도구로 Google Fonts와 비슷한 수준의 unicode-range 분할을 구현할 수 있습니다.

프레임워크별 폰트 최적화 자동화

Next.js (next/font)

Next.js의 next/font는 2026년 현재 가장 진보된 폰트 최적화 시스템이라고 해도 과언이 아닙니다. 빌드 타임에 Google Fonts를 다운로드해서 셀프 호스팅하고, size-adjust를 자동으로 계산하며, 폰트 서브셋도 알아서 적용합니다. 개발자가 할 일이 거의 없어요.

// app/layout.tsx
import { Noto_Sans_KR } from 'next/font/google';

const notoSansKR = Noto_Sans_KR({
  subsets: ['latin'],  // 한국어는 자동 dynamic subset 적용
  weight: ['400', '700'],
  display: 'swap',
  adjustFontFallback: true,  // size-adjust 자동 계산
  preload: true,
});

export default function RootLayout({ children }) {
  return (
    <html lang="ko" className={notoSansKR.className}>
      <body>{children}</body>
    </html>
  );
}

adjustFontFallback: true가 핵심입니다. 이 한 줄이 폴백 폰트의 size-adjust, ascent-override, descent-override를 자동으로 계산해서 CLS를 거의 제로로 만들어 줍니다.

Nuxt 3

Nuxt 3에서는 @nuxtjs/fontaine 모듈이 비슷한 역할을 합니다:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/fontaine'],
  fontMetrics: {
    fonts: ['Noto Sans KR'],
  },
});

실전 체크리스트: 지금 바로 적용하세요

자, 여기까지 읽으셨다면 이론은 충분합니다. 이제 실제로 뭘 해야 하는지 우선순위대로 정리해 드리겠습니다:

  1. WOFF2 포맷 사용: 아직 TTF나 OTF, WOFF를 쓰고 계신다면 지금 바로 WOFF2로 바꾸세요. 이것만으로 30~50% 용량이 줄어듭니다
  2. font-display 설정: 모든 @font-facefont-display: swap 또는 optional을 추가하세요
  3. 서브셋 적용: 한국어 폰트는 반드시 서브셋을 만들거나 Google Fonts API v2의 동적 서브셋을 활용하세요
  4. 필요한 굵기만 로드: 실제 사용하는 font-weight만 선언하세요. 안 쓰는 굵기를 로드하는 건 대역폭 낭비입니다
  5. 프리로드 적용: ATF 콘텐츠에 사용되는 폰트 1~2개를 <link rel="preload">로 프리로드하세요
  6. 폰트 메트릭 매칭: size-adjustascent-override로 폴백 폰트의 메트릭을 웹 폰트에 맞추세요
  7. 캐싱 설정: 폰트 파일에 Cache-Control: public, max-age=31536000, immutable 헤더를 설정하세요

1번부터 3번까지만 적용해도 체감 성능이 확연히 달라질 겁니다.

성능 측정과 모니터링

최적화를 했으면 효과를 숫자로 확인해야겠죠. 다음 도구들을 활용해 보세요:

  • Chrome DevTools: Network 탭에서 폰트 파일의 크기와 로딩 시간을 확인합니다. Performance 패널에서는 CLS와 LCP에 대한 폰트의 영향을 직접 볼 수 있습니다
  • Lighthouse: "Ensure text remains visible during webfont load" 경고가 뜨면 font-display가 빠져 있는 겁니다
  • WebPageTest: Waterfall 차트에서 폰트 다운로드 타이밍과 텍스트 렌더링 시점을 시각적으로 비교할 수 있습니다
  • CrUX(Chrome User Experience Report): 실제 사용자 데이터 기반의 CLS, LCP 점수를 확인합니다. PageSpeed Insights에서도 같은 데이터를 볼 수 있습니다

자주 묻는 질문 (FAQ)

font-display: swap과 optional 중 어떤 걸 써야 하나요?

CLS를 최우선으로 고려한다면 optional이 확실히 유리합니다. 첫 방문 시 커스텀 폰트가 안 보일 수 있다는 단점이 있지만, 레이아웃 시프트가 거의 없습니다. 브랜드 아이덴티티 때문에 커스텀 폰트가 반드시 보여야 한다면 swap을 쓰되, size-adjust로 폴백 폰트 메트릭을 맞춰서 CLS를 최소화하세요. 저는 하이브리드 전략(본문 optional, 제목 swap)을 가장 자주 씁니다.

한국어 웹 폰트를 셀프 호스팅하는 게 나은가요, Google Fonts를 쓰는 게 나은가요?

한국어 폰트의 경우, Google Fonts CSS API v2의 머신러닝 기반 동적 서브셋이 워낙 잘 되어 있어서 대부분의 프로젝트에서는 Google Fonts가 더 편리하고 효율적입니다. 단, GDPR 같은 프라이버시 규정 준수, 오프라인 지원, 또는 극한의 성능 튜닝이 필요하다면 셀프 호스팅을 선택하고 korsubset이나 font-range 같은 도구로 서브셋을 직접 만드는 게 맞습니다.

가변 폰트를 사용하면 일반 폰트보다 항상 빠른가요?

아뇨, 항상 그런 건 아닙니다. 한 가지 굵기만 쓴다면 일반 폰트가 오히려 더 작습니다. 가변 폰트가 유리해지는 건 3개 이상의 굵기를 사용할 때부터입니다. 그리고 한국어 가변 폰트는 아직 영문 가변 폰트보다 파일이 꽤 크므로, 반드시 서브셋과 함께 쓰세요.

preload를 사용하면 폰트 렌더링이 얼마나 빨라지나요?

일반적으로 200~500ms의 LCP 개선 효과가 있습니다. 폰트 파일은 보통 CSS가 파싱된 후에야 발견되는데, preload를 쓰면 HTML 파싱 단계에서 바로 다운로드를 시작하니까 이 지연이 통째로 사라집니다. 다만 프리로드할 폰트는 1~2개로 제한하세요. 과도한 프리로드는 네트워크 대역폭 경쟁을 유발해서 역효과가 납니다.

size-adjust로 CLS를 완전히 제거할 수 있나요?

size-adjust, ascent-override, descent-override를 사용하면 수직 방향의 레이아웃 시프트는 거의 제거할 수 있습니다. 하지만 문자 간격(letter-spacing)과 단어 간격(word-spacing)은 이 디스크립터로 조절할 수 없기 때문에, 긴 텍스트 블록에서 줄바꿈 위치가 달라져 미세한 높이 변화가 남을 수 있습니다. 완벽한 CLS 제로가 목표라면, font-display: optional이 사실상 유일한 답입니다.

저자 소개 Yuki Tanabe

Yuki is a senior web performance consultant based in Berlin with 13 years in the trade. She did five years at Akamai as a solutions architect for European media customers, tuning CDN configs and edge cache rules for newspapers handling 8-figure daily pageviews, then moved to Zalando as a staff engineer on the Mobile Web Performance squad. There she ran the project that cut JavaScript shipped to product detail pages by 41% without losing any tracking signals the marketing org cared about. She holds the Google Mobile Web Specialist cert (back when it existed) and contributes occasionally to the web-vitals npm package. Her writing tends to focus on perf budgets that actually survive contact with a product roadmap, image pipeline strategy beyond just slapping on AVIF, and the unglamorous work of getting RUM into a CI pipeline that PMs will read.