Next.js

Next.jsのCSS入門:グローバルCSSとCSS Modulesの適用手順

この記事でわかること

Pages RouterでグローバルCSSとCSS Modulesを使う手順を解説。ファイルの配置、読み込み先、クラスの適用、スタイルの衝突を避ける考え方を紹介します。

Next.jsでは、アプリケーション全体の基本スタイルをグローバルCSSに、部品ごとの見た目をCSS Modulesに分けると管理しやすくなります。CSS Modulesはクラス名の衝突を避ける仕組みで、ファイル名を.module.cssで終わらせて利用します。

この記事はTypeScriptとPages Routerの構成を前提にします。ルートのpages/を使うプロジェクトでは、以下のパスからsrc/を除いて読み替えてください。

CSSを適用する手順

全体に適用するCSSを用意する

余白の初期値、文字の色、ボックスのサイズ計算などをsrc/styles/globals.cssへ書きます。

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  color: #172033;
  background: #f5f7fb;
  font-family: system-ui, sans-serif;
  line-height: 1.7;
}

button,
input {
  font: inherit;
}

a {
  color: #1d4ed8;
}

Pages Routerでは、グローバルCSSをsrc/pages/_app.tsxから読み込みます。既にこのファイルがあり、Providerやレイアウトを使っている場合は、それらを残したままimportを追加してください。次は最小構成です。

import type { AppProps } from 'next/app';
import '../styles/globals.css';

export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

グローバルCSSのセレクターはページ全体へ影響します。たとえばbuttonの背景色をここで一律指定すると、別の機能のボタンにも適用されます。全体に必要な基礎だけに絞ると、後から上書きする量を減らせます。

CSS Modulesでカードの見た目を定義する

カード用にsrc/components/ArticleCard.module.cssを作成します。

.card {
  width: min(100%, 40rem);
  margin-inline: auto;
  padding: clamp(1rem, 4vw, 2rem);
  border: 1px solid #d8deea;
  border-radius: 1rem;
  background: #fff;
  box-shadow: 0 0.5rem 1.5rem rgb(23 32 51 / 8%);
}

.title {
  margin-block: 0 0.5rem;
  font-size: clamp(1.25rem, 3vw, 1.75rem);
}

.link {
  display: inline-block;
  margin-top: 0.75rem;
  text-underline-offset: 0.2em;
}

.link:focus-visible {
  outline: 3px solid #2563eb;
  outline-offset: 4px;
}

width: min(100%, 40rem)で、小さい画面では親要素に収め、大きい画面では幅を制限しています。キーボード操作でリンクの位置が分かるよう、フォーカスの枠も残しています。

TypeScriptのコンポーネントから読み込む

src/components/ArticleCard.tsxを作成します。

import Link from 'next/link';
import styles from './ArticleCard.module.css';

type ArticleCardProps = {
  title: string;
  description: string;
  href: string;
};

export default function ArticleCard({
  title,
  description,
  href,
}: ArticleCardProps) {
  return (
    <article className={styles.card}>
      <h2 className={styles.title}>{title}</h2>
      <p>{description}</p>
      <Link className={styles.link} href={href}>記事を読む</Link>
    </article>
  );
}

CSSの.cardは、importされたstyles.cardから参照します。ビルド時には衝突しにくいクラス名へ変換されます。別のCSS Moduleで同じ.cardという名前を使っても、それぞれのローカルクラスとして扱われます。

ただし、CSS ModulesはShadow DOMのような完全な隔離ではありません。グローバルCSS、継承されるプロパティ、:globalで指定したルールは影響し得ます。また、同じModuleから取得したクラスを複数の部品に付ければ、当然それらすべてにスタイルが適用されます。

ページで表示する

src/pages/index.tsxからカードを読み込みます。この例のリンク先は、同じプロジェクトで作成する紹介ページの/aboutです。

import ArticleCard from '../components/ArticleCard';

export default function HomePage() {
  return (
    <main style={{ padding: '2rem 1rem' }}>
      <h1>開発ノート</h1>
      <ArticleCard
        title="このサイトについて"
        description="学習内容とサイトの使い方を紹介します。"
        href="/about"
      />
    </main>
  );
}

表示確認では画面幅を変え、文字の折り返し、横スクロール、キーボードでのフォーカスを確認します。CSSをimportしただけではクラスは付きません。見た目が変わらないときは、className={styles.card}の指定と、CSS側のクラス名が一致するか調べます。

App Routerとの違いと追加ライブラリ

App Routerでは、全体用CSSを通常src/app/layout.tsxから読み込みます。CSSを使うためだけに'use client'を付ける必要はありません。CSS Modulesはどちらのルーターでも利用できます。

通常のCSSとCSS Modulesは追加パッケージなしで使えます。Sassを使う場合は別途sassが必要です。Lessが標準でそのまま使えるという意味ではありません。最初は標準のCSSで構成を理解してから、必要な仕組みを追加すると判断しやすくなります。

関連記事と公式資料

部品の作り方はコンポーネントの作成と使用方法、全体の配置はディレクトリ構成と役割も参照してください。

スタイルが反映されないときの調べ方

読み込みとクラス名を確認する

CSSファイルが読み込まれているか、classNameに期待するクラスが付いているかを開発者ツールで確認します。CSS Modulesのクラスを文字列だけで指定せず、読み込んだオブジェクトから参照してください。

小さい画面でも操作する

デスクトップで収まっていても、長い見出しやコードで横にはみ出す場合があります。画面幅を変え、文字の折り返し、コード欄のスクロール、ボタンの操作を確認します。

Next.jsとは・ルーターの違い・学習順を確認する

y.
WRITTEN BY

y_ymo10

SEの部屋で、JavaScript・TypeScript・React.js・Next.jsの開発ノートを公開しています。

ほかの開発ノートを読む →