프로젝트 최적화(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-plugin 과 html-webpack-plugin이다.
프로젝트에 사용 된 Next.js 14버전은 번들러로 webpack이 아니라 Turbopack을 사용하기 때문에, 해당 플러그인 사용은 어려울 것으로 예상되는데, 🤔 어떻게 진행해야 할지는 실제로 적용해보면서 확인해야 할듯 하다. (내용 추가 예정!)
📩마무리
추가적으로, font prelaod에 대해 알아보다 “장점만 있는 것 같은데 왜 preload가 default 값이 아닌거지?”라는 의문이 들었다.🤔
그 이유는, 첫째로, 모든 폰트 리소스를 미리 로드하면 사용자의 대역폭을 낭비할 수 있기 때문이데, 사용자가 로드하려는 그 폰트가 필요하지 않을 수 있기 때문이다. 둘째로, 로딩 시간 최적화를 위해 브라우저가 로딩할 리소스의 우선순위 결정이 중요하기 때문이다.
즉 preload가 항상 모든 상황에 최적이 아니기 때문에, 페이지 성능과 사용자 경험을 고려하고 리소스에 대해 preload를 사용해야 하는 것이다.
대역폭: 네트워크에서 데이터를 전송하는 데이터의 최대 전달 용량
저번 memo 때도 그렇지만, 최적화 기법이라고 모든 상황에서 사용하는 것이 옳은 것은 아니라는 점에 주의해야 하구나 생각했다.😎