Design

Tailwind CSS ベストプラクティス完全ガイド

kitahara-dev2025/11/0212 min read
Tailwind CSS ベストプラクティス完全ガイド

Tailwind CSS ベストプラクティス完全ガイド

Tailwind CSSは、ユーティリティファーストのCSSフレームワークとして人気を集めています。このガイドでは、Tailwind CSSを効果的に使用するための実践的なベストプラクティスを網羅的に紹介します。

📋 目次

  1. カスタムテーマの設定
  2. コンポーネントの抽出とデザイントークン
  3. レスポンシブデザインの実装
  4. よくある間違いと解決策
  5. プラグインの活用
  6. パフォーマンスの最適化
  7. ダークモードの実装
  8. カスタムユーティリティクラス
  9. チーム開発での一貫性

1. カスタムテーマの設定

tailwind.config.tsでプロジェクト固有のテーマを定義し、デザインシステムを構築します。

基本的なカスタマイズ

// tailwind.config.ts
import type { Config } from 'tailwindcss';

const config: Config = {
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      colors: {
        // ブランドカラーの定義
        brand: {
          50: '#eff6ff',
          100: '#dbeafe',
          200: '#bfdbfe',
          500: '#3b82f6',
          600: '#2563eb',
          900: '#1e3a8a',
        },
        // セマンティックカラー
        primary: '#0066cc',
        secondary: '#6b7280',
        success: '#10b981',
        warning: '#f59e0b',
        error: '#ef4444',
      },
      // カスタムスペーシング
      spacing: {
        '128': '32rem',
        '144': '36rem',
      },
      // カスタムフォントサイズ
      fontSize: {
        'xxs': '0.625rem',
        'display': '4.5rem',
      },
      // カスタムブレークポイント
      screens: {
        'xs': '475px',
        '3xl': '1920px',
      },
    },
  },
  plugins: [],
};

export default config;

CSS変数との連携

// tailwind.config.ts
export default {
  theme: {
    extend: {
      colors: {
        background: 'hsl(var(--background))',
        foreground: 'hsl(var(--foreground))',
        primary: 'hsl(var(--primary))',
      },
    },
  },
};
/* globals.css */
:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --primary: 221.2 83.2% 53.3%;
}

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  --primary: 217.2 91.2% 59.8%;
}

2. コンポーネントの抽出とデザイントークン

繰り返されるスタイルパターンは、Reactコンポーネントとして抽出します。

❌ 悪い例:同じクラスを繰り返す

// コピペで同じクラスを何度も書いている
<button className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200">
  保存
</button>

<button className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200">
  送信
</button>

✅ 良い例:コンポーネント化

// components/ui/Button.tsx
import { cn } from '@/lib/utils';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
}

const buttonVariants = {
  primary: 'bg-blue-500 text-white hover:bg-blue-600',
  secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
  outline: 'border-2 border-blue-500 text-blue-500 hover:bg-blue-50',
  ghost: 'text-blue-500 hover:bg-blue-50',
};

const buttonSizes = {
  sm: 'px-3 py-1.5 text-sm',
  md: 'px-4 py-2',
  lg: 'px-6 py-3 text-lg',
};

export default function Button({
  variant = 'primary',
  size = 'md',
  className,
  children,
  ...props
}: ButtonProps) {
  return (
    <button
      className={cn(
        'rounded-lg font-medium transition-colors duration-200',
        'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2',
        'disabled:opacity-50 disabled:cursor-not-allowed',
        buttonVariants[variant],
        buttonSizes[size],
        className
      )}
      {...props}
    >
      {children}
    </button>
  );
}
// 使用例
<Button variant="primary" size="md">保存</Button>
<Button variant="secondary">キャンセル</Button>
<Button variant="outline" size="lg">詳細を見る</Button>

cn()ヘルパー関数

// lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

3. レスポンシブデザインの実装

Tailwindのモバイルファーストアプローチを活用します。

基本的なレスポンシブデザイン

<div className="
  grid
  grid-cols-1        {/* モバイル: 1列 */}
  sm:grid-cols-2     {/* 640px以上: 2列 */}
  md:grid-cols-3     {/* 768px以上: 3列 */}
  lg:grid-cols-4     {/* 1024px以上: 4列 */}
  gap-4
  sm:gap-6
  lg:gap-8
">
  {items.map(item => (
    <Card key={item.id} {...item} />
  ))}
</div>

テキストサイズのレスポンシブ対応

<h1 className="
  text-3xl          {/* モバイル */}
  sm:text-4xl       {/* タブレット */}
  lg:text-5xl       {/* デスクトップ */}
  xl:text-6xl       {/* 大画面 */}
  font-bold
  leading-tight
">
  レスポンシブな見出し
</h1>

コンテナクエリの活用

<div className="@container">
  <div className="
    grid
    grid-cols-1
    @md:grid-cols-2    {/* コンテナが768px以上 */}
    @lg:grid-cols-3    {/* コンテナが1024px以上 */}
    gap-4
  ">
    {/* コンテンツ */}
  </div>
</div>

4. よくある間違いと解決策

❌ 間違い1: インラインスタイルの多用

// 悪い例
<div style={{
  padding: '16px',
  backgroundColor: '#3b82f6',
  borderRadius: '8px'
}}>
  コンテンツ
</div>
// 良い例
<div className="p-4 bg-blue-500 rounded-lg">
  コンテンツ
</div>

❌ 間違い2: 任意値の乱用

// 悪い例:デザイントークンを無視
<div className="w-[347px] h-[231px] mt-[13px]">
  コンテンツ
</div>
// 良い例:標準のスペーシングを使用
<div className="w-80 h-56 mt-3">
  コンテンツ
</div>

❌ 間違い3: !importantの多用

// 悪い例
<div className="!text-red-500 !p-4">
  コンテンツ
</div>
// 良い例:詳細度を正しく管理
<div className="text-red-500 p-4">
  コンテンツ
</div>

❌ 間違い4: 長すぎるクラス名

// 悪い例:可読性が低い
<button className="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background bg-primary text-primary-foreground hover:bg-primary/90 h-10 py-2 px-4">
  ボタン
</button>
// 良い例:コンポーネント化
<Button>ボタン</Button>

5. プラグインの活用

よく使うプラグイン

// tailwind.config.ts
export default {
  plugins: [
    require('@tailwindcss/typography'),      // proseクラス
    require('@tailwindcss/forms'),           // フォームスタイル
    require('@tailwindcss/aspect-ratio'),    // アスペクト比
    require('@tailwindcss/container-queries'), // コンテナクエリ
  ],
};

@tailwindcss/typography の使用

<article className="
  prose
  prose-lg
  prose-headings:font-bold
  prose-a:text-blue-600
  prose-code:text-pink-600
  dark:prose-invert
  max-w-none
">
  <ReactMarkdown>{content}</ReactMarkdown>
</article>

@tailwindcss/forms の使用

<input
  type="email"
  className="
    form-input              {/* プラグインのスタイル */}
    rounded-lg
    border-gray-300
    focus:border-blue-500
    focus:ring-blue-500
  "
  placeholder="メールアドレス"
/>

6. パフォーマンスの最適化

PurgeCSS(自動)の設定

// tailwind.config.ts
export default {
  content: [
    './src/**/*.{js,ts,jsx,tsx,mdx}',
    // 動的クラス名を使用する場合は明示的に指定
    './safelist.txt',
  ],
  safelist: [
    // 常に含めるクラス
    'bg-red-500',
    'bg-green-500',
    {
      pattern: /bg-(red|green|blue)-(100|200|300)/,
    },
  ],
};

JIT(Just-In-Time)モードの活用

// 任意の値を使用可能(本番ビルドでも含まれる)
<div className="top-[117px] w-[347px] bg-[#1da1f2]">
  任意の値
</div>

本番ビルドサイズの確認

# ビルドサイズを確認
npm run build

# gzip圧縮後のサイズを確認
gzip -9 < .next/static/css/*.css | wc -c

7. ダークモードの実装

class戦略(推奨)

// tailwind.config.ts
export default {
  darkMode: 'class', // .darkクラスでトグル
};
// components/ThemeToggle.tsx
'use client';

import { useEffect, useState } from 'react';

export default function ThemeToggle() {
  const [theme, setTheme] = useState<'light' | 'dark'>('light');

  useEffect(() => {
    const savedTheme = localStorage.getItem('theme') as 'light' | 'dark' || 'light';
    setTheme(savedTheme);
    document.documentElement.classList.toggle('dark', savedTheme === 'dark');
  }, []);

  const toggleTheme = () => {
    const newTheme = theme === 'light' ? 'dark' : 'light';
    setTheme(newTheme);
    localStorage.setItem('theme', newTheme);
    document.documentElement.classList.toggle('dark', newTheme === 'dark');
  };

  return (
    <button
      onClick={toggleTheme}
      className="
        p-2 rounded-lg
        bg-gray-200 dark:bg-gray-800
        text-gray-900 dark:text-gray-100
        hover:bg-gray-300 dark:hover:bg-gray-700
      "
    >
      {theme === 'light' ? '🌙' : '☀️'}
    </button>
  );
}

ダークモード対応のコンポーネント

<div className="
  bg-white dark:bg-gray-900
  text-gray-900 dark:text-gray-100
  border border-gray-200 dark:border-gray-700
  shadow-sm dark:shadow-lg
">
  <h2 className="text-2xl font-bold text-gray-900 dark:text-white">
    タイトル
  </h2>
  <p className="text-gray-600 dark:text-gray-400">
    説明文
  </p>
</div>

8. カスタムユーティリティクラスの作成

@layerディレクティブの使用

/* globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .btn-primary {
    @apply px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600;
    @apply focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2;
  }

  .card {
    @apply bg-white dark:bg-gray-800 rounded-lg shadow-md p-6;
    @apply border border-gray-200 dark:border-gray-700;
  }
}

@layer utilities {
  .text-gradient {
    @apply bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-purple-600;
  }

  .scrollbar-hide {
    -ms-overflow-style: none;
    scrollbar-width: none;
  }

  .scrollbar-hide::-webkit-scrollbar {
    display: none;
  }
}

プラグインでの拡張

// tailwind.config.ts
import plugin from 'tailwindcss/plugin';

export default {
  plugins: [
    plugin(function({ addUtilities }) {
      addUtilities({
        '.glass': {
          'background': 'rgba(255, 255, 255, 0.7)',
          'backdrop-filter': 'blur(10px)',
          '-webkit-backdrop-filter': 'blur(10px)',
          'border': '1px solid rgba(255, 255, 255, 0.2)',
        },
      });
    }),
  ],
};

9. チーム開発での一貫性

Prettierとの統合

// .prettierrc
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindConfig": "./tailwind.config.ts"
}

自動的にクラスを並び替え:

// Before
<div className="text-center mb-4 p-2 bg-blue-500">

// After(自動整形)
<div className="mb-4 bg-blue-500 p-2 text-center">

ESLintルールの設定

// .eslintrc.json
{
  "extends": [
    "next/core-web-vitals",
    "plugin:tailwindcss/recommended"
  ],
  "rules": {
    "tailwindcss/classnames-order": "warn",
    "tailwindcss/no-custom-classname": "warn",
    "tailwindcss/no-contradicting-classname": "error"
  }
}

スタイルガイドの作成

// constants/design-tokens.ts
export const COLORS = {
  primary: 'bg-blue-500',
  secondary: 'bg-gray-600',
  success: 'bg-green-500',
  error: 'bg-red-500',
} as const;

export const SPACING = {
  section: 'py-16 md:py-24',
  container: 'px-4 sm:px-6 lg:px-8',
} as const;

export const TYPOGRAPHY = {
  h1: 'text-4xl md:text-5xl lg:text-6xl font-bold',
  h2: 'text-3xl md:text-4xl font-bold',
  body: 'text-base leading-relaxed',
} as const;

📝 まとめ

Tailwind CSSを効果的に使用するためのポイント:

  • カスタムテーマでデザインシステムを構築
  • コンポーネント化で再利用性を向上
  • レスポンシブ対応でモバイルファーストに
  • よくある間違いを避けて保守性を確保
  • プラグイン活用で機能を拡張
  • パフォーマンス最適化で高速化
  • ダークモードでUXを向上
  • カスタムユーティリティで独自スタイルを追加
  • チーム開発で一貫性を保持

これらのベストプラクティスを活用して、保守性が高く、高速で、拡張性のあるUIを構築しましょう!

🔗 参考リンク

#Tailwind CSS#CSS#Web Design#Frontend

著者について

kitahara-devによって執筆されました。