이번 글은 Next.js 공식 튜토리얼을 번역한 글입니다.
공식 튜토리얼을 따라하면 Next.js 의 동작원리와 개발 방식에 대해 학습하기 쉽고 잘 쓰여진 튜토리얼이라고 생각되어 번역하게 되었습니다.
오타 또는 오역된 부분이 있다면 댓글 부탁드립니다.
지난 장에서는 Next.js 애플리케이션의 스타일링에 대해 알아보았습니다. 이번에는 홈페이지에 커스텀 폰트와 히어로 이미지를 추가하는 방법을 배워보겠습니다.
이번 장에서 다룰 주제는 다음과 같습니다.
- next/font를 사용하여 커스텀 폰트 추가하기
- next/image를 사용하여 이미지 추가하기
- Next.js에서 폰트와 이미지가 최적화되는 방식
폰트를 최적화하는 이유
폰트는 웹사이트의 디자인에 중요한 역할을 하지만, 커스텀 폰트를 사용하면 폰트 파일을 불러오고 로드하는 데 시간이 걸려 성능에 영향을 줄 수 있습니다.
구글이 웹사이트의 성능과 사용자 경험을 평가할 때 사용하는 지표 중 하나인 누적 레이아웃 이동(CLS)는 페이지가 로드될 때 콘텐츠가 이동하는 현상을 측정합니다. 폰트의 경우, 브라우저가 처음에는 대체 폰트나 시스템 폰트로 텍스트를 표시하고 이후 커스텀 폰트가 로드되면 이를 교체하는 과정에서 레이아웃이 변경될 수 있습니다.
이렇게 폰트가 로드되면서 발생하는 레이아웃 이동은 요소 간의 위치가 변경되거나 텍스트 크기와 간격이 달라질 수 있는 원인이 됩니다. Next.js는 next/font 모듈을 사용하면 애플리케이션 내 폰트를 자동으로 최적화합니다. 빌드 시 폰트 파일을 다운로드하여 다른 정적 파일과 함께 제공하므로, 사용자가 애플리케이션에 접근할 때 추가적인 폰트 관련 네트워크 요청 없이 빠르게 로드됩니다.
퀴즈: 방금 배운 내용을 테스트해봅시다.
Next.js는 어떻게 폰트를 최적화할까요?
- A: 추가적인 네트워크 요청을 발생시켜 성능을 높입니다.
- B: 모든 커스텀 폰트를 비활성화합니다.
- C: 런타임에 모든 폰트를 미리 로드합니다.
- D: 폰트 파일을 다른 정적 파일과 함께 호스팅하여 추가적인 네트워크 요청 없이 로드합니다.
정답: D
주요 폰트 추가하기
애플리케이션에 커스텀 Google 폰트를 추가해 보면서 이 작동 방식을 알아보겠습니다!
/app/ui 폴더에 fonts.ts라는 새 파일을 생성합니다. 이 파일은 애플리케이션 전반에서 사용될 폰트를 보관하는 데 사용됩니다.
next/font/google 모듈에서 Inter 폰트를 가져옵니다. 이 폰트는 주 폰트로 사용할 것입니다. 그런 다음, 로드할 서브셋을 지정합니다. 여기서는 'latin'을 사용합니다.
// /app/ui/fonts.ts
import { Inter } from 'next/font/google';
export const inter = Inter({ subsets: ['latin'] });
마지막으로 /app/layout.tsx의 <body> 요소에 폰트를 추가합니다.
// /app/layout.tsx
import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={`${inter.className} antialiased`}>{children}</body>
</html>
);
}
Inter 폰트를 <body> 요소에 추가하면 애플리케이션 전반에 폰트가 적용됩니다. 여기서는 Tailwind의 antialiased 클래스를 추가하여 폰트를 부드럽게 표시하고 있습니다. 꼭 필요한 것은 아니지만, 미관상 도움이 됩니다.
브라우저로 이동하여 개발자 도구를 열고 body 요소를 선택합니다. 이제 Inter와 Inter_Fallback이 스타일에 적용된 것을 확인할 수 있습니다.
연습: 보조 폰트 추가하기
애플리케이션의 특정 요소에 폰트를 추가할 수도 있습니다.
이제 여러분 차례입니다! fonts.ts 파일에서 Lusitana라는 보조 폰트를 가져오고, /app/page.tsx 파일의 <p> 요소에 적용해 보세요. 이전과 같이 서브셋을 지정하는 것 외에도 폰트 두께를 지정해야 합니다.
준비가 되면 아래 코드 조각을 확장하여 솔루션을 확인하세요.
힌트
- 폰트에 어떤 두께 옵션을 전달해야 할지 모르겠다면 코드 편집기에서 TypeScript 오류를 확인하세요.
- Google Fonts 웹사이트에서 Lusitana를 검색하여 사용할 수 있는 옵션을 확인하세요.
- 여러 폰트를 추가하는 방법과 사용 가능한 옵션 목록을 보려면 문서를 참조하세요
import { Inter, Lusitana } from 'next/font/google';
export const inter = Inter({ subsets: ['latin'] });
export const lusitana = Lusitana({
weight: ['400', '700'],
subsets: ['latin'],
});
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
export default function Page() {
return (
// ...
<p
className={`${lusitana.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>
// ...
);
}
마지막으로, Lusitana 폰트를 사용하는 <AcmeLogo /> 컴포넌트도 주석 처리가 되어 있습니다. 이제 주석을 해제할 수 있습니다.
// /app/page.tsx
// ...
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>
</main>
);
}
훌륭합니다!
이제 애플리케이션에 두 개의 커스텀 폰트를 추가했습니다. 다음으로 홈 페이지에 히어로 이미지를 추가해 보겠습니다.
왜 이미지를 최적화해야 할까요?
Next.js는 /public 폴더 아래에서 이미지와 같은 정적 자산을 제공할 수 있습니다. /public 안의 파일은 애플리케이션에서 참조할 수 있습니다.
일반적인 HTML에서는 다음과 같이 이미지를 추가할 수 있습니다.
<img
src="/hero.png"
alt="데스크톱 버전의 대시보드 프로젝트 스크린샷"
/>
하지만, 이 경우 다음을 수동으로 수행해야 합니다.
- 다양한 화면 크기에 대해 이미지가 반응형으로 표시되도록 합니다.
- 기기별로 이미지 크기를 지정합니다.
- 이미지를 로드할 때 레이아웃 이동을 방지합니다.
- 사용자의 뷰포트에 들어오지 않은 이미지를 지연 로드합니다.
이미지 최적화는 웹 개발에서 큰 주제이며 전문 분야로 여겨질 정도입니다. 이러한 최적화를 수동으로 구현하는 대신, next/image 컴포넌트를 사용하여 이미지를 자동으로 최적화할 수 있습니다.
<Image> 컴포넌트
<Image> 컴포넌트는 HTML <img> 태그의 확장이며, 다음과 같은 자동 이미지 최적화 기능을 제공합니다.
- 이미지 로드 시 레이아웃 이동을 자동으로 방지합니다.
- 작은 뷰포트를 가진 기기에 큰 이미지를 전송하지 않도록 이미지를 크기 조정합니다.
- 뷰포트에 들어오는 이미지를 기본적으로 지연 로드합니다.
- 브라우저가 지원할 경우, WebP 및 AVIF와 같은 최신 형식으로 이미지를 제공합니다.
데스크톱 히어로 이미지 추가하기
<Image> 컴포넌트를 사용해 보겠습니다. /public 폴더 안에 hero-desktop.png와 hero-mobile.png라는 두 개의 이미지가 있습니다. 이 두 이미지는 완전히 다르며, 사용자의 기기가 데스크톱인지 모바일인지에 따라 표시됩니다.
// /app/page.tsx
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
import Image from 'next/image';
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 */}
<Image
src="/hero-desktop.png"
width={1000}
height={760}
className="hidden md:block"
alt="데스크톱 버전의 대시보드 프로젝트 스크린샷"
/>
</div>
//...
);
}
여기서 너비를 1000픽셀, 높이를 760픽셀로 설정하고 있습니다. 레이아웃 이동을 방지하기 위해 이미지의 너비와 높이를 설정하는 것이 좋습니다. 이 비율은 원본 이미지와 동일해야 합니다.
또한, hidden 클래스를 사용해 모바일 화면에서는 이미지를 DOM에서 제거하고, md:block 클래스를 사용해 데스크톱 화면에서는 이미지를 표시합니다.
이제 홈페이지는 다음과 같아야 합니다.
연습: 모바일 히어로 이미지 추가하기
이제 여러분 차례입니다! 방금 추가한 이미지 아래에 hero-mobile.png를 위한 <Image> 컴포넌트를 추가해 보세요.
- 너비는 343픽셀, 높이는 388픽셀로 설정하세요.
- md:hidden을 사용하여 데스크톱 화면에서는 이미지를 숨기세요.
준비가 되면 아래 코드 조각을 확장하여 솔루션을 확인하세요.
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
import Image from 'next/image';
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 */}
<Image
src="/hero-desktop.png"
width={1000}
height={760}
className="hidden md:block"
alt="Screenshots of the dashboard project showing desktop version"
/>
<Image
src="/hero-mobile.png"
width={560}
height={620}
className="block md:hidden"
alt="Screenshot of the dashboard project showing mobile version"
/>
</div>
//...
);
}
좋아요! 이제 홈페이지에 사용자 정의 글꼴과 히어로 이미지가 있습니다.
퀴즈: 방금 배운 내용을 테스트해봅시다.
True 또는 False: 너비와 높이가 지정되지 않은 이미지와 웹 폰트는 레이아웃 이동의 흔한 원인이다.
- A. True
- B. False
정답: A
추천 문서
이 주제들에 대해 더 배울 것이 많습니다.
여기에는 원격 이미지 최적화와 로컬 폰트 파일 사용이 포함됩니다. 폰트와 이미지에 대해 더 깊이 알아보고 싶다면, 아래 자료를 참고하세요.
'Frontend > Next.js' 카테고리의 다른 글
[Next.js] Next 공식 튜토리얼 진행하기 - Chapter 4 (1) | 2024.11.17 |
---|---|
[Next.js] Next.js Middleware로 로그인 검증하기 (0) | 2024.11.15 |
[Next.js] Next 공식 튜토리얼 진행하기 - Chapter 2 (0) | 2024.11.10 |
[Next.js] Next 공식 튜토리얼 진행하기 - Chapter 1 (1) | 2024.11.10 |
[Next.js] Next 공식 튜토리얼 진행하기 - Introduction (2) | 2024.11.09 |