ゼロから学ぶ React, Next.js⑩【Learn Next.js】Chapter3
【Chapter3】フォントと画像の最適化
前の章では、Next.jsアプリケーションのスタイリング方法を学びました。カスタムフォントとヒーロー画像を追加することで、ホームページの作業を続けましょう。
この章で扱うトピック
- 📝 next/fontを使ってカスタムフォントを追加する方法
- 🖼️ next/imageを使って画像を追加する方法
- ✅ Next.jsでフォントと画像がどのように最適化されるか
なぜフォントを最適化するのか?
フォントはウェブサイトのデザインに重要な役割を果たしますが、フォントファイルをフェッチしてロードする必要がある場合、プロジェクトでカスタムフォントを使用するとパフォーマンスに影響を与える可能性があります。
累積レイアウトずれ(CLS)は、ウェブサイトのパフォーマンスとユーザーエクスペリエンスを評価するためにGoogleが使用するメトリックです。フォントの場合、ブラウザが最初にテキストをフォールバックまたはシステムフォントでレンダリングし、カスタムフォントがロードされるとそれに置き換えられるときにレイアウトずれが発生します。このスワップにより、テキストのサイズ、間隔、またはレイアウトが変更され、周囲の要素がシフトする可能性があります。
next/font
モジュールを使用すると、Next.jsはアプリケーションのフォントを自動的に最適化します。ビルド時にフォントファイルをダウンロードし、他の静的アセットとともにホストします。つまり、ユーザーがアプリケーションにアクセスしたときに、パフォーマンスに影響を与えるようなフォントの追加のネットワークリクエストはありません。
クイズの時間です!
知識をテストし、学んだことを確認しましょう。Next.jsはどのようにフォントを最適化しますか?
A. パフォーマンスを向上させる追加のネットワークリクエストを引き起こします。
B. すべてのカスタムフォントを無効にします。
C. 実行時にすべてのフォントをプリロードします。
D. フォントファイルを他の静的アセットとともにホストするので、追加のネットワークリクエストはありません。
解答
D. フォントファイルを他の静的アセットとともにホストするので、追加のネットワークリクエストはありません。
Next.jsはビルド時にフォントファイルをダウンロードし、他の静的アセットと一緒にホストします。つまり、ユーザーがアプリケーションにアクセスしたときに、パフォーマンスに影響するようなフォントの追加ネットワークリクエストは発生しません。
プライマリフォントの追加
これがどのように機能するかを確認するために、カスタムのGoogleフォントをアプリケーションに追加しましょう!
/app/ui
フォルダに、fonts.ts
という新しいファイルを作成します。このファイルは、アプリケーション全体で使用されるフォントを保持するために使用します。
next/font/google
モジュールからInter
フォントをインポートします。これがプライマリフォントになります。次に、ロードするサブセットを指定します。この場合は'latin'です:
+import { Inter } from 'next/font/google';
+export const inter = Inter({ subsets: ['latin'] });
最後に、/app/layout.tsx
の<body>
要素にフォントを追加します:
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>
// ...
);
}
最後に、<AcmeLogo />
コンポーネントもLusitana
を使用しています。エラーを防ぐためにコメントアウトされていたので、コメントを外すことができます:
// ...
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>
);
}
以下のようにロゴが表示されるはずです:
素晴らしい、アプリケーションに2つのカスタムフォントを追加しました!次に、ホームページにヒーロー画像を追加しましょう。
なぜ画像を最適化するのか?
Next.jsは、トップレベルの/public
フォルダの下にある画像などの静的アセットを提供できます。/public
内のファイルは、アプリケーションで参照できます。
通常のHTMLでは、次のように画像を追加します:
<img
src="/hero.png"
alt="Screenshots of the dashboard project showing desktop version"
/>
しかし、これは以下のことを手動で行う必要があることを意味します:
- 画像がさまざまな画面サイズでレスポンシブになるようにします。
- さまざまなデバイス用に画像サイズを指定します。
- 画像の読み込み時のレイアウトずれを防ぎます。
- ユーザーのビューポートの外にある画像を遅延ロードします。
画像最適化は、Web開発における大きなトピックであり、それ自体が専門分野と見なされる可能性があります。これらの最適化を手動で実装する代わりに、next/image
コンポーネントを使用して画像を自動的に最適化できます。
<Image>
コンポーネント
<Image>
コンポーネントは、HTML<img>
タグの拡張機能であり、以下のような自動画像最適化機能が付属しています:
- 画像の読み込み時のレイアウトずれを自動的に防ぎます。
- 大きな画像をビューポートが小さいデバイスに送信しないように、画像のサイズを変更します。
- デフォルトで画像を遅延ロードします(画像はビューポートに入るときにロードされます)。
- ブラウザがサポートしている場合は、WebPやAVIFなどの最新の形式で画像を提供します。
デスクトップ版ヒーロー画像の追加
<Image>
コンポーネントを使ってみましょう。/public
フォルダの中を見ると、hero-desktop.png
とhero-mobile.png
の2つの画像があることがわかります。これら2つの画像は完全に異なるものであり、ユーザーのデバイスがデスクトップかモバイルかによって表示されます。
/app/page.tsx
ファイルで、next/image
からコンポーネントをインポートします。次に、コメントの下に画像を追加します:
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">
{/* ここにヒーロー画像を追加 */}
+ <Image
+ src="/hero-desktop.png"
+ width={1000}
+ height={760}
+ className="hidden md:block"
+ alt="Screenshots of the dashboard project showing desktop version"
+ />
</div>
//...
);
}
ここでは、width
を1000
ピクセル、heirht
を760
ピクセルに設定しています。レイアウトずれを避けるために画像の幅と高さを設定することをお勧めします。これらは、ソース画像と同じアスペクト比である必要があります。
また、モバイル画面でDOMから画像を削除するためのhidden
クラスと、デスクトップ画面で画像を表示するためのmd:block
クラスも確認できます。
メモ:mdブレークポイント
Tailwindでは、ユーティリティクラスにブレークポイントのプレフィックス(md,lgなど)を付けることで、特定の画面サイズでのみ適用されるようにできます。
md:blockを指定すると、mdブレークポイント(デフォルトでは画面幅768px)以上の画面サイズで要素をdisplay: block;にして表示します。
hidden
md:block
という組み合わせは以下のように動作します:
-
画面幅が768px未満(モバイルサイズ)の場合、hiddenクラスが適用され要素は非表示になります。md:blockクラスは無視されます。
-
画面幅が768px以上(中型サイズ以上)の場合、hiddenクラスは上書きされ、md:blockクラスによって要素が表示されます。
これで、ホームページは次のようになっているはずです:
練習:モバイル版ヒーロー画像の追加
今度はあなたの番です!追加したばかりの画像の下に、hero-mobile.png
用に別の<Image>
コンポーネントを追加してください。
- 画像の
width
を560
ピクセル、heirht
を620
ピクセルにしてください。 - モバイル画面で表示され、デスクトップで非表示になるようにしてください。開発者ツールを使用して、デスクトップ画像とモバイル画像が正しく切り替わっているかどうかを確認できます。
準備ができたら、以下のコードスニペットを展開して解答確認してください。
解答
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">
{/* ここにヒーロー画像を追加 */}
<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>
//...
);
}
素晴らしい!あなたのホームページには、カスタムフォントとヒーロー画像が表示されるようになりました。
クイズの時間です!
知識をテストし、学んだことを確認しましょう。正しいか誤りか:ディメンションのない画像とWebフォントは、レイアウトずれの一般的な原因です。
A. 正しい
B. 誤り
解答
A. 正しい
寸法のない画像やウェブフォントは、ブラウザが追加リソースをダウンロードする必要があるため、レイアウトずれの一般的な原因です。
おすすめの読み物
これらのトピックについては、リモート画像の最適化やローカルフォントファイルの使用など、さらに多くのことを学ぶことができます。フォントと画像の詳細について知りたい場合は、以下を参照してください:
次の章
Discussion