웹폰트는 웹사이트의 디자인과 브랜드 정체성을 강화하는 데 중요한 역할을 하지만, 동시에 웹 성능에 영향을 미칠 수 있다. 웹폰트를 사용하는 경우, 사용자의 브라우저는 폰트를 서버에서 다운로드해야 하며, 이 과정이 페이지 로딩 속도에 영향을 미칠 수 있다.
특히, 웹폰트 파일의 크기가 크거나 여러 종류의 웹폰트를 로드해야 하는 경우, 폰트 다운로드 시간이 길어져 텍스트 콘텐츠가 표시되기까지 지연되는 FOIT(Fallback On Invisible Text) 또는 FOUT(Flash of Unstyled Text) 현상이 발생할 수 있다. 이는 사용자 경험을 저하시킬 뿐 아니라 웹사이트의 첫인상을 악화시킬 위험이 있다.
게다가, 특정 폰트 형식(WOFF2, WOFF, TTF 등)이 브라우저에 따라 지원되지 않을 수 있기 때문에, 여러 형식을 준비해야 하며 이는 추가적인 리소스 관리 부담으로 이어질 수 있다. 웹폰트 최적화는 이러한 문제를 완화하는 데 핵심적인 역할을 한다.

웹폰트가 다운로드되는 동안 텍스트 콘텐츠를 화면에 표시하지 않고 대기 상태로 유지하다가, 웹폰트 다운로드가 완료되면 해당 폰트가 적용된 텍스트 콘텐츠를 보여주는 현상이다. 이로 인해 사용자는 한동안 빈 화면을 보게 되어 사용자 경험이 저하될 수 있다.
웹폰트가 다운로드되기 전까지 브라우저의 기본 폰트를 사용해 텍스트 콘텐츠를 먼저 표시하고, 웹폰트가 다운로드되면 이후 웹폰트가 적용된 텍스트 콘텐츠로 대체되는 현상이다. 이로 인해 텍스트의 스타일이 갑작스럽게 변경되는 느낌을 줄 수 있어 일관된 사용자 경험을 방해할 수 있다.
웹폰트의 다운로드 완료 시점에 따라 텍스트의 표시 방식을 제어하려면 font-display CSS 속성을 사용한다. 이를 통해 폰트가 로드되는 동안 발생할 수 있는 FOUT (Flash of Unstyled Text) 또는 FOIT (Flash of Invisible Text) 현상을 관리할 수 있다.
주요 옵션
auto: 브라우저 기본 동작을 따른다.
swap: 폰트가 로드될 때까지 텍스트는 기본 폰트로 렌더링된다. 이후 웹폰트가 로드되면 즉시 해당 폰트로 교체된다. 이 방식은 FOUT현상을 유발할 수 있지만, 폰트가 로드되지 않은 상태에서 사용자에게 빈 화면을 보여주는 것보다는 더 나은 사용자 경험을 제공한다.
block: 웹폰트가 완전히 로드될 때까지 텍스트가 보이지 않게 숨겨준다. 이 방식은 FOIT 현상을 일으켜 폰트가 로드되기 전까지 사용자에게 비어있는 화면을 보여주게 된다.
fallback: 웹폰트를 3초 이내에 로드하지 못한 경우, 기본 폰트로 텍스트를 렌더링한다. 이후 웹폰트가 로드되면 캐시에서 로드되어 교체된다.
optional: 네트워크 상태에 따라, 웹폰트를 로드할지 기본 폰트를 유지할지 결정한다. 네트워크 속도가 느리거나 웹폰트가 로드되지 않으면 기본 폰트를 사용하며, 이후 웹폰트를 로드하지 않을 수도 있다.
적용 예시
@font-face {
font-family: 'CustomFont';
src: url('custom-font.woff2') format('woff2');
font-display: swap;
}
위와 같이 font-display: swap;을 설정하면, 웹폰트가 로드되기 전에 기본 폰트로 텍스트를 표시하고, 폰트가 로드되면 해당 폰트로 즉시 교체된다. 이를 통해 페이지 로드 시간이 길어지는 동안에도 텍스트가 빈 화면으로 표시되지 않도록 할 수 있다.
폰트 용량을 줄이면 서버에서 웹폰트를 다운로드하는 시간을 단축시킬 수 있어 페이지 로딩 속도를 개선할 수 있다. 아래 방법들을 활용해 폰트 최적화를 진행할 수 있다.
Transfonter는 웹 개발자나 디자이너가 웹폰트를 쉽고 빠르게 변환하고 최적화할 수 있도록 도와주는 웹사이트 이다. 해당 사이트는 폰트 포맷 변환, 웹폰트 키트 생성, 서브셋 생성, 압축 및 최적화와 같은 작업을 간편하게 할 수 있다. 또한 사용이 간단하고 무료로 제공되니 해당 사이트를 참고해보자.
웹폰트 포맷은 브라우저 호환성과 파일 크기에 따라 선택해야 한다. 주요 포맷은 다음과 같다.
EOT: 매우 오래된 포맷으로 IE 6~8에서만 사용하며, 최신 브라우저에서는 지원되지 않는다. 압축 기능이 거의 없어 파일 크기가 크다.
TTF/OTF: 파일 크기가 EOT보다는 작지만, 웹 최적화를 고려한 포맷은 아니다. 대체로 모든 브라우저에서 지원된다.
WOFF: W3C에서 웹 환경에 적합한 폰트를 제공하기 위해 만든 포맷이다. 대부분의 브라우저에서 지원되며, 현재도 많이 사용되지만 WOFF2에 비해 효율이 낮아 점차 대체되는 추세이다.
WOFF2: 기존 WOFF 대비 30% 이상 작은 파일 크기를 제공한다. 가장 효율적인 웹폰트 포맷이지만 최신브라우저에서만 지원하기 때문에 구형 브라우저와 호환되지 않는다.
웹폰트 포맷에 따른 웹폰트 압축은 위에 소개해준 Transfer 사이트에서 할 수 있다.

사이트로 이동하여 변환을 원하는 폰트를 등록하고, Formats에서 원하는 형식의 format을 선택한 후 다운로드 받으면 된다.

WOFF2, WOFF가 압출륙이 좋지만 브라우저마다 지원하는 폰트가 다르기 때문에 @font-face 규칙을 적용하여 여러 포맷을 지정해 브라우저가 지원하는 파일을 우선 다운로드하도록 설정해야 한다.
적용 예시
@font-face {
font-family: 'CustomFont';
src: url('customfont.woff2') format('woff2'), /* 최신 브라우저용 */
url('customfont.woff') format('woff'), /* 구형 브라우저용 */
url('customfont.ttf') format('truetype');
font-display: swap;
}
만약 사용자의 브라우저에 서버에서 다운로드할 웹폰트가 존재한다면, 추가로 웹폰트를 다운로드하지 않아도 되므로 로딩 시간을 단축할 수 있다.
적용 예시
@font-face {
font-family: 'LocalFont';
src: local('LocalFont'), /* 사용자의 시스템에서 폰트를 검색 */
url('localfont.woff2') format('woff2'), /* 로컬에 폰트가 설치되어있지 않다면 다음 폰트들을 적용한다 */
url('localfont.woff') format('woff'),
url('localfont.ttf') format('truetype');
}

한글은 자음과 모음의 조합으로 이루어져 있어, 모든 조합을 포함하면 만 개가 넘는 글자가 생성된다. 하지만 실제 서비스에서는 사용하지 않는 조합(예: 긗, 귶)도 많다.
웹폰트에 모든 글리프(문자)를 포함하면 파일 크기가 불필요하게 커지는데, 실제 사용하는 문자만 남기고 나머지를 제거한 서브셋 폰트를 생성하면 용량을 크게 줄일 수 있다. 이를 통해 폰트 파일 크기를 최적화하고 페이지 로딩 속도를 개선할 수 있다.
다만, 서브셋 폰트를 사용하는 경우 주의할 점이 있다. 텍스트가 동적으로 생성되는 페이지에서는 서브셋 폰트에 포함되지 않은 글자가 나타날 가능성이 있다. 이런 상황에서는 일관성 있는 텍스트 디자인을 제공하지 못할 수 있다. 따라서 서브셋 폰트는 주로 사용되는 문자가 고정된 랜딩 페이지나 정적인 콘텐츠에 적합하다.
서브셋 폰트 또한 Transfonter 사이트에서 생성할 수 있다.

사이트로 이동하여 변환을 원하는 폰트를 등록하고, characters에 원하는 글자 목록을 추가하면 된다.
한 페이지에서 특정 문자 집합만 사용하는 경우, CSS의 unicode-range 속성을 활용하면 브라우저가 필요한 글리프(문자)만 로드하도록 설정할 수 있다. 이를 통해 웹폰트 파일 크기를 줄이고 로딩 속도를 최적화할 수 있다.
기본 예시
아래 예제는 기본 라틴 문자만 로드하도록 설정한 경우다.
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
unicode-range: U+0000-007F; /* 기본 라틴 문자만 사용 */
}
다국어 웹폰트 설정
다국어 서비스를 제공하는 경우, unicode-range를 사용해 나라별로 필요한 폰트를 구분하여 로드할 수 있다. 이렇게 하면 모든 폰트를 한 번에 다운로드하지 않아도 된다.
/* 한글 전용 폰트 */
@font-face {
font-family: 'koreaFont';
src: url('koreafont.woff2') format('woff2');
unicode-range: U+1100-U+11FF; /* 한글 문자만 */
}
/* 라틴어 전용 폰트 */
@font-face {
font-family: 'latinFont';
src: url('latinfont.woff2') format('woff2');
unicode-range: U+0000-005FF; /* 라틴 문자만 */
}
data-uri 방식은 웹폰트 리소스를 CSS 파일에 직접 포함하여 추가 네트워크 요청을 줄이고 초기 로딩 속도를 개선할 수 있다는 장점이 있다. 또한, CSS와 리소스를 하나의 파일로 묶어 관리가 간편해진다는 이점도 있다.
그러나 Base64 인코딩으로 인해 파일 크기가 원본보다 약 33% 커지고, 포함된 리소스는 브라우저에서 캐싱되지 않아 반복 요청 시 비효율적일 수 있다. 더불어, 긴 Base64 문자열은 읽기 어렵고 수정이나 디버깅이 불편하다는 단점도 있다.
data-uri는 작은 리소스를 포함해 초기 로딩 속도를 개선하는 데 효과적이지만, 파일 크기와 캐싱 문제를 고려해 신중히 활용해야 한다.
data-uri 또한 Transfonter 사이트에서 변환할 수 있다.

사이트로 이동하여 변환을 원하는 폰트를 등록하고, Base64 encode를 활성화 하면 된다.
적용 예시
@font-face {
font-family: 'MyFont';
src: url(data:font/woff2;base64,...); /* Base64 인코딩된 폰트 데이터 */
}
웹폰트 Preload는 브라우저가 폰트 파일을 CSS가 로드되기 전에 미리 다운로드하도록 지시하는 기법이다. 이를 통해 FOUT(Flash of Unstyled Text) 또는 FOIT(Flash of Invisible Text)를 방지하고, 페이지 로딩 속도를 향상시킬 수 있다.
Preload는 HTML의 <link> 태그를 사용하여 명시하며, 브라우저는 이를 최우선 순위로 로드한다. 이를 통해 웹폰트가 CSS보다 먼저 로드되도록 보장한다.
다만, Preload는 잘못 사용하면 리소스 로딩 순서가 뒤섞여 성능이 저하를 유발할 수 있다. 따라서 초기 화면에 필요한 폰트만 Preload하는 것이 중요하다. Preload로 폰트를 로드한 후에는, CSS에서 @font-face 규칙을 사용해 폰트를 정의해야 정상적으로 사용할 수 있다.
적용 예시
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webfont Preload Example</title>
<!-- 웹폰트 Preload -->
<!-- rel="preload": 리소스를 미리 로드하도록 지시.-->
<!-- href: 폰트 파일 경로.-->
<!-- as="font": 리소스 타입을 지정(폰트).-->
<!-- type="font/woff2": 폰트 파일의 포맷 지정.-->
<!-- crossorigin="anonymous": 크로스 오리진 요청 시 사용(외부 폰트 URL이 있는 경우 필요). -->
<link rel="preload" href="/fonts/myfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<!-- CSS 파일 -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1 style="font-family: 'MyFont';">웹폰트 Preload 테스트</h1>
</body>
</html>
웹팩(Webpack)이나 비트(Vite) 같은 번들링 도구로 웹 애플리케이션을 빌드할 때, 폰트 파일, 이미지, 스크립트 같은 정적 리소스에 해시값(hash)이 추가된다. 이렇게 하면 캐시를 무효화할 수 있어서 항상 최신 리소스를 로드할 수 있다.
하지만 이 해시값 때문에 HTML의 <link rel="preload"> 태그 경로를 일일이 업데이트해야 하는 번거로움이 생긴다. 이걸 해결하려면 웹팩 플러그인을 써서 Preload 태그를 자동으로 생성하고 관리할 수 있다.
1. PreloadWebpackPlugin 설치 (Preload 태그 자동 생성)
먼저 Preload 태그 자동 생성으로 생성해주는 preload-webpack-plugin을 설치한다.
npm install preload-webpack-plugin --save-dev
2. 웹팩 설정 파일 작성
웹팩 설정 파일(webpack.config.js)에 PreloadWebpackPlugin을 추가해서 자동화한다.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
module.exports = {
entry: './src/index.js', // 애플리케이션 진입점
output: {
path: path.resolve(__dirname, 'build'), // 빌드 출력 경로
filename: '[name].[contenthash].js', // JS 파일 이름에 해시 추가
assetModuleFilename: 'fonts/[name].[contenthash][ext]', // 폰트 파일 이름에 해시 추가
},
module: {
rules: [
{
test: /\.css$/, // CSS 처리
use: ['style-loader', 'css-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/, // 폰트 파일 처리
type: 'asset/resource',// 웹팩 5의 기본 정적 파일 처리 방식
},
],
},
//플러그인
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html', // HTML 템플릿 경로
}),
new PreloadWebpackPlugin({
rel: 'preload', // Preload 태그 생성
as: (entry) => {
if (/\.woff2?$/.test(entry)) return 'font'; // 폰트 파일은 font로 설정
if (/\.css$/.test(entry)) return 'style'; // CSS 파일은 style로 설정
if (/\.js$/.test(entry)) return 'script'; // JS 파일은 script로 설정
return 'auto';
},
include: 'allAssets', // 모든 에셋 포함
fileWhitelist: [/\.(woff|woff2)$/i], // woff, woff2 파일만 포함
crossorigin: 'anonymous', // CORS 지원을 위해 추가
}),
],
devServer: {
static: './build', // 개발 서버 정적 파일 경로
port: 3000, // 개발 서버 포트
open: true, // 브라우저 자동 열기
},
};
3. 설정 주요 포인트
Preload 태그의 파일 타입 관리
as 옵션을 사용해서 파일 형식에 맞는 as 속성을 설정한다. 예를 들어, 폰트 파일은 as="font", 스크립트는 as="script"로 설정한다.
파일 필터링
fileWhitelist 옵션을 사용해서 특정 형식의 파일만 Preload 태그에 포함시킬 수 있다. 위 예시에서는 woff와 woff2 파일만 포함시킨다.
CORS 지원
웹폰트는 CORS 정책에 의해 리소스가 다운로드되지 않을 수 있으므로, Preload 태그를 생성할 때 crossorigin="anonymous" 속성을 추가하는 것이 중요하다. 이 속성은 웹폰트를 안전하게 로드할 수 있도록 도와준다.
4. 빌드 및 실행
설정이 완료되었으니 빌드하거나 개발 서버를 실행한다.(스크립트 설정에 따라 명령어는 달라질 수 있다.)
npm run build
npm start
5. 결과 확인
빌드된 HTML 파일에서 Preload 태그가 자동으로 생성된 걸 확인할 수 있다.
<link rel="preload" href="assets/myfont.abcdef.woff2" as="font" type="font/woff2" crossorigin="anonymous">