고른 폰트가 아무리 예뻐도 늦게 뜨면 첫 화면에서 글자가 깜빡이거나 텅 빕니다. 웹폰트는 어떻게 불러오고 언제 보여줄지가 절반입니다. 로딩을 코드로 다뤄 봅니다. 아래 예제는 그대로 확인할 수 있습니다.
57.1 @font-face로 폰트 등록
직접 올린 폰트 파일은 @font-face로 이름을 붙여 등록합니다. 이 이름을 font-family에서 부르면 됩니다.
@font-face {
font-family: "Pretendard";
src: url("/fonts/pretendard.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
body { font-family: "Pretendard", system-ui, sans-serif; }
woff2는 압축률이 가장 좋아 요즘 표준으로 씁니다. 브라우저가 이 파일을 받아 오는 동안 화면을 어떻게 다룰지가 다음 문제입니다.
57.2 font-display로 깜빡임 다스리기
폰트가 오기 전에 글자를 감출지 대체 폰트로 보여줄지는 font-display가 정합니다. 본문은 대개 swap이 무난합니다.
@font-face {
font-family: "Pretendard";
src: url("/fonts/pretendard.woff2") format("woff2");
font-display: swap;
}
swap은 대체 폰트로 먼저 글을 보여주고 웹폰트가 오면 바꿔 끼웁니다. 글자가 안 보이는 시간을 없애는 대신, 폰트가 뒤늦게 바뀌는 깜빡임을 감수하는 선택입니다.
57.3 display 값 골라 쓰기
상황에 따라 다른 값이 낫습니다. 아이콘 폰트는 optional, 꼭 그 폰트여야 하는 로고는 block이 어울립니다.
/* 없어도 그만인 장식 폰트 */
@font-face {
font-family: "Fancy";
src: url("/fonts/fancy.woff2") format("woff2");
font-display: optional;
}
optional은 폰트가 아주 빨리 안 오면 그냥 대체 폰트로 남깁니다. 느린 네트워크에서 늦은 교체로 인한 깜빡임을 아예 막아, 첫 화면이 안정적입니다.
57.4 중요한 폰트는 미리 받기
첫 화면에 바로 필요한 폰트는 브라우저가 늦게 발견하지 않도록 미리 알립니다. head에 preload를 넣습니다.
<link rel="preload" href="/fonts/pretendard.woff2"
as="font" type="font/woff2" crossorigin>
이 한 줄이면 브라우저가 CSS를 다 읽기 전에 폰트를 먼저 챙깁니다. 다만 정말 첫 화면에 쓰는 폰트에만 써야지, 남발하면 다른 자원과 경쟁해 오히려 느려집니다.
57.5 대체 폰트의 크기 맞추기
swap으로 폰트가 바뀔 때 대체 폰트와 크기가 다르면 글이 출렁입니다. size-adjust로 대체 폰트 크기를 미리 맞춰 둡니다.
@font-face {
font-family: "Fallback";
src: local("Arial");
size-adjust: 105%;
ascent-override: 90%;
}
대체 폰트를 웹폰트와 비슷한 덩치로 조정하면 교체 순간 줄 높이와 폭이 덜 흔들립니다. 화면이 툭 밀리는 현상을 눈에 안 띄게 줄이는 방법입니다.
57.6 굵기마다 파일을 나누거나 하나로
굵기별로 파일을 따로 등록하면 필요한 것만 받습니다. 반대로 가변 폰트는 하나에 모든 굵기가 들어 있습니다.
/* 굵기별 개별 파일 */
@font-face {
font-family: "Pretendard";
src: url("/fonts/pretendard-700.woff2") format("woff2");
font-weight: 700;
}
이렇게 두면 400과 700을 각각 받습니다. 굵기를 여러 개 쓸수록 파일이 늘어나 요청이 많아지는 것이 단점입니다.
57.7 가변 폰트 한 파일로
가변 폰트는 한 파일에서 굵기를 연속으로 뽑아 씁니다. 여러 굵기를 쓸수록 개별 파일보다 이득입니다.
@font-face {
font-family: "PretendardVar";
src: url("/fonts/pretendard-var.woff2") format("woff2");
font-weight: 100 900; /* 범위 지정 */
}
.thin { font-weight: 300; }
.bold { font-weight: 650; } /* 중간값도 가능 */
100부터 900까지 한 파일에 담겨 있어 650 같은 어중간한 굵기도 씁니다. 굵기를 세 개 이상 쓰는 화면이라면 대개 가변 폰트가 가볍습니다.
57.8 폰트 자체를 가볍게
파일 크기를 줄이는 가장 확실한 방법은 안 쓰는 글자를 빼는 것입니다. 한글은 글자 수가 많아 부분집합이 특히 효과적입니다.
@font-face {
font-family: "PretendardSub";
src: url("/fonts/pretendard-subset.woff2") format("woff2");
unicode-range: U+AC00-D7A3, U+0041-005A, U+0061-007A;
}
unicode-range로 실제 쓰는 글자 영역만 지정하면 브라우저가 해당 글자가 있을 때만 파일을 받습니다. 완성형 한글과 영문 알파벳만 남겨도 파일이 크게 줄어듭니다.
57.9 CSS로 폰트 로딩 감지
폰트가 실제로 준비됐는지 코드로 확인할 수 있습니다. 로딩 상태에 따라 화면을 살짝 다르게 다루면 깜빡임이 덜 거슬립니다.
/* 로딩 전에는 대체 폰트 기준 자간 보정 */
body { letter-spacing: 0.01em; }
.fonts-loaded body {
letter-spacing: 0;
}
스크립트가 폰트 로딩을 확인해 최상위에 표시 클래스를 붙이면 위 규칙이 켜집니다. 대체 폰트와 웹폰트의 폭 차이를 자간으로 살짝 메워 교체 순간의 출렁임을 줄이는 방식입니다.
57.10 여러 형식 폴백
woff2를 못 읽는 아주 오래된 환경까지 챙기려면 형식을 여러 개 나열합니다. 브라우저가 읽을 수 있는 첫 형식을 고릅니다.
@font-face {
font-family: "Pretendard";
src: url("/fonts/pretendard.woff2") format("woff2"),
url("/fonts/pretendard.woff") format("woff");
font-display: swap;
}
앞의 woff2를 읽을 수 있으면 그걸 쓰고 아니면 woff로 내려갑니다. 요즘은 woff2만으로 충분한 경우가 대부분이지만, 폭넓은 지원이 필요하면 이렇게 겹쳐 둡니다.
57.11 정리
웹폰트는 @font-face로 등록하고 woff2로 받되, font-display로 깜빡임을 다스리고, 첫 화면 폰트는 preload로 앞당기고, 대체 폰트는 size-adjust로 덩치를 맞추는 것이 로딩의 핵심입니다. 굵기를 많이 쓰면 가변 폰트, 글자를 적게 쓰면 부분집합으로 파일을 줄이면 됩니다. 폰트는 고르는 순간이 아니라 뜨는 순간에 완성됩니다.