1. LCP 요소 파악하기
Lighthouse로 성능을 측정했더니 LCP(Largest Contentful Paint)가 2.9s ~ 3.1s로 높게 나왔다. LCP 기준이 2.5s 이하인데 훨씬 넘기고 있었다.

Lighthouse의 INSIGHTS 부분에서 LCP Breakdown을 눌러보면 현재 LCP를 차지하는 요소가 무엇인지 확인할 수 있다. 확인해보니 배너 이미지가 LCP 요소로 잡혀 있었다.

2. 원인 찾기
배너 이미지가 원래 CSS background-image로 처리되어 있었는데, Next.js의 <Image> 태그로 변경하고 아래 설정을 추가했다.
<Image
src={bannerImage}
priority
fetchPriority="high"
...
/>
LCP request discovery의 경고는 사라졌지만 LCP는 그대로였다. 아무리 이미지 설정을 바꿔도 개선되지 않아서 배너를 아예 제거해봤는데, 그래도 LCP가 그대로인걸 보니 배너가 문제가 아니었다.
이미지가 있는 요소들을 하나씩 제거해가며 확인하면서 결국 텍스트가 있는 footer만 남겼는데도 LCP가 똑같았다. 이때 LCP Breakdown을 다시 확인하니 LCP 요소가 이미지가 아닌 텍스트로 잡혀 있었다.
혹시 폰트가 문제일까 싶어서 폰트 로드를 제거해봤더니, 배너 이미지가 있는 상태에서도 LCP가 정상 범위로 내려왔다.
원인은 폰트였다… 😇
3. 폰트 Subset 적용하기
디자인 시안을 따라야 하기 때문에 폰트를 아예 제거하는 건 불가능하다. 대신 Subset 폰트를 사용하는 방법이 있다. 이 프로젝트에서는 Pretendard를 사용하고 있었는데, Pretendard는 Subset 버전도 제공한다.
Pretendard
Pretendard 프리텐다드 Pretendard 프리텐다드 글꼴 다운로드 일본어 버전 다운로드 GitHub에서 보기 폰트 제작 및 운영 클래스 ..
cactus.tistory.com
다운로드 후 web/static 폴더에서 woff2-subset 또는 woff-subset을 선택한다. 기존에 woff2를 사용하고 있었기 때문에 woff2-subset을 선택했다.
기존 폰트 파일을 제거하고, 프로젝트에서 실제로 사용하는 굵기의 파일만 추가했다. 이 프로젝트에서는 400, 500, 600, 700만 사용하고 있어서 이 4개만 넣고 layout.tsx를 아래와 같이 수정했다.
변경 전
const pretendard = localFont({
src: './fonts/pretendard/PretendardVariable.woff2',
display: 'swap',
variable: '--font-pretendard',
});
변경 후
const pretendard = localFont({
src: [
{
path: './fonts/pretendard/Pretendard-Regular.subset.woff2',
weight: '400',
},
{
path: './fonts/pretendard/Pretendard-Medium.subset.woff2',
weight: '500',
},
{
path: './fonts/pretendard/Pretendard-SemiBold.subset.woff2',
weight: '600',
},
{
path: './fonts/pretendard/Pretendard-Bold.subset.woff2',
weight: '700',
},
],
display: 'swap',
variable: '--font-pretendard',
});
4. 결과
Subset 폰트 적용 후 LCP가 평균 2.9s → 1.4s로 약 50% 개선되었고, Lighthouse의 Performance 지표도 90점대로 올랐다.

LCP 요소가 이미지일 거라고 생각하기 쉽지만 폰트가 원인인 경우도 있다. LCP가 이상하게 높게 나온다면 폰트도 의심해보자!