Post

프로젝트 최적화(4) - 폰트 최적화

📌시작하며

이번에는 폰트를 최적화해보자.😎 Next.js의 경우 Next/font를 이용해 최적화 된 폰트를 사용할 수 있는데, 이번에 진행한 프로젝트에서는 로컬 폰트를 사용하면서 다른 방식의 폰트 최적화의 필요성을 느꼈다. 어떤 방법이 있는지 알아보고 프로젝트에 적용해보고자 한다.

✅확장자별 폰트 사이즈

지난번 동영상, 이미지에서도 알아봤던 것 처럼, 최적화의 기본, ‘용량 줄이기’를 위해 어떤 폰트 확장자를 사용하면 용량을 줄일 수 있는지 살펴보자.

WOFF2 → WOFF → TTF → SVG → EOT

기본적으로는 다음과 같은 순서대로 파일 용량이 크다.

  • WOFF2 (Web Open Font Format 2): WOFF의 최신 버전으로, 더 효율적으로 파일이 압축되어 있다.
  • WOFF (Web Open Font Format): 웹에서 사용되는 가벼운 폰트 형식이다.
  • TTF (TrueType Font): 웹에서 널리 사용되는 폰트 형식 중 하나다.
  • SVG (Scalable Vector Graphics): 이미지로서의 텍스트를 포함하므로, 크기가 상대적으로 크고 다운로드 속도가 느릴 수 있다.
  • EOT (Embedded OpenType): 마이크로소프트에서 제작한 폰트형식으로, 현재는 거의 사용되지 않는다.

✅@font-face src

@font-face의 src 속성을 이용해 브라우저가 사용가능한 더 가벼운 형식의 폰트부터 불러와 페이지의 로딩 속도를 개선할 수 있다.

*이때 ttf의 경우 format이 truetype임에 주의한다.

1
2
3
4
5
@font-face {
  font-family: "MyWebFont";
  src: url("font.woff2") format("woff2"), url("font.woff") format("woff"),
    url("font.ttf") format("truetype");
}

✅폰트 로드 방식

font-display 속성은 웹 폰트가 로드되는 동안 브라우저가 어떻게 텍스트를 표시할지 결정하고, 웹 폰트의 로드 시간 동안 발생하는 FOIT(Flash of Invisible Text) 또는 FOUT(Flash of Unstyled Text)를 제어해 사용자 경험을 향상시킬 수 있다.

➡️FOIT과 FOUT

FOIT (Flash of Invisible Text): FOIT은 웹 폰트가 로드되는 동안 브라우저가 해당 텍스트를 숨기는(보이지 않는) 현상을 말한다. 따라서 사용자는 폰트가 로드되기 전에는 폰트가 사용된 부분을 빈 공간으로 인식할 수 있다.

FOUT (Flash of Unstyled Text): FOUT는 웹 폰트가 로드되기 전에 브라우저가 기본 폰트를 사용하여 텍스트를 표시한 다음, 웹 폰트로 교체하는 현상을 말한다. 즉 사용자는 기본 글꼴 → 폰트가 적용된 글꼴 로 변환하는 과정에서 깜빡임을 느낄 수 있다.

➡️@font-display

CSS를 이용해 폰트가 로드되는 방식을 변경할 수 있다.

속성설명
auto브라우저 기본 동작을 따른다.
(폰트의 다운로드가 완료되기 전까지 대체 폰트로 텍스트를 표시하다가
폰트 다운로드가 완료되면 폰트를 교체한다.)
block폰트가 다운로드될 때까지 텍스트를 표시하지 않는다.
swap폰트가 다운로드될 때까지 대체 폰트를 사용하다가, 다운로드 이후 교체한다.
fallback사용자에게 텍스트를 빠르게 표시하고자 유사한 폰트로 텍스트를 표시한 다음,
폰트 다운로드가 완료되면 폰트를 교체한다.
@font-face {
  font-family: ExampleFont;
  src:
    url(/path/to/fonts/examplefont.woff) format("woff"),
    url(/path/to/fonts/examplefont.eot) format("eot");
  font-weight: 400;
  font-style: normal;
  font-display: fallback;👈
}

✅Font Subset

폰트 서브셋이란, 전체 폰트 파일에서 자주 사용되는 글자 일부에 대한 폰트파일이다. 파일 용량을 적게 유지할 수 있어, 페이지 로드 시간을 줄일 수 있다.

예를 들어, 한국어 ‘가’, ‘을’, ‘은’ 등은 우리 문장에서 자주 사용되는 글자이다. 하지만 ‘뷃’ ‘뢗’과 같은 글자는 거의 사용되지 않음을 알 수 있다.🤔

이렇게 특수한 상황이 아닌 이상 사용되지 않는 글자는 폰트 파일의 대응에서 제외하는 것이다.

이러한 특성으로 다국어모드를 지원할때도 이 기능을 유용하게 사용할 수 있는데, 다국어 웹 페이지의 경우 여러 언어의 텍스트를 포함할 수 있으므로, 사용자 언어 환경에 따라 필요한 언어 폰트 서브셋을 동적으로 제공하여, 로드 시간을 최적화 할 수 있기 때문이다.

적용 방법은 @font-face를 통해 subset 폰트를 적용해주면 끝이다.

1
2
3
4
5
6
7
@font-face {
  font-family: ExampleFont;
  src: url("path/to/font_subset.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: fallback;
}

✅Preload

Font Preload는 웹페이지에서 폰트 리소스를 브라우저가 미리 로드하는 속성으로, 페이지 렌더링 전에 폰트 파일이 미리 다운로드되어 사용자 경험을 향상시킬 수 있다.

위에서 살펴본 FOUT을 방지하고자 하려면 즉시 필요한 웹 글꼴을 미리 로드하면 된다! rel="preload"를 사용해 preload 해보자.

FOUT: 웹 폰트가 로드되기 전에 브라우저가 기본 폰트를 사용하여 텍스트를 표시한 다음, 웹 폰트로 교체하는 현상

1
2
3
4
5
6
7
8
9
10
<head>
  <!-- ... -->
  <link
    rel="preload👈"
    href="/assets/Pacifico-Bold.woff2"
    as="font"
    type="font/woff2"
    crossorigin
  />
</head>

CRA로 만든 리액트 프로젝트의 경우 plugin을 사용해서 preload 하기도 하는데, stack overflow나 npm 사이트에서 찾은 유용해보이는 plugin은 webpack-font-preload-pluginhtml-webpack-plugin이다.

프로젝트에 사용 된 Next.js 14버전은 번들러로 webpack이 아니라 Turbopack을 사용하기 때문에, 해당 플러그인 사용은 어려울 것으로 예상되는데, 🤔 어떻게 진행해야 할지는 실제로 적용해보면서 확인해야 할듯 하다. (내용 추가 예정!)

📩마무리

추가적으로, font prelaod에 대해 알아보다 “장점만 있는 것 같은데 왜 preload가 default 값이 아닌거지?”라는 의문이 들었다.🤔

그 이유는, 첫째로, 모든 폰트 리소스를 미리 로드하면 사용자의 대역폭을 낭비할 수 있기 때문이데, 사용자가 로드하려는 그 폰트가 필요하지 않을 수 있기 때문이다. 둘째로, 로딩 시간 최적화를 위해 브라우저가 로딩할 리소스의 우선순위 결정이 중요하기 때문이다.

즉 preload가 항상 모든 상황에 최적이 아니기 때문에, 페이지 성능과 사용자 경험을 고려하고 리소스에 대해 preload를 사용해야 하는 것이다.

대역폭: 네트워크에서 데이터를 전송하는 데이터의 최대 전달 용량

저번 memo 때도 그렇지만, 최적화 기법이라고 모든 상황에서 사용하는 것이 옳은 것은 아니라는 점에 주의해야 하구나 생각했다.😎

🗂️참고 사이트

This post is licensed under CC BY 4.0 by the author.