NextTurotial
2.CSS Styling
Tailwind
css に以下のような感じで tailwind ディレクティブを書き込むと各スタイリングが import される
@tailwind base;
@tailwind components;
@tailwind utilities;
以下のようにクラス名を tailwind のルールに則って命名するといい感じのスタイルが当たる
<h1 className="text-blue-500">I'm blue!</h1>
CSS Modules
home.module.css
のように modules
を含めた名前で命名すると、css をモジュールとして利用できる。
import して別名を付けて、クラス名で呼び出せるよう。
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import styles from '@/app/ui/home.module.css';
export default function Page() {
return (
<main className="flex min-h-screen flex-col p-6">
<div className={styles.shape} />
// ...
)
}
Tailwind を使うか CSS Modules のどちらを使うかは好みによるので、どっちでも良いし、なんなら両立しても良い。
clsx
動的にスタイルを変えたい場合に用いる。
例えばボタンの活性/非活性をコントロールしたい場合など。
以下のように記述する。
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import styles from '@/app/ui/home.module.css';
export default function Page() {
return (
<main className="flex min-h-screen flex-col p-6">
<div className={styles.shape} />
// ...
)
}
3. Optimize Fonts and Images(フォントと画像の最適化)
なぜフォントを最適化する必要があるのか
カスタムフォントはデザインに必須だが、追加でダウンロードが発生するためパフォーマンスに影響する可能性があるため。
また、Google のウェブサイト評価には累積レイアウトシフトなるものがある。
Webページの表示の際、まずはデフォルトのフォントがロードされ、その後追加でカスタムフォントがダウンロードされて置き換わる。
その際にレイアウトがズレることがある。これがレイアウトシフト。
Next.js では next/font
を使えばモジュールの利用するフォントを最適化してくれる。
ビルド時にフォントをダウンロードし、静的アセットとしてホストするため、追加のリクエストも発生しない。
なぜ画像を最適化する必要があるのか
/public
配下に静的アセットを配置するとアプリケーションから参照できる。
従来の html では普通にやると以下のようになる。
<img
src="/hero.png"
alt="Screenshots of the dashboard project showing desktop version"
/>
画像によるレイアウト崩れや遅延ロードなどを考えたり色々手動でやるとしんどい。
next/image
を使えば簡単に実装できる。
<Image>
コンポーネントは以下の機能を持つ。
- 画像サイズの自動調整
- 遅延ロード
- ブラウザが対応していれば WEBP などに変換
画像は以下のような感じでデスクトップ/モバイルで出し分けられる。
<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>
className
がポイント。
block
は display: block
を表す。
md:hidden
はレスポンシブ用のやつ。
md
部分は画面サイズを表す。
md
サイズ以上の画面 = PC や ipad でのブラウザ視聴と考えて良さそう。
また、一般的に画像の with と height を決めておくのはデザイン崩れの予防になるので忘れないようにしよう。
4. Creating Layouts and Pages
ルーティング
ディレクトリ構造がそのままルーティングとなる。
page.tsx
という名前のファイルがあると、ページとして認識される。
例えば app/page.tsx
-> /
、app/dashboard/page.tsx
-> /dashboard
といった具合。
共通レイアウト
layout.tsx
を配置して、複数のページで共有される UI を定義できる。
<Layout /> コンポーネントは children
props を受け取り、これが子ページとなる。
layout.tsx
より下にあるページは , Layout コンポーネントの中に自動的にネストされる。
import SideNav from '@/app/ui/dashboard/sidenav';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
<div className="w-full flex-none md:w-64">
<SideNav />
</div>
<div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
</div>
);
}
Next.js ではレイアウトを使うとページコンポーネントだけが更新され、レイアウトは再レンダリングされないという利点がある。
これを partial rendering と呼ぶ。
ちなみに 3 章で inter フォントを設定した app/layout.tsx
の RootLayout
は必須。
メタデータはここで設定する。
5. Navigating Between Pages
Link コンポーネント
<Link />
コンポーネントを使うことでクライアントサイドナビゲーションを実現できる。
使い方はほとんど a タグと同じ。
Link を使うだけでページ更新を挟まず、差分だけが更新される。
import {
UserGroupIcon,
HomeIcon,
DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
// ...
export default function NavLinks() {
return (
<>
{links.map((link) => {
const LinkIcon = link.icon;
return (
<Link
key={link.name}
href={link.href}
className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
>
<LinkIcon className="w-6" />
<p className="hidden md:block">{link.name}</p>
</Link>
);
})}
</>
);
}
実は Next.js はナビゲーション体験向上のため、自動的にルートセグメント毎にコードを分割している。
これによって、どこかのページがエラーを起こしても他は動作するという副作用もある。
Link コンポーネントが表示されるたび、そのリンク先をプリフェッチするため、リンク先をクリックするころにはすべて読み込まれているということになる。
パターン: アクティブリンクの表示
ユーザの現在いる場所へのリンクを表示するためにはパスを取得する必要がある。
そういった場合usePathName()
hook を使えば良い。
これは hook なので React の use client
ディレクティブが必要なことに注意。
use client
はサーバサイドの React を併用する際に、このコンポーネントはクライアントサイドで動作するものであることを示すために使う。
'use client';
import {
UserGroupIcon,
HomeIcon,
InboxIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
// ...
clsx を利用すれば、usePathName で取得したリンクと現在地が同じ時に、リンクに特定のスタイルを当てるということが実現できる。
<Link
key={link.name}
href={link.href}
className={clsx(
'flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3',
{
'bg-sky-100 text-blue-600': pathname === link.href,
},
)}
>