📚
「個人開発×Claude Code」 ナポレオン開発日記 #8 レスポンシブデザイン
ナポレオンゲームのレスポンシブUI実装
PC/スマホでデザインを切り替える方法
本記事では、Tailwind CSS のレスポンシブクラスを活用して、
PC / スマホで UI を切り替える設計方法を解説します。
というのも友人にゲームで遊んでもらったところスマホ版が見にくいという意見をいただきまして。。
開発自体もPCで挙動確認していてあんまりスマホ版を気にしたことがなかったのです。。
そもそもみんなノートPCを持っているわけでもないのでデザインを修正しようと思いました。
📱 概要
このプロジェクトでは、Tailwind CSS のブレークポイントを活用してデバイスごとに UI を最適化しています。
主な制御方法は以下の 3 つです:
- Tailwind のレスポンシブクラス — サイズ・余白の調整
-
表示/非表示の切り替え —
hidden×lg:block - コンポーネント分離 — モバイル専用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設定も簡潔に記述可能
引き続きより良いアプリにするために開発していきます。
📚 参考リンク
Discussion