Storybook と Design Tokens:ブランド統一の極意

現代の Web 開発において、ブランドの一貫性を保つことは成功の鍵となります。しかし、複数の開発者が関わるプロジェクトでは、デザインの統一を保つのが困難になることがあります。そんな課題を解決するのが、Storybook と Design Tokens の組み合わせです。
この記事では、Design Tokens の基本概念から、Storybook での実装方法、そしてブランド統一を実現するための実践的なテクニックまで、段階的に解説していきます。開発チーム全体で一貫したデザインシステムを構築し、ブランドの価値を最大化する方法を学んでいきましょう。
Design Tokens とは何か
Design Tokens は、デザインシステムの基盤となる最小単位のデザイン要素です。色、フォント、スペーシング、ボーダー半径などの値を変数として定義し、一貫したデザインを実現するための仕組みです。
Design Tokens の基本構造
Design Tokens は階層構造で管理され、以下のような形で定義されます:
json{
"color": {
"primary": {
"50": "#eff6ff",
"500": "#3b82f6",
"900": "#1e3a8a"
},
"secondary": {
"50": "#f8fafc",
"500": "#64748b",
"900": "#0f172a"
}
},
"typography": {
"fontSize": {
"xs": "0.75rem",
"sm": "0.875rem",
"base": "1rem",
"lg": "1.125rem",
"xl": "1.25rem"
},
"fontWeight": {
"normal": "400",
"medium": "500",
"semibold": "600",
"bold": "700"
}
},
"spacing": {
"xs": "0.25rem",
"sm": "0.5rem",
"md": "1rem",
"lg": "1.5rem",
"xl": "2rem"
}
}
この構造により、デザインの変更が必要な場合でも、トークンの値を変更するだけで全体に反映されるため、保守性が大幅に向上します。
Design Tokens の種類と役割
Design Tokens には主に以下の種類があります:
- Color Tokens: ブランドカラー、セマンティックカラー(success、error、warning)
- Typography Tokens: フォントサイズ、フォントウェイト、行間
- Spacing Tokens: マージン、パディング、ギャップ
- Border Tokens: ボーダー半径、ボーダー幅、ボーダーカラー
- Shadow Tokens: ドロップシャドウ、ボックスシャドウ
- Animation Tokens: トランジション時間、イージング関数
Storybook で Design Tokens を活用する理由
Storybook は UI コンポーネントの開発・テスト・ドキュメント化を効率化するツールですが、Design Tokens と組み合わせることで、さらに強力なデザインシステムを構築できます。
Storybook と Design Tokens の相乗効果
- 一貫性の保証: Design Tokens を使用することで、すべてのコンポーネントで同じデザイン値が使用されます
- 変更の容易さ: トークンの値を変更するだけで、関連するすべてのコンポーネントが自動的に更新されます
- チーム間の連携: デザイナーと開発者が同じトークンを参照することで、コミュニケーションが円滑になります
- 品質の向上: デザインの一貫性が保たれることで、ユーザー体験が向上します
よくある課題と Design Tokens による解決
従来の開発では、以下のような課題が発生していました:
css/* 問題のある従来のアプローチ */
.button-primary {
background-color: #3b82f6; /* ハードコードされた色 */
padding: 12px 24px; /* マジックナンバー */
border-radius: 6px; /* 一貫性のない値 */
}
.button-secondary {
background-color: #64748b; /* 異なる色の定義方法 */
padding: 10px 20px; /* 異なるスペーシング */
border-radius: 4px; /* 異なるボーダー半径 */
}
Design Tokens を使用することで、これらの問題を解決できます:
css/* Design Tokens を使用した改善されたアプローチ */
.button-primary {
background-color: var(--color-primary-500);
padding: var(--spacing-md) var(--spacing-lg);
border-radius: var(--border-radius-md);
}
.button-secondary {
background-color: var(--color-secondary-500);
padding: var(--spacing-md) var(--spacing-lg);
border-radius: var(--border-radius-md);
}
Design Tokens の設計と管理方法
効果的な Design Tokens システムを構築するためには、適切な設計と管理方法が重要です。
Design Tokens の設計原則
- セマンティック命名: 用途を明確に示す名前を使用する
- 階層構造: 論理的な階層でトークンを整理する
- 拡張性: 将来の変更に対応できる柔軟な構造にする
- 一貫性: 命名規則と値の定義方法を統一する
推奨される Design Tokens の構造
json{
"global": {
"color": {
"brand": {
"primary": {
"value": "#3b82f6",
"type": "color"
},
"secondary": {
"value": "#64748b",
"type": "color"
}
},
"semantic": {
"success": {
"value": "#10b981",
"type": "color"
},
"error": {
"value": "#ef4444",
"type": "color"
},
"warning": {
"value": "#f59e0b",
"type": "color"
}
}
},
"typography": {
"fontFamily": {
"primary": {
"value": "Inter, system-ui, sans-serif",
"type": "fontFamily"
}
},
"fontSize": {
"xs": {
"value": "0.75rem",
"type": "fontSize"
},
"sm": {
"value": "0.875rem",
"type": "fontSize"
},
"base": {
"value": "1rem",
"type": "fontSize"
}
}
}
}
}
Design Tokens の管理ツール
Design Tokens を効率的に管理するために、以下のツールが活用できます:
- Style Dictionary: Amazon が開発した Design Tokens 変換ツール
- Theo: Salesforce が開発した Design Tokens 管理ツール
- Figma Tokens: Figma プラグインで Design Tokens を管理
- Design Tokens Studio: ブラウザベースの Design Tokens エディタ
Style Dictionary を使用した Design Tokens 管理
Style Dictionary を使用すると、Design Tokens を複数のプラットフォーム向けに変換できます:
javascript// style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'dist/css/',
files: [
{
destination: 'tokens.css',
format: 'css/variables',
},
],
},
scss: {
transformGroup: 'scss',
buildPath: 'dist/scss/',
files: [
{
destination: '_tokens.scss',
format: 'scss/variables',
},
],
},
},
};
Storybook での Design Tokens 実装手順
Storybook で Design Tokens を実装する具体的な手順を説明します。
1. 必要なパッケージのインストール
まず、必要なパッケージをインストールします:
bashyarn add -D @storybook/addon-styling style-dictionary
yarn add -D @storybook/addon-themes
2. Storybook の設定ファイルの更新
.storybook/main.js
ファイルを更新して、Design Tokens のサポートを追加します:
javascript// .storybook/main.js
module.exports = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-styling',
'@storybook/addon-themes',
],
framework: {
name: '@storybook/react-webpack5',
options: {},
},
docs: {
autodocs: 'tag',
},
};
3. Design Tokens の定義
tokens/
ディレクトリを作成し、Design Tokens を定義します:
json// tokens/colors.json
{
"color": {
"brand": {
"primary": {
"50": { "value": "#eff6ff" },
"100": { "value": "#dbeafe" },
"500": { "value": "#3b82f6" },
"600": { "value": "#2563eb" },
"900": { "value": "#1e3a8a" }
},
"secondary": {
"50": { "value": "#f8fafc" },
"100": { "value": "#f1f5f9" },
"500": { "value": "#64748b" },
"600": { "value": "#475569" },
"900": { "value": "#0f172a" }
}
},
"semantic": {
"success": { "value": "#10b981" },
"error": { "value": "#ef4444" },
"warning": { "value": "#f59e0b" },
"info": { "value": "#3b82f6" }
}
}
}
4. CSS 変数の生成
Style Dictionary を使用して CSS 変数を生成します:
javascript// scripts/build-tokens.js
const StyleDictionary = require('style-dictionary');
const styleDictionary = StyleDictionary.extend({
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'src/styles/',
files: [
{
destination: 'tokens.css',
format: 'css/variables',
options: {
showFileHeader: true,
},
},
],
},
},
});
styleDictionary.buildAllPlatforms();
5. Storybook での Design Tokens の読み込み
.storybook/preview.js
ファイルで Design Tokens を読み込みます:
javascript// .storybook/preview.js
import '../src/styles/tokens.css';
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
themes: {
default: 'light',
list: [
{
name: 'light',
class: 'theme-light',
color: '#ffffff',
},
{
name: 'dark',
class: 'theme-dark',
color: '#000000',
},
],
},
};
6. コンポーネントでの Design Tokens の使用
コンポーネントで Design Tokens を使用します:
tsx// src/components/Button/Button.tsx
import React from 'react';
import './Button.css';
interface ButtonProps {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
children: React.ReactNode;
onClick?: () => void;
}
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
children,
onClick,
}) => {
return (
<button
className={`button button--${variant} button--${size}`}
onClick={onClick}
>
{children}
</button>
);
};
css/* src/components/Button/Button.css */
.button {
border: none;
border-radius: var(--border-radius-md);
font-family: var(--font-family-primary);
font-weight: var(--font-weight-medium);
cursor: pointer;
transition: all var(--transition-duration-fast);
}
.button--primary {
background-color: var(--color-brand-primary-500);
color: var(--color-white);
}
.button--primary:hover {
background-color: var(--color-brand-primary-600);
}
.button--secondary {
background-color: var(--color-brand-secondary-500);
color: var(--color-white);
}
.button--secondary:hover {
background-color: var(--color-brand-secondary-600);
}
.button--sm {
padding: var(--spacing-xs) var(--spacing-sm);
font-size: var(--font-size-sm);
}
.button--md {
padding: var(--spacing-sm) var(--spacing-md);
font-size: var(--font-size-base);
}
.button--lg {
padding: var(--spacing-md) var(--spacing-lg);
font-size: var(--font-size-lg);
}
7. Storybook ストーリーの作成
Design Tokens を使用したコンポーネントのストーリーを作成します:
tsx// src/components/Button/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: { type: 'select' },
options: ['primary', 'secondary'],
},
size: {
control: { type: 'select' },
options: ['sm', 'md', 'lg'],
},
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Primary Button',
},
};
export const Secondary: Story = {
args: {
variant: 'secondary',
children: 'Secondary Button',
},
};
export const Small: Story = {
args: {
size: 'sm',
children: 'Small Button',
},
};
export const Large: Story = {
args: {
size: 'lg',
children: 'Large Button',
},
};
ブランド統一を実現する Design Tokens の活用パターン
Design Tokens を効果的に活用してブランド統一を実現するための実践的なパターンを紹介します。
1. セマンティックカラーの活用
ブランドの意味を明確に伝えるセマンティックカラーを定義します:
json// tokens/semantic-colors.json
{
"color": {
"semantic": {
"success": {
"value": "#10b981",
"type": "color",
"description": "成功状態を示す色"
},
"error": {
"value": "#ef4444",
"type": "color",
"description": "エラー状態を示す色"
},
"warning": {
"value": "#f59e0b",
"type": "color",
"description": "警告状態を示す色"
},
"info": {
"value": "#3b82f6",
"type": "color",
"description": "情報状態を示す色"
}
}
}
}
2. レスポンシブデザインのためのトークン
異なる画面サイズに対応するためのトークンを定義します:
json// tokens/breakpoints.json
{
"breakpoint": {
"mobile": {
"value": "320px",
"type": "size"
},
"tablet": {
"value": "768px",
"type": "size"
},
"desktop": {
"value": "1024px",
"type": "size"
},
"wide": {
"value": "1440px",
"type": "size"
}
}
}
3. アニメーションとトランジションの統一
ブランドの動きを統一するためのアニメーショントークンを定義します:
json// tokens/animation.json
{
"animation": {
"duration": {
"fast": {
"value": "150ms",
"type": "time"
},
"normal": {
"value": "250ms",
"type": "time"
},
"slow": {
"value": "350ms",
"type": "time"
}
},
"easing": {
"ease-in": {
"value": "cubic-bezier(0.4, 0, 1, 1)",
"type": "cubicBezier"
},
"ease-out": {
"value": "cubic-bezier(0, 0, 0.2, 1)",
"type": "cubicBezier"
},
"ease-in-out": {
"value": "cubic-bezier(0.4, 0, 0.2, 1)",
"type": "cubicBezier"
}
}
}
}
4. ダークモード対応
ダークモードに対応するためのトークンを定義します:
json// tokens/dark-mode.json
{
"color": {
"background": {
"primary": {
"value": "#ffffff",
"type": "color",
"darkValue": "#1a1a1a"
},
"secondary": {
"value": "#f8fafc",
"type": "color",
"darkValue": "#2a2a2a"
}
},
"text": {
"primary": {
"value": "#1e293b",
"type": "color",
"darkValue": "#f1f5f9"
},
"secondary": {
"value": "#64748b",
"type": "color",
"darkValue": "#94a3b8"
}
}
}
}
5. アクセシビリティ対応
アクセシビリティを考慮したトークンを定義します:
json// tokens/accessibility.json
{
"color": {
"contrast": {
"high": {
"value": "4.5:1",
"type": "ratio"
},
"medium": {
"value": "3:1",
"type": "ratio"
}
}
},
"spacing": {
"touch": {
"minimum": {
"value": "44px",
"type": "size",
"description": "タッチターゲットの最小サイズ"
}
}
}
}
チーム開発での Design Tokens 運用ベストプラクティス
チーム全体で Design Tokens を効果的に運用するためのベストプラクティスを紹介します。
1. 命名規則の統一
チーム全体で一貫した命名規則を使用します:
javascript// 推奨される命名規則
const namingConventions = {
// セマンティック命名
semantic: {
color: 'color-semantic-success',
spacing: 'spacing-component-button-padding',
typography: 'typography-heading-h1',
},
// 階層構造
hierarchy: {
global: 'global-color-brand-primary',
component: 'component-button-primary-background',
state: 'state-hover-background',
},
};
2. バージョン管理と変更履歴
Design Tokens の変更を適切に管理します:
json// tokens/version.json
{
"version": "1.2.0",
"changes": [
{
"version": "1.2.0",
"date": "2024-01-15",
"changes": [
"Added new semantic color tokens for improved accessibility",
"Updated primary brand color to match new brand guidelines",
"Deprecated old spacing tokens in favor of new scale"
]
}
]
}
3. 自動化と CI/CD パイプライン
Design Tokens の更新を自動化します:
yaml# .github/workflows/design-tokens.yml
name: Design Tokens CI
on:
push:
paths:
- 'tokens/**/*.json'
pull_request:
paths:
- 'tokens/**/*.json'
jobs:
build-tokens:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'yarn'
- name: Install dependencies
run: yarn install
- name: Build design tokens
run: yarn build:tokens
- name: Run tests
run: yarn test:tokens
- name: Create pull request
if: github.event_name == 'push'
uses: peter-evans/create-pull-request@v4
with:
title: 'Update design tokens'
body: 'Automatically generated from design tokens changes'
branch: update-design-tokens
4. ドキュメント化とガイドライン
Design Tokens の使用方法を明確にドキュメント化します:
markdown# Design Tokens ガイドライン
# 使用方法
## 色の使用
- ブランドカラー: `var(--color-brand-primary-500)`
- セマンティックカラー: `var(--color-semantic-success)`
- 背景色: `var(--color-background-primary)`
## スペーシングの使用
- コンポーネント内: `var(--spacing-sm)`
- セクション間: `var(--spacing-lg)`
- ページ全体: `var(--spacing-xl)`
## タイポグラフィの使用
- 見出し: `var(--font-size-xl)`
- 本文: `var(--font-size-base)`
- キャプション: `var(--font-size-sm)`
# 禁止事項
- ハードコードされた値の使用
- 既存トークンと異なる命名規則の使用
- セマンティックでない色の直接指定
5. 品質保証とテスト
Design Tokens の品質を保証するためのテストを実装します:
javascript// tests/design-tokens.test.js
const fs = require('fs');
const path = require('path');
describe('Design Tokens', () => {
test('should have valid JSON structure', () => {
const tokensPath = path.join(__dirname, '../tokens');
const tokenFiles = getAllJsonFiles(tokensPath);
tokenFiles.forEach((file) => {
const content = fs.readFileSync(file, 'utf8');
expect(() => JSON.parse(content)).not.toThrow();
});
});
test('should have consistent naming conventions', () => {
const tokens = loadAllTokens();
Object.keys(tokens).forEach((category) => {
Object.keys(tokens[category]).forEach((token) => {
expect(token).toMatch(/^[a-z][a-z0-9-]*$/);
});
});
});
test('should have valid color values', () => {
const tokens = loadAllTokens();
if (tokens.color) {
Object.values(tokens.color).forEach((colorToken) => {
if (colorToken.value) {
expect(colorToken.value).toMatch(
/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
);
}
});
}
});
});
function getAllJsonFiles(dir) {
// 実装省略
}
function loadAllTokens() {
// 実装省略
}
6. よくあるエラーと対処法
Design Tokens の実装でよく発生するエラーとその対処法を紹介します:
エラー 1: CSS 変数が未定義
css/* エラー: CSS 変数が未定義 */
.button {
background-color: var(
--color-primary-500
); /* 未定義の変数 */
}
対処法: Design Tokens のビルドプロセスを確認し、CSS ファイルが正しく生成されているかチェックします。
bash# ビルドプロセスの確認
yarn build:tokens
cat src/styles/tokens.css
エラー 2: 型の不一致
typescript// エラー: 型の不一致
interface ButtonProps {
variant: 'primary' | 'secondary' | 'invalid'; // 存在しないバリアント
}
対処法: TypeScript の型定義を Design Tokens から自動生成します。
javascript// scripts/generate-types.js
const StyleDictionary = require('style-dictionary');
const styleDictionary = StyleDictionary.extend({
source: ['tokens/**/*.json'],
platforms: {
typescript: {
transformGroup: 'typescript',
buildPath: 'src/types/',
files: [
{
destination: 'design-tokens.ts',
format: 'typescript/module',
},
],
},
},
});
エラー 3: パフォーマンスの問題
css/* 問題: 大量の CSS 変数によるパフォーマンス低下 */
:root {
/* 数百個の CSS 変数 */
}
対処法: 必要なトークンのみをインポートする仕組みを構築します。
javascript// utils/token-loader.js
export function loadTokens(categories = []) {
const tokens = {};
categories.forEach((category) => {
const categoryTokens = require(`../tokens/${category}.json`);
Object.assign(tokens, categoryTokens);
});
return tokens;
}
まとめ
Storybook と Design Tokens を組み合わせることで、ブランド統一を実現し、開発効率を大幅に向上させることができます。
この記事で紹介した手法を実践することで、以下のような効果が期待できます:
- 一貫性の向上: すべてのコンポーネントで統一されたデザインが実現されます
- 開発効率の向上: デザインの変更が容易になり、開発速度が向上します
- チーム間の連携強化: デザイナーと開発者のコミュニケーションが円滑になります
- 品質の向上: デザインの一貫性により、ユーザー体験が向上します
- 保守性の向上: デザインの変更が一箇所で管理できるようになります
Design Tokens の導入は、最初は少し手間がかかるかもしれませんが、長期的に見れば大きな投資対効果を得ることができます。チーム全体で一貫したデザインシステムを構築し、ブランドの価値を最大化していきましょう。
関連リンク
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来