Atomic Designを用いたコンポーネントの実装について(atoms〜organisms)
Published on February 19, 2025
Category: メモ
基本方針
- 一貫した実装が可能であること
- 実装者とデザイナー間で認識を共有できる状態を作ること
スタイリング方針の選択肢
1. 自前でCSSを実装する場合
必要な定義
- クラスの命名規則
- CSS実装方法の選定
- CSS in JS
- CSS modules
- Sass
- CSSのスタイル管理方法
特徴と課題
- 自由にスタイリングが可能
- デザイナーとエンジニアの認識が異なりやすい
- 1つのタグごとに以下の細かい認識合わせが必要:
- px指定
- フォント設定
- その他の詳細なスタイル
- 認識合わせを行わない場合、デザイナーがイメージしているUXと全く異なる結果になる
2. CSSフレームワークを使用する場合
必要な定義:
- ライブラリの選定
- ライブラリの運用認識確認
利点:
- 定義されているクラスに則ることで、デザイナーとエンジニアの細かいスタイルの認識調整が軽減される
- ベースとなる基準があるため、細かいことは考えずにUI実装に注力できる
Atomic Designの実装方針
基本原則
- コンポーネントを作成しすぎない
- コンポーネントを作成する際、基準をどこに持っていくか考える
各レイヤーの詳細
Atoms(原子)
- 最小単位のコンポーネント
- 基本的なスタイルの状態を提供する必要がある
Molecules(分子)
基本概念:
- 再利用できるコンポーネント
- ユースケースでコンポーネントを作成する
実装アプローチの変更点
当初の理解:
- molecules/Cardのような組み合わせを作成し、Storyごとにユースケースで場合分けする
改善後の方針
- ユースケースごとにコンポーネントを分ける
- molecules/ImageCard
- molecules/TextCard
- molecules/CardList
実装の重要ポイント
- 個別の処理/スタイリングについて
- 各コンポーネント内で完結させる
- そのユースケースが持つ個別の動作をコンポーネント内にカプセル化
- スタイルも各コンポーネントで管理
- 外部との関係
- 外部ではそのコンポーネントに関する情報は一切持たせない
- organismsでmoleculesを参照する場合
呼び出し元 → 参照するコンポーネント
の流れで依存- 参照するコンポーネントは呼び出し元の情報を知らない状態を維持
- 呼び出し元が全てclassNameでスタイルを渡すことでorganisms独立のスタイルを反映することができる。
- スタイル打ち消しの例:
- atoms/Cardに
Padding:10px
の設定がある場合 - molecules/ImageCardでPaddingが不要な場合
- molecules/ImageCard内で打ち消す
- atoms/Cardに
ユースケースで管理する理由
- molecules/Cardのように複数の使い方が考えられる実装を避ける
- 実装者の判断による統一性の欠如を防ぐ
- コンポーネントの実装の複雑化を防ぐ
- コンポーネントの役割と独立性を明確にする
問題のある実装例:
// molecules/card/index.tsx
import React, { ComponentProps } from "react";
import { Card as BaseCard } from "../../../shadcn/card";
import { cn } from "../../../utils";
import { cardVariants, type CardVariants } from "./index.variants";
type CardProps = ComponentProps<typeof BaseCard> & CardVariants;
export const Card = ({ size, background, layout, spacing, className, ...props }: CardProps) => {
return (
<BaseCard
className={cn(cardVariants({ size, background, layout, spacing }), className)}
{...props}
/>
);
};
export type { CardProps };
// molecules/card/index.variants.ts
import { cva, VariantProps } from "class-variance-authority";
const cardVariants = cva(
"flex flex-col items-start bg-card rounded-[8px] border border-[#E4E4E7] text-card-foreground bg-white shadow-[0px_1px_2px_0px_rgba(0,0,0,0.05)]",
{
variants: {
size: {
default: "min-w-[248px] min-h-[348px]",
},
background: {
default: "bg-white",
gray: "bg-[#F5F5F5]",
},
layout: {
fixed: "w-fit",
},
spacing: {
normal: "p-6",
},
},
defaultVariants: {
size: "default",
background: "default",
layout: "fixed",
spacing: "normal",
},
}
);
type CardVariants = VariantProps<typeof cardVariants>;
export { cardVariants, type CardVariants };
このコードの問題点
- Cardの複数のユースケースのスタイリングを一つのコンポーネントで保持している
- どの時にコンポーネントのスタイルを適用するか判断が人によって変わる。
Organisms(有機体)
- 特定の機能を提供する時の箱のような存在
- moleculesのユースケースを複数組み合わせたもの
- 複数の条件を持ち、特定の条件がマッチすることによって動作を制御
具体例: Google Formのような構造
- 各moleculesのカードコンポーネントが集結
- それぞれの制約をコンポーネントごとに保持
.png)
実装上の重要な注意点
- コンポーネントの役割の明確化
- 依存関係の一方向性の維持
- カプセル化の徹底
- ユースケースベースでの分割
- スタイリングの責任範囲の明確化