Next.js プロジェクトのスタイリングで一番好きな組み合わせ | css modules, scss, Radix UI
はじめに
今回は、Next.jsプロジェクトを始めたばかりで、スタイリングをどうしようか悩んでいる人に向けて、個人的に一番だと思っている構成について紹介します!
各ライブラリの概要とメリット
CSS Modules + Scss について
CSS Modulesとは、CSSをモジュール化してJavaScriptプロジェクトに統合するための一つの方法です. 特にコンポーネントベースの開発フレームワークやライブラリ(React)との組み合わせで非常に有用です.
(Sass は、Next.jsに関係なく、これまでのシンプルなLPでも使われていたと思うので省略)
CSS Modules + Scss のメリット
- 1コンポーネント1スタイルファイルになるので、分かりやすい
- モジュール化されるので、クラス名の衝突が起きない
(素のCSSもどんどん進化しているので、Sassを使わない未来が訪れるかもしれません)
Radix UI について
Radix UIとは、Reactアプリケーション向けに設計された UIコンポーネントライブラリです. 開発者が独自のデザインシステムを構築できるように、スタイル未指定のプリミティブを提供していることが特徴です.
Radix UI のメリット
- スタイルがついていないので(機能のみ提供)、カスタマイズ性が高い
- アクセシビリティが重視された作りになっている
- デザインシステムの適用が容易
チームによっては、エンジニアがデザインに関しても担当するといった場合があると思います.
その時は、デザインシステムなんて用意しないかもしれません、そういったプロジェクトは、shadcn/ui でコンポーネントを生成するのがいいかもしれません.
(内部的には、Radix UI を使っているコンポーネントがいくつかあります)
環境構築
環境構築もしておきます.
- Next.jsプロジェクトを用意 (参考)
npx, yarn dlx, bunx お好きなツールで
pnpm dlx create-next-app@latest
tailwind を使うかどうかの質問だけ No を選択
- CSS Modules を導入 (参考)
Next.js プロジェクトでは、デフォルトで使えます.
.module.css ファイルを作成するだけでOK
試しに、Button コンポーネントを作成
import { ButtonHTMLAttributes, FC, ReactNode } from "react";
import styles from "./styles.module.css";
type Props = {
children: ReactNode | string;
} & ButtonHTMLAttributes<HTMLButtonElement>;
export const Button: FC<Props> = ({ children, ...rest }) => {
return (
<button className={styles.button} {...rest}>
{children}
</button>
);
};
.button {
padding: 10px 20px;
cursor: pointer;
color: #fff;
background-color: #4caf50;
border: none;
border-radius: 5px;
}
これを、app で import して使えてたらOK!
- Sass を導入 (参考)
下記コマンドでインストール
pnpm install --save-dev sass
先ほどの CSSファイルで、Sass の変数機能を試す
$button-bg-color: #4caf50;
.button {
padding: 10px 20px;
cursor: pointer;
color: #fff;
background-color: $button-bg-color;
border: none;
border-radius: 5px;
}
あとは、Button コンポーネントのスタイルを import しているファイル名を変更して完了
- Radix UI を導入 (参考)
ドキュメントを見ていると、primitives と themes があります.
primitives は純粋な機能だけを提供するコンポーネントで、themes はスタイルがいい感じについています.
今回使うのは primitives
Chakra UI などのライブラリは、一度インストールしたらさまざまなコンポーネントを import して使えますが、Radix UI は必要な機能を満たすコンポーネントだけをインストールします.
例えば、モーダル機能を作成したい!となったら
pnpm i @radix-ui/react-dialog
を実行して、dialog コンポーネントを使えるようにする.
"use client";
import React from "react";
import * as Dialog from "@radix-ui/react-dialog";
export const Modal = () => (
<Dialog.Root>
<Dialog.Trigger asChild>
<button>Click!</button>
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title>モーダルのタイトルだよ!</Dialog.Title>
<Dialog.Description>ここは、モーダルの説明書だよ</Dialog.Description>
<p>モーダルの中身はここに書いていくよ</p>
<Dialog.Close asChild>
<button>Close!</button>
</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
このように、必要なコンポーネントごとにインストールして使います.
まとめ
今回紹介した構成は、シンプルisベストでありながら、全てのケースに対応できると考えています. しかし、シンプルなので、他のライブラリに比べて自分たちで定義すべきコード量は増えます. 短期間で成果を出さないといけないプロジェクトには向かないかもしれません.
できるだけ、素のCSSに近い形で使えるので、ライブラリ特有の問題も、ほぼ0でしょう.
Discussion