📚

「個人開発×Claude Code」 ナポレオン開発日記 #8 レスポンシブデザイン

に公開

ナポレオンゲームのレスポンシブUI実装

PC/スマホでデザインを切り替える方法

本記事では、Tailwind CSS のレスポンシブクラスを活用して、
PC / スマホで UI を切り替える設計方法を解説します。

というのも友人にゲームで遊んでもらったところスマホ版が見にくいという意見をいただきまして。。
開発自体もPCで挙動確認していてあんまりスマホ版を気にしたことがなかったのです。。
そもそもみんなノートPCを持っているわけでもないのでデザインを修正しようと思いました。


📱 概要

このプロジェクトでは、Tailwind CSS のブレークポイントを活用してデバイスごとに UI を最適化しています。

主な制御方法は以下の 3 つです:

  1. Tailwind のレスポンシブクラス — サイズ・余白の調整
  2. 表示/非表示の切り替えhidden × lg:block
  3. コンポーネント分離 — モバイル専用UIの作成

🎯 Tailwind のブレークポイント

Tailwind デフォルトのブレークポイントを使用します。

Prefix px 用途
sm: 640px モバイル横向き・小タブレット
md: 768px タブレット
lg: 1024px ノートPC・デスクトップ
xl: 1280px 大型デスクトップ

本プロジェクトでは md:lg: の使い分けが中心です。


1️⃣ サイズ・余白の調整

■ 例1: ゲームボードの高さ

<div className="h-[350px] md:h-[600px]">
  {/* ゲームボード */}
</div>
  • モバイル: 350px
  • タブレット以上: 600px

■ 例2: テキストサイズ調整

<div className="text-[0.6rem] md:text-xs">tricks</div>
  • モバイル: 0.6rem(約 9.6px)
  • タブレット以上: 0.75rem(12px)

■ 例3: パディングと余白

<div className="p-2 md:p-4 space-y-2 md:space-y-4">

2️⃣ 表示/非表示の切り替え

■ デスクトップのみ表示

<div className="hidden lg:block lg:col-span-1">
  <GameStatus
    gameState={gameState}
    currentPlayerId={currentPlayerId}
  />
</div>
  • hidden: モバイル & タブレットでは非表示
  • lg:block: 1024px 以上で表示

■ モバイルのみ表示

<div className="lg:hidden">
  <CompactGameProgress gameState={gameState} />
</div>

3️⃣ コンポーネント分離戦略

■ モバイル用:CompactGameProgress

export function CompactGameProgress({ gameState }: { gameState: GameState }) {
  const progress = getGameProgress(gameState)

  if (gameState.phase !== GAME_PHASES.PLAYING) {
    return null
  }

  return (
    <div className="bg-white rounded-lg shadow-md p-2 text-xs">
      <div className="flex items-center justify-between gap-2">
        {/* Tricks */}
        <div className="flex flex-col items-center">
          <span className="text-gray-600">Tricks</span>
          <span className="font-bold text-sm">{progress.tricksPlayed}/12</span>
        </div>

        {/* Napoleon Team */}
        <div className="flex flex-col items-center">
          <span className="text-gray-600">Napoleon</span>
          <span className="font-bold text-yellow-600 text-sm">
            {progress.napoleonTeamFaceCards}
          </span>
        </div>

        {/* Alliance Team */}
        <div className="flex flex-col items-center">
          <span className="text-gray-600">Alliance</span>
          <span className="font-bold text-blue-600 text-sm">
            {progress.citizenTeamFaceCards}
          </span>
        </div>
      </div>
    </div>
  )
}

特徴

  • 横並びレイアウト
  • 最小限の情報
  • フォントは text-xs / text-sm でコンパクト

■ デスクトップ用:GameStatus

export function GameStatus({ gameState, currentPlayerId }: GameStatusProps) {
  return (
    <div className="bg-white rounded-lg shadow-md p-2 md:p-4 space-y-2 md:space-y-4">
      {/* 詳細情報いろいろ */}
    </div>
  )
}

特徴

  • 縦並びレイアウト
  • 詳細情報をフル表示
  • フォントは text-base 〜 text-lg

4️⃣ グリッドレイアウトの切り替え

<div className="grid grid-cols-1 lg:grid-cols-4 gap-4 md:gap-6">
  <div className="lg:col-span-3">
    {/* メインコンテンツ */}
  </div>

  <div className="hidden lg:block lg:col-span-1">
    <GameStatus />
  </div>
</div>

レイアウトの変化

  • モバイル:1列
  • デスクトップ:4列(3列メイン + 1列サイドバー)

5️⃣ ボタン・インタラクション要素

<button className="px-4 py-2 md:px-6 md:py-3 text-sm md:text-base">
  Play Selected Card
</button>
  • モバイル:コンパクト
  • タブレット以上:押しやすいサイズに

6️⃣ カード表示のサイズ切替

<Card card={card} size="tiny" />   // モバイル
<Card card={card} size="small" />  // タブレット
<Card card={card} size="medium" /> // デスクトップ

📊 まとめ:実装パターン一覧表

要素 モバイル タブレット デスクトップ
Progress表示 CompactGameProgress 同左 GameStatus(詳細)
サイドバー 非表示 非表示 表示
ゲームボード 350px 600px 600px
テキスト 0.6rem〜xs xs〜sm sm〜base
パディング p-2 p-4 p-4
グリッド 1列 1列 4列(3+1)

✅ ベストプラクティス

1. モバイルファースト

// ❌ 非推奨
<div className="text-base md:text-sm">

// ✅ 推奨
<div className="text-sm md:text-base">

2. コンポーネント分離の基準

  • 微調整で済む → 同じコンポーネント
  • 情報量が大きく違う → 別コンポーネントに分離

3. 読みやすいクラス順

コードをコピーする
<div
  className="
    flex items-center gap-2
    px-4 py-2 md:px-6 md:py-3
    text-sm md:text-base
    bg-white rounded-lg shadow-md
  "
>

🎨 スマホ最適化ポイント

  • スクロールを極力削減
  • ボタンは最低 44x44px
  • フォントは最小 0.6rem
  • 余白を少なめに (p-2, gap-1)
  • 横並びレイアウトを活用

🔧 技術スタック

  • Next.js 15.4 (App Router)
  • Tailwind CSS
  • TypeScript

📝 学習したこと

  • tailwindはクラス指定でモバイルとPCデザインを自由にいじれる
  • prefixで固定で設定可能、いちいち値指定する必要はない
  • hidden設定も簡潔に記述可能

引き続きより良いアプリにするために開発していきます。

📚 参考リンク
https://tailwindcss.com/docs/responsive-design

https://github.com/ksleep98/napoleon-game-4players

Discussion