왜 폰트(Fonts)를 최적화하는가?

  • 폰트는 웹 사이트 디자인에 중요한 역할을 한다. 그러나, 사용자 지정 폰트를 사용하기 위해, 로드 과정이 별도로 필요한 경우에는 성능에 영향을 미칠 수 있다.
  • Cumulative Layout Shift(누적 레이아웃 변화)는 Google이 웹사이트의 성능과 사용자 경험을 평가하는 지표 중 하나이다.
    • 브라우저는 처음에 대체 폰트나 시스템 폰트로 텍스트를 렌더링한 후, 사용자 지정 폰트를 로드하고 교체하는 과정을 수행한다.
    • 이 과정에서 레이아웃 변경이 일어날 수 있다. (텍스트 크기, 간격, 그 주위 요소 등)
  • Next.jsnext/font모듈을 사용할 때, 애플리케이션의 폰트를 자동으로 최적화한다.
    • Next.js는 폰트 최적화를 위해, 빌드 과정에서 폰트 파일을 다운로드하고 다른 정적 자산과 함께 호스팅하는 방법을 사용한다.
    • 해당 방법은 사용자가 애플리케이션을 방문할 때 폰트에 대한 추가적인 네트워크 요청이 발생하지 않도록 한다.

 

기본 폰트 추가

  • 먼저, /app/ui 디렉터리 내에, font.ts라는 파일을 만든다. 해당 파일을 통해, 애플리케이션 전체에서 사용될 폰트를 유지할 수 있다.

import { Inter } from "next/font/google";

{/* Inter 모듈에서, 폰트 불러오기 */}
export const inter = Inter({ subsets: ["latin"] });
  • 그 다음, /app/layout.tsx에서, font.ts에서 export한 inter폰트를 body태그에 적용한다.
    - 이렇게 하면, Next.js 애플리케이션 전체에 해당 폰트가 적용된다.
    - 여기서, <body>태그에 추가 작성된 antialiased는 폰트를 부드럽게 만들어주는 Tailwind className이다.
import "@/app/ui/global.css";
import { inter } from "./ui/font";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
	  {/* 여기! */}
      <body className={`${inter.className} antialiased`}>{children}</body>
    </html>
  );
}

 

왜 이미지 최적화를 해야하는가?

  • Next.js는 이미지와 같은 정적 파일을 /public 디렉터리 내 최상위 위치에서 제공한다.
    • 정상적으로 Course1의 설치 과정을 따라왔다면, public 디렉터리 내에 hero-desktop.pnghero-mobile.png 두 개의 이미지가 존재할 것이다. 이는 사용자의 기기가 데스크탑인지 모바일인지에 따라 토글 방식으로 표시된다.
  • /app/page.tsx 에 예시로 일반 HTML을 작성해보았을 때, 아래와 같이 이미지를 추가할 수 있다.
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import { lusitana } from '@/app/ui/fonts';
 
export default function Page() {
  return (
    // ...
    <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      {/* Add Hero Images Here */}
      <img
        src="/hero.png"
        alt="Screenshots of the dashboard project showing desktop and mobile versions"
      />
    </div>
    //..
  );
}
  • 하지만 일반 HTML를 사용하여 이미지를 출력할 경우, 아래의 작업을 수동으로 진행해주어야 한다.
    • 이미지가 다양한 화면 크기에 반응하는지 확인
    • 다양한 장치에 대한 이미지 크기 지정
    • 이미지 로드 시 레이아웃이 바뀌는지 확인하고, 바뀐다면 방지 작업 진행
    • 사용자 뷰포트(Viewport) 밖에 있는 이미지 Lazy Load 작업 진행
  • Next.js에서 제공하는 <Image> 컴포넌트는 HTML의 <img>태그의 확장기능을 제공하며, 아래의 자동 이미지 최적화 기능을 제공한다.
    • 이미지가 로드될 때, 자동으로 레이아웃이 이동되는 문제 방지
    • 작은 뷰포트(Viewport)를 가진 디바이스에 큰 이미지를 제공하지 않도록, 이미지의 크기를 조정한다.
    • 기본적으로 이미지를 Lazy Load한다.
    • 브라우저가 지원하는 경우, WebP 및 VIF와 같은 최신 형식으로도 이미지를 제공한다.

 

데스크탑 이미지 추가 (Hero Image)

  • 앞서, /app/page.tsx에서 일반적인 HTML의 <img> 태그로 작성했던 코드를 변경해보자.
    • 아래는 데스크탑과 모바일 환경을 고려하여 <Image> 컴포넌트를 사용한 코드이다.
    • 레이아웃 변화를 방지하기 위해, <Image> 컴포넌트는 이미지의 너비값과 높이값을 필수로 요구한다.
import AcmeLogo from "@/app/ui/acme-logo";
import Link from "next/link";
import clsx from "clsx";
import Image from "next/image";

export default function Page() {
  return (
    <main className="flex min-h-screen flex-col p-6">
      <div className="flex h-20 shrink-0 items-end rounded-lg bg-blue-500 p-4 md:h-52">
        {/* <AcmeLogo /> */}
      </div>
      <div className="mt-4 flex grow flex-col gap-4 md:flex-row">
        <div className="flex flex-col justify-center gap-6 rounded-lg bg-gray-50 px-6 py-10 md:w-2/5 md:px-20">
          <p className={`text-xl text-gray-800 md:text-3xl md:leading-normal`}>
            <strong>Welcome to Acme.</strong> This is the example for the
            <a href="https://nextjs.org/learn/" className="text-blue-500">
              Next.js Learn Course
            </a>
            , brought to you by Vercel.
          </p>
          <Link
            href="/login"
            className="flex items-center gap-5 self-start rounded-lg bg-blue-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-blue-400 md:text-base"
          >
            <span>Log in</span>
          </Link>
        </div>
        <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
          {/* Add Hero Images Here */}
          <Image
            src="/hero-desktop.png"
            {/* 레이아웃 변화 방지를 위한 너비/높이 설정 */}
            width={1000}
            height={760}
            {/* 모바일 환경에서는 해당 이미지 hidden */}
            className="hidden md:block"
            alt="Screenshots of the dashboard project showing desktop and mobile versions"
          />
          <Image
            src="/hero-mobile.png"
            width={560}
            height={620}
            {/* 데스크탑 환경에서는 해당 이미지 hidden */}
            className="block md:hidden"
            alt="Screenshot of the dashboard project showing mobile version"
          />
        </div>
      </div>
    </main>
  );
}
profile
프론트엔드 입문 개발자입니다.

0개의 댓글