웹 폰트 최적화
웹 폰트는 네트워크를 통해 다운로드되기 때문에,
다운로드 사이즈를 줄이거나, 폰트 적용 시점을 조절해 최적화할 수 있다.
예제 상황
네트워크 설정을 Fast 4G로 설정하고 테스트했다.
- 폰트 사이즈: 1.9MB
- 로드 시간: 11.76초
- 문제: 페이지가 로드된 후 약 12초 뒤에야 폰트가 적용됨
웹 폰트 최적화해야 하는 이유
네트워크 상황에 따라 느리게 폰트가 적용될 가능성이 있으며, 다음과 같은 문제가 생길 수 있다.
- 폰트가 깜빡인다. (기본 폰트 → 커스텀 폰트로 변경되는 과정에서의 깜빡임)
- 다른 요소를 밀어낼 수 있다.
폰트 렌더링 방식 (FOUT vs FOIT)
폰트는 "다운로드가 완료된 시점"에 적용된다.
그럼 다운로드 전까지 텍스트는 어떻게 보일까?
FOUT | 기본 폰트를 먼저 보여주고, 커스텀 폰트 로드 후 교체됨 |
FOIT | 커스텀 폰트가 로드될 때까지 텍스트가 숨겨짐 |
사실, FOIT 방식이라고 해서 다운로드될 때까지 안보이는 것은 아니다.
timeout(n초) 기다린 후 다운로드 되지 않는다면 일단 기본 폰트를 보여주고, 완료되면 폰트를 적용한다.
아래에서 자세히 설명하니 넘어가도 된다.
브라우저 기본 동작
- FOUT: IE, Edge
- FOIT: Chrome, Safari, Firefox
폰트 최적화 방법
- 폰트 적용 시점 제어 (FOUT or FOIT)
- 폰트 용량 최적화
1. 폰트 적용 시점 제어 – font-display
@font-face에서 font-display 속성을 사용하여 폰트 표시 방식을 제어할 수 있다.
속성 값 5가지 요약
auto | 브라우저 기본값 | |
block | FOIT (3초) | 3초간 텍스트 숨김 → 이후 기본 폰트 적용, 다운로드 완료되면 교체 |
swap | FOUT | 기본 폰트 → 커스텀 폰트 |
fallback | FOIT (0.1초) | 0.1초 후 기본 폰트 적용, 이후 캐시로 빠르게 교체 |
optional | FOIT (0.1초 + 네트워크 상황 반영) | fallback과 유사하지만, 네트워크가 느릴 경우 커스텀 폰트 적용 안함 (구글 권장 방식) |
참고) 3초는 브라우저에 따라 다른 값을 가질 수 있음
정리
- swap: FOUT 방식 – 깜빡이지만 빠르게 텍스트 표시
- block, fallback, optional: FOIT 방식
- block: 3초 대기
- fallback, optional: 0.1초 대기 후 기본 폰트 표시
- optional: 네트워크 상태 고려 → 구글 권장
실제 적용
참고로 나는 배너의 텍스트라 덜 중요하다고 판단하여, 느슨한 timeout을 가진 FOIT 방식인 block을 선택했다.
폰트에 애니메이션 적용
block 설정한 경우, 갑자기 '뿅' 하고 나오기 때문에 부자연스럽다고 느낄 수 있다.
따라서 폰트에 서서히 나타나는 애니메이션을 적용하여 부드럽게 나올 수 있도록 설정했다.
- opacity, transition 활용
우선 폰트가 다운로드 완료된 시점을 알아야 한다.
왜냐하면 폰트가 다운로드되면 커스텀 폰트로 적용이 될 것이기 때문에, 그 시점에 opacity를 0 → 1로 변경하면서 애니메이션을 적용할 예정이기 때문이다.
다행히도, 폰트의 로드된 시점을 알려주는 라이브러리 fontfaceobserver가 있다.
설치
npm i fontfaceobserver
폰트 로드되는 시점 감지
// BannerVideo.js
import FontFaceObserver from "fontfaceobserver";
import React, { useEffect, useState } from "react";
function BannerVideo() {
const [fontLoaded, setFontLoaded] = useState(false);
useEffect(() => {
const font = new FontFaceObserver("BMYEONSUNG");
font.load(null, 10000) // 10초 타임아웃
.then(() => {
setFontLoaded(true);
})
}, []);
return (
<div className="BannerVideo">
{fontLoaded && (
<div style={{ opacity: fontLoaded ? 1 : 0, transition: "opacity 0.3s ease-in-out" }}>
TEXT TEXT TEXT TEXT
</div>
)}
</div>
);
}
폰트에 애니메이션 적용
- 폰트가 로드되자마자 opacity를 1로 변경
- opacity: 0 → 1로, transition 애니메이션 적용하여 서서히 나타나도록 설정