DEV Community

Cover image for ๐ŸงฑNext.js 14์— Pretendard ํฐํŠธ ์ ์šฉํ•˜๊ธฐ
Chan
Chan

Posted on

๐ŸงฑNext.js 14์— Pretendard ํฐํŠธ ์ ์šฉํ•˜๊ธฐ

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Next.js 14 ๋ฒ„์ „์—์„œ Pretendard ํฐํŠธ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฒ•๊ณผ, ๊ธฐ์กด์— cdn์—์„œ ํฐํŠธ๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ์— ๋น„ํ•ด์„œ ์–ด๋–ค ์ตœ์ ํ™”๊ฐ€ ์ด๋ฃจ์–ด์ง€๋Š”์ง€ ๋‹ค๋ฃจ๊ฒ ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ Next.js 14์— ๋Œ€ํ•œ ์ž๋ฃŒ๋Š” ํ•œ๊ธ€ํ™”๋œ ๋ฌธ์„œ๊ฐ€ ๋งŽ์ง€ ์•Š์•„์„œ ๋„์›€์„ ๋ฐ›์œผ์‹ค ๋ถ„๋“ค์ด ๋งŽ์œผ์…จ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

Pretenard

  • ์‚ฌ์‹ค์ƒ ํ˜„์—… ํ‘œ์ค€์œผ๋กœ ์ž๋ฆฌ์žก์€ ํ•œ๊ธ€ ํฐํŠธ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ํšŒ์‚ฌ๋“ค์ด ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์•„์ด์ฝ˜, ์ˆซ์ž์™€์˜ ๋ฐฐ์น˜๊ฐ€ ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ฒƒ์ด ์žฅ์ ์ž…๋‹ˆ๋‹ค.
  • ํฐํŠธ ๊ตต๊ธฐ๊ฐ€ ๋‹ค์–‘ํ•˜์—ฌ ์„ฌ์„ธํ•œ ํฐํŠธ ์Šคํƒ€์ผ๋ง์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฌด๋ฃŒ ์ƒ์—…์šฉ ํฐํŠธ๋กœ ๋ˆ„๊ตฌ๋‚˜ ๊ฐ€์ ธ๋‹ค ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ค์น˜

  1. Prendtendard releast note๋กœ ๋“ค์–ด๊ฐ€์„œ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„์ฃผ์„ธ์š”.

    Release note assets

  2. ์••์ถ•์„ ํ’€๊ณ  .../Pretendard-1.3.9/web/variable/woff2/PretendardVariable.woff2 ํŒŒ์ผ์„ ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ์— ๋„ฃ์–ด์ฃผ์„ธ์š”. ์ œ ํ”„๋กœ์ ํŠธ์—๋Š” /static/fonts ๋””๋ ‰ํ† ๋ฆฌ์— ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค.

    Project directory

  3. global font๋กœ ์ ์šฉ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ app/layout.tsx์— className์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

    import localFont from "next/font/local";
    
    const pretendard = localFont({
      src: "../static/fonts/PretendardVariable.woff2",
      display: "swap",
      weight: "45 920",
      variable: "--font-pretendard",
    });
    
    export default function RootLayout({
      children,
    }: Readonly<{
      children: React.ReactNode;
    }>) {
      return (
        <html lang="kr" className={`${pretendard.variable}`}>
          <body className={pretendard.className}>
            <Header/>
            {children}
          </body>
        </html>
      );
    }
    

tailwindcss์— css varaible๋กœ ๋“ฑ๋กํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ

์ „์—ญ์ ์œผ๋กœ ํฐํŠธ๋ฅผ ์ ์šฉ์‹œํ‚ค๋Š” ๋Œ€์‹ ์— ๋ถ€๋ถ„์ ์œผ๋กœ ํฐํŠธ๋ฅผ ์ ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋Š” tailwind์˜ css variable์œผ๋กœ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. app/layout.tsx์—์„œ ํฐํŠธ์˜ css variable์„ document์— ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

    import localFont from "next/font/local";
    
    const pretendard = localFont({
      src: "../static/fonts/PretendardVariable.woff2",
      display: "swap",
      weight: "45 920",
      variable: "--font-pretendard",
    });
    
    export default function RootLayout({
      children,
    }: Readonly<{
      children: React.ReactNode;
    }>) {
      return (
        <html lang="kr" className={`${pretendard.variable}`}>
          <body className={pretendard.className}>
            <Header/>
            {children}
          </body>
        </html>
      );
    }
    
  2. tailwind.cssconfig.js์—์„œ css variable์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

    import type { Config } from "tailwindcss";
    
    const config: Config = {
      content: [
        "./pages/**/*.{js,ts,jsx,tsx,mdx}",
        "./components/**/*.{js,ts,jsx,tsx,mdx}",
        "./app/**/*.{js,ts,jsx,tsx,mdx}",
        "./src/**/*.{js,ts,jsx,tsx,mdx}",
        "./stories/**/*.{js,ts,jsx,tsx,mdx}",
      ],
      theme: {
        extend: {
          fontFamily: {
            pretendard: ["var(--font-pretendard)"],
          },
        },
      },
      plugins: [],
    };
    export default config;
    

์‚ฌ์šฉ

className์— font-pretendard๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํฐํŠธ๋ฅผ ์ ์šฉ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<div className="font-pretendard shrink-0 font-black">ํ”„๋ฆฌํ…๋‹ค๋“œ</div>
Enter fullscreen mode Exit fullscreen mode

Font Optimization

์ด ์ฏค์—์„œ ์˜๋ฌธ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

.css file์—์„œ font-face attribute๋กœ cdn ํ†ตํ•ด ํฐํŠธ๋ฅผ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์ง€ ์•Š๊ณ  ๊ตณ์ด ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ฌด์—‡์ผ๊นŒ?

Next.js ํŠœํ† ๋ฆฌ์–ผ ๋น„๋””์˜ค์— ๋”ฐ๋ฅด๋ฉด ์ด์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ต๋ณ€ํ•ด์ค๋‹ˆ๋‹ค.

  • cdn์œผ๋กœ๋ถ€ํ„ฐ ๋‹ค์šด๋กœ๋“œ ๋ฐ›๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ custom ํฐํŠธ๋ฅผ ๋‹ค์šด๋กœ๋“œ ๋ฐ›๊ธฐ ์ „๊นŒ์ง€๋Š” ์šด์˜์ฒด์ œ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ fallback font(Arial ๋“ฑ)๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. custom ํฐํŠธ ๋กœ๋“œ ์ „/๋กœ๋“œ ํ›„์— ํฐํŠธ ์‚ฌ์ด์ฆˆ ํฌ๊ธฐ ์ฐจ์ด๋กœ ์ธํ•ด cumulative layout shift๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํฌ๊ฒŒ ๋–จ์–ด๋œจ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • Next.js์˜ next/font๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” font๋ฅผ ๋นŒ๋“œ ํƒ€์ž„ ๋•Œ ํ•œ๋ฒˆ๋งŒ ๋‹ค์šด๋กœ๋“œ ๋ฐ›๊ณ , fallback font๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๋™์•ˆ css size-adjust ํ”„๋กœํผํ‹ฐ๋ฅผ ์ ์šฉ์‹œ์ผœ์„œ ๊ธ€์ž ํฌ๊ธฐ๋ฅผ ๋™์ผํ•˜๊ฒŒํ•˜์—ฌ layout shift๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์•„์ค๋‹ˆ๋‹ค.

์ง์ ‘ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ์ผœ๊ณ  ํ™•์ธํ•ด๋ดค์Šต๋‹ˆ๋‹ค.
๋„คํŠธ์›Œํฌ์— throttling์„ ๊ฑธ์–ด์„œ ์ผ๋‹จ custom font๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ์ „์˜ UI์™€ ๋กœ๋“œ๋œ ํ›„์˜ UI๋ฅผ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๋กœ๋“œ ์ „: ์‹œ์Šคํ…œ ํฐํŠธ๊ฐ€ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
    Text with fallback font

  • ๋กœ๋“œ ํ›„: Pretendard ํฐํŠธ๊ฐ€ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
    Text with Loaded font

  • ํŽ˜์ด์ง€์— ์ ‘์†ํ–ˆ์„ ๋•Œ ์ฒ˜์Œ ๋ฐ›์•„์˜ค๋Š” global css file์„ ํ™•์ธํ•ด๋ณด๋‹ˆ, ์ปค์Šคํ…€ ํฐํŠธ๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๋™์•ˆ fallback font์— size-adjust๋ฅผ ์„ค์ •ํ•˜์—ฌ layout shift๋ฅผ ๋ง‰๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

font in devtools

font in devtools2

References

Top comments (1)

Collapse
 
prugehada profile image
ํ‘ธ๋ฅด๊ฒŒํ•˜๋‹ค

๊ณ ๋งˆ์›Œ์š” ์ž˜ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.