[Next.js] Next.js의 next/font에 대해서 (공식문서 및 최적화 테크닉)
카테고리: Next.js
태그: Font
Font Optimization
next/font
- 자동으로 글꼴 최적화 (사용자 지정 글꼴 포함)
- 외부 네트워크 요청을 제거 (개인정보 보호, 성능 개선)
🎥
next/font
에 대한 유튜브 영상 (6분)
-
next/font
특징- CSS 및 글꼴 파일은 빌드 시 다운로드되며 나머지 정적 에셋과 함께 자체 호스팅
-
브라우저에서 Google에 요청을 보내지 않음
- [Appendix]
next/font
의 pre-download- 빌드 타임에 글꼴 미리 다운로드 (웹 폰트의 경우) → 로컬 디렉토리에 저장
- HTML파일이 로컬 파일을 link하는 방식으로 구성 됨
- 다른 도메인 간 연결을 위한 handshake 과정 생략 → 체감 속도 향상
-
CSS의
size-adjust
속성 이용한 layout shift 방지-
[Appendix]
next/font
의 zero Layout Shift-
FOUT & FOIT
- [참고 링크] FOUT – Fonts Knowledge - Google Fonts
- [참고 링크] FOIT – Fonts Knowledge - Google Fonts
- next/font (12 ver.) OR others
- FOUT**(Flash Of Unstyled Text) → CLS(Cumulative Layout Shift)
- next/font (13 ver.)
- Zero Layout Shift
-
동작 원리
- 웹 폰트 로드 전 사용되는
fallback
시스템 폰트가 존재 - 폰트는 같은 크기라도 약간씩 높이가 다름 (CLS의 원인)
-
css-adjust
속성을 사용 시스템 폰트의 x-높이를 웹 폰트의 x-높이와 일치하도록 설정-
[Appendix]
css-adjust
속성이란?-
글리프 윤곽선과 메트릭에 대해 배수를 조정 → 다양한 끌꼴을 조화시킴
size-adjust: 90%;
-
Next.js
에서는adjustFontFallbackMetrics
함수에서 속성 조정- 사용자가 지정한 폰트에 대한
fallback font
(기본 폰트) 결정 fallback font
와의CLS
를 발생시킬 수 있는 크기 차이를 비교size-adjust
속성을 조정하는 방식으로 동작 [참고 링크] size-adjust - CSS: Cascading Style Sheets | MDN
[참고 링크] How @next/font works
[참고 링크] Zero Layout Shift를 위한 Next Font Optimization의 원리
- 사용자가 지정한 폰트에 대한
-
-
- 웹 폰트 로드 전 사용되는
-
-
- [Appendix]
하나의 글꼴 사용하기
Google 글꼴 사용 하기
- 자체 호스팅 기능을 통해 브라우저에서 구글에 별도 요청 🚫
next/font/google
에서 사용하려는 글꼴을 함수로 가져와서 시작-
최상의 성능과 유연성을 위해
가변 글꼴
을 사용하는 것이 좋습니다종류 특징 가변 글꼴 여러 스타일의 버전(굵기 등)이 한 파일에 통합되어 있는 openType 글꼴 정적 글꼴 스타일 별 별도의 파일을 가지는 기존의 글꼴 [Appendix] 가변 글꼴 vs 정적 글꼴에 대한 상세한 아티클 (TLTR;)
[참고 링크] Variable fonts (가변 폰트) | WIT블로그
[Link] Google Fonts 내 가변 글꼴 리스트
[참고 링크] Variable Fonts - Google Fonts
[Appendix] 나무위키 내 한글 가변 글꼴 리스트
[참고 링크] https://namu.wiki/w/가변 글꼴 -
모든 페이지에서 글꼴 사용 시
pages/_app.js
에 글꼴 추가import { Inter } from "next/font/google"; // 가변 글꼴인 inter의 경우 굵기 설정 불필요 const inter = Inter({ subsets: ["latin"] }); export default function MyApp({ Component, pageProps }) { return ( <main className={inter.className}> <Component {...pageProps} /> </main> ); }
-
정적 글꼴의 경우 가중치(weight)를 지정
// pages/_app.js import { Roboto } from "next/font/google"; // 정적 글꼴인 Roboto의 경우 굵기 설정이 필요 const roboto = Roboto({ weight: "400", subsets: ["latin"], }); export default function MyApp({ Component, pageProps }) { return ( <main className={roboto.className}> <Component {...pageProps} /> </main> ); }
-
배열을 사용하여 스타일 및 설정
const roboto = Roboto({ weight: ["400", "700"], // 굵기 style: ["normal", "italic"], // 스타일 subsets: ["latin"], // 지원 언어 (라틴 알파벳) display: "swap", // 로딩 전략 (페이지가 로드되면서 사용 가능한 경우 즉시 폰트를 바꿉) });
[TIP] 폰트 사이에 띄어 쓰기가 있는 경우 언더스코어( 사용. E.g)
Roboto_\__Mono
<head>
에 글꼴 적용하기
-
head 안에 글꼴을 삽입 → 래퍼와 클래스명 없이 글꼴을 사용!!
import { Inter } from "next/font/google"; const inter = Inter({ subsets: ["latin"] }); export default function MyApp({ Component, pageProps }) { return ( <> <style jsx global>{` html { font-family: ${inter.style.fontFamily}; } `}</style> <Component {...pageProps} /> </> ); }
단일 페이지에서 사용
-
단일 페이지에서 글꼴을 사용하려면 아래와 같이 특정 페이지에 글꼴 추가
// pages/index.js import { Inter } from "next/font/google"; const inter = Inter({ subsets: ["latin"] }); export default function Home() { return ( <div className={inter.className}> <p>Hello World</p> </div> ); }
대상 언어(subset) 지정하기
-
Google 글꼴은 자동적으로
subset
방식- 글꼴 파일의 크기가 줄어들고 성능 향상
-
미리 로드할
subset
을 정의해야 함 (preload
상태에서subset
미 지정 시 🚨경고🚨)const inter = Inter({ subsets: ["latin"] });
여러 글꼴 사용하기
두 가지 접근 방법이 존재
-
[방법 1] 글꼴을 내보내고 가져온 다음 필요한 곳에 클래스명을 적용하는 유틸리티 함수 사용
-
글꼴이 렌더링될 때만 글꼴이
preload
됨// app/fonts.ts import { Inter, Roboto_Mono } from "next/font/google"; export const inter = Inter({ subsets: ["latin"], display: "swap", }); export const roboto_mono = Roboto_Mono({ subsets: ["latin"], display: "swap", });
-
[방법 2] CSS 변수를 생성하여 원하는 CSS 솔루션과 함께 사용
-
Inter가 전역적으로 적용되고 모든
<h1>
태그의 스타일이 Roboto Mono로 지정됩// app/global.css html { font-family: var(--font-inter); } h1 { font-family: var(--font-roboto-mono); }
-
-
❗ 여러 글꼴 사용 시 다운로드 해야하는 리소스가 늘어나므로 신중히 사용할 것!!
로컬 글꼴 사용 하기
-
next/font/local
을 불러와 로컬 글꼴 파일의src
지정 (가변 글꼴 추천)**import localFont from 'next/font/local'** // 폰트 파일은 pages 디렉토리 내 넣어두어야 함 **const myFont = localFont({ src: './my-font.woff2' })** export default function MyApp({ Component, pageProps }) { return ( <main className={myFont.className}> <Component {...pageProps} /> </main> ) }
-
src
배열 지정 가능 (단일 글꼴 패밀리에 여러 파일을 사용하려는 경우)const roboto = localFont({ src: [ { path: "./Roboto-Regular.woff2", weight: "400", style: "normal", }, { path: "./Roboto-Italic.woff2", weight: "400", style: "italic", }, { path: "./Roboto-Bold.woff2", weight: "700", style: "normal", }, { path: "./Roboto-BoldItalic.woff2", weight: "700", style: "italic", }, ], });
자세한 내용은 글꼴 API 문서를 참조
테일윈드 CSS 와 함께 사용하기
next/font
는 CSS 변수를 통해 Tailwind 와 함께 사용 가능- CSS
variable
이름을 정의하고 inter에 할당 -
inter.variable
을 사용하여 HTML 문서에 CSS 변수를 추가import { Inter } from 'next/font/google' const inter = Inter({ subsets: ['latin'], **variable: '--font-inter',** }) export default function MyApp({ Component, pageProps }) { return ( <main className={`${**inter.variable**} font-sans`}> <Component {...pageProps} /> </main> ) }
-
tailwind.config.js
에 CSS 변수를 추가**// tailwind.config.js** /** @type {import('tailwindcss').Config} */ module.exports = { content: [ './pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}', './app/**/*.{js,ts,jsx,tsx}', ], theme: { extend: { fontFamily: { **sans: ['var(--font-inter)'],** mono: ['var(--font-roboto-mono)'], }, }, }, plugins: [], }
font-sans
와font-mono
유틸리티 클래스를 사용하여 요소에 글꼴을 적용 가능
기타
사전 로드 (preload)
-
페이지에서 글꼴 함수 호출 시 페이지의 타입에 따라 관련 경로에서만
preload
됨종류 위치 적용 특정 페이지 /pages 하위 페이지 내 특정 경로에서 preload
됨커스텀 앱 /pages/_app /pages
하위 모든 경로에서preload
됨
글꼴 재사용
- localFont 또는 Google 글꼴 함수를 호출 시 하나의 인스턴스로 호스팅 됨
- 여러 파일에서 동일한 글꼴 함수를 로드 시 여러 인스턴스가 호스팅 됨 (중복)
-
적절한 재사용 방법
- 하나의 공유 파일에서 글꼴 로더 함수를 호출합니다.
- 상수로 내보내기
-
글꼴을 사용하려는 각 파일에서 상수를 가져옵니다.
[Appendix] 공유 파일 예시 코드// styles/fonts.ts import { Inter, Lora, Source_Sans_Pro } from "next/font/google"; import localFont from "next/font/local"; // define your variable fonts const inter = Inter(); const lora = Lora(); // define 2 weights of a non-variable font const sourceCodePro400 = Source_Sans_Pro({ weight: "400" }); const sourceCodePro700 = Source_Sans_Pro({ weight: "700" }); // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder const greatVibes = localFont({ src: "./GreatVibes-Regular.ttf" }); export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes };
**// tsconfig.json** { "compilerOptions": { "paths": { "@/fonts": ["./styles/fonts"] } } }
// app/about/page.tsx import { greatVibes, sourceCodePro400 } from "@/fonts";
[reference] https://nextjs.org/docs/app/api-reference/components/font
댓글 남기기