tailwindcss-mobile-first
Tailwind CSS v4 を使ったモバイルファーストのレスポンシブデザインパターンを提供するスキルです。ブレークポイント(`sm:` / `md:` / `lg:` 等)の正しい適用順序、レスポンシブなグリッド・タイポグラフィ・表示切替、コンテナクエリ(`@container`)によるコンポーネント単位のレスポンシブ対応、セーフエリアのインセット処理、タッチ/ホバーの使い分けなど、実務で必要なパターンを網羅しています。モバイルファーストの設計方針でUIを構築・調整する際に自動的に活性化されます。
description の原文を見る
Mobile-first responsive design patterns with Tailwind CSS v4 (2025-2026). PROACTIVELY activate for: (1) mobile-first design with Tailwind breakpoints (sm:, md:, lg:, xl:, 2xl:), (2) responsive utility ordering (default = mobile, then breakpoints), (3) responsive typography (text-base sm:text-lg lg:text-xl), (4) responsive grids and flexbox, (5) hide/show across breakpoints (hidden md:block), (6) max-* breakpoints for desktop-down overrides, (7) container queries (@container) for component-level responsiveness, (8) safe-area insets and notch handling, (9) landscape vs portrait orientation, (10) touch vs hover (hover: with @media). Provides: breakpoint reference, mobile-first patterns, container-query examples, safe-area recipes, and touch/hover handling.
SKILL.md 本文
モバイルファーストレスポンシブデザイン (2025/2026)
コアフィロソフィ
モバイルファーストデザインは 2025/2026 の業界標準 です。モバイルトラフィックが世界中のウェブトラフィックの 60% を常に超え、Google のモバイルファーストインデックス付けにより、モバイルから始めることは最適なユーザー体験と SEO パフォーマンスを確保します。
モバイルファーストの心構え
<!-- 正しい: モバイルファースト (プログレッシブエンハンスメント) -->
<div class="text-sm md:text-base lg:text-lg">
小さく始めて、上へ向かって拡張
</div>
<!-- 誤り: デスクトップファースト (グレースフルデグラデーション) -->
<div class="lg:text-lg md:text-base text-sm">
大きく始めて、下へ縮小 (より多くのコード、より多くのバグ)
</div>
重要原則: プレフィックスなしのユーティリティはすべての画面サイズに適用されます。ブレークポイントプレフィックスはそのサイズ以上に適用されます。
2025/2026 ブレークポイント戦略
Tailwind のデフォルトブレークポイント
| プレフィックス | 最小幅 | 対象デバイス |
|---|---|---|
| (なし) | 0px | すべてのモバイル電話 (ベース) |
sm: | 640px (40rem) | 大型電話、小型タブレット |
md: | 768px (48rem) | タブレット (ポートレイト) |
lg: | 1024px (64rem) | タブレット (ランドスケープ)、ノートパソコン |
xl: | 1280px (80rem) | デスクトップ |
2xl: | 1536px (96rem) | 大型デスクトップ |
コンテンツドリブンのブレークポイント
ベストプラクティス 2025/2026: デバイスの寸法ではなく、コンテンツがブレークポイントを決定します。
@theme {
/* コンテンツのニーズに基づいてデフォルトをオーバーライド */
--breakpoint-sm: 36rem; /* 576px - コンテンツがより多くのスペースを必要とする場合 */
--breakpoint-md: 48rem; /* 768px */
--breakpoint-lg: 62rem; /* 992px - 一般的なコンテンツ幅 */
--breakpoint-xl: 75rem; /* 1200px */
--breakpoint-2xl: 90rem; /* 1440px */
/* 特定のコンテンツニーズ用のカスタムブレークポイントを追加 */
--breakpoint-xs: 20rem; /* 320px - 非常に小さいデバイス */
--breakpoint-3xl: 120rem; /* 1920px - 超ワイド */
}
スクリーンカバレッジ戦略
<!-- 最も一般的なデバイス範囲をカバー (2025/2026 データ) -->
<!-- 375px-430px: モバイルデバイスの約 50% (iPhone、最新 Android) -->
<div class="px-4">モバイルベース</div>
<!-- 768px+: タブレットと小型ノートパソコン -->
<div class="px-4 md:px-6">タブレット拡張</div>
<!-- 1024px+: デスクトップ体験 -->
<div class="px-4 md:px-6 lg:px-8">デスクトップ拡張</div>
<!-- 1440px+: ワイドデスクトップ体験 -->
<div class="px-4 md:px-6 lg:px-8 xl:px-12">ワイドデスクトップ</div>
流動的タイポグラフィシステム
CSS Clamp による滑らかなスケーリング
流動的タイポグラフィはブレークポイント間のサイズジャンプの不安定さを排除します:
@theme {
/* 流動的タイポグラフィスケール */
--text-fluid-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-fluid-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--text-fluid-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-fluid-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);
--text-fluid-xl: clamp(1.25rem, 1rem + 1.25vw, 1.5rem);
--text-fluid-2xl: clamp(1.5rem, 1.1rem + 2vw, 2rem);
--text-fluid-3xl: clamp(1.875rem, 1.2rem + 3.375vw, 2.5rem);
--text-fluid-4xl: clamp(2.25rem, 1rem + 6.25vw, 3.5rem);
--text-fluid-5xl: clamp(3rem, 1rem + 10vw, 5rem);
}
アクセシビリティのための重要事項: vw と rem を組み合わせて、ユーザーのズーム設定を常に尊重します (WCAG コンプライアンス)。
流動的タイポグラフィの使用
<!-- スムーズにスケーリングする流動的見出し -->
<h1 class="text-fluid-4xl font-bold leading-tight">
レスポンシブ見出し
</h1>
<!-- 流動的本文テキスト -->
<p class="text-fluid-base leading-relaxed max-w-prose">
ビューポートに比例してスケーリングしながら、
ユーザーのフォントサイズ設定を尊重する本文テキスト。
</p>
<!-- 微調整のための流動的とブレークポイントオーバーライド -->
<h2 class="text-fluid-2xl lg:text-fluid-3xl font-semibold">
セクションタイトル
</h2>
流動的スペーシングシステム
Clamp ベースのスペーシング
@theme {
/* 流動的スペーシングスケール */
--spacing-fluid-xs: clamp(0.25rem, 0.2rem + 0.25vw, 0.5rem);
--spacing-fluid-sm: clamp(0.5rem, 0.4rem + 0.5vw, 1rem);
--spacing-fluid-md: clamp(1rem, 0.75rem + 1.25vw, 2rem);
--spacing-fluid-lg: clamp(1.5rem, 1rem + 2.5vw, 3rem);
--spacing-fluid-xl: clamp(2rem, 1.25rem + 3.75vw, 4rem);
--spacing-fluid-2xl: clamp(3rem, 1.5rem + 7.5vw, 6rem);
--spacing-fluid-section: clamp(4rem, 2rem + 10vw, 8rem);
}
流動的スペーシングの使用
<!-- 流動的セクションパディング -->
<section class="py-fluid-section px-fluid-md">
<div class="max-w-7xl mx-auto">
<h2 class="mb-fluid-lg">セクションタイトル</h2>
<div class="grid gap-fluid-md grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
<!-- カード -->
</div>
</div>
</section>
<!-- 流動的スペーシングを備えたヒーローセクション -->
<header class="min-h-screen flex items-center py-fluid-2xl px-fluid-md">
<div class="max-w-4xl">
<h1 class="text-fluid-5xl mb-fluid-md">ヒロータイトル</h1>
<p class="text-fluid-lg mb-fluid-lg">ヒロー説明</p>
<button class="px-fluid-md py-fluid-sm">はじめる</button>
</div>
</header>
タッチフレンドリーなインタラクティブ要素
WCAG 2.2 タッチターゲット要件
最小サイズ (2025 標準):
- WCAG 2.2 レベル AA: 最小 24x24 CSS ピクセル
- 推奨: 44x44 CSS ピクセル (Apple、Google、Microsoft ガイドライン)
- 最適: 重要なアクションのために 48x48 CSS ピクセル
<!-- WCAG 2.2 準拠のタッチターゲット -->
<!-- 最小 AA 準拠 (24px) -->
<button class="min-h-6 min-w-6 p-1">
<svg class="h-4 w-4">...</svg>
</button>
<!-- 推奨サイズ (44px) -->
<button class="min-h-11 min-w-11 p-2.5">
<svg class="h-6 w-6">...</svg>
<span class="sr-only">アクション</span>
</button>
<!-- プライマリアクションの最適なサイズ (48px) -->
<button class="min-h-12 min-w-12 px-6 py-3 text-base">
プライマリアクション
</button>
拡張タッチターゲット
<!-- 表示要素を超えてタッチターゲットを拡張 -->
<a href="/link" class="relative inline-block text-sm">
小さな表示リンク
<!-- 見えない拡張タッチエリア -->
<span class="absolute -inset-3" aria-hidden="true"></span>
</a>
<!-- 拡張ターゲット付きのアイコンボタン -->
<button class="relative p-2 -m-2 rounded-lg hover:bg-gray-100">
<svg class="h-5 w-5" aria-hidden="true">...</svg>
<span class="sr-only">閉じる</span>
</button>
タッチターゲットスペーシング
<!-- タッチターゲット間の適切なスペーシング (最小 8px ギャップ) -->
<nav class="flex gap-3">
<a href="#" class="min-h-11 px-4 py-2.5">ホーム</a>
<a href="#" class="min-h-11 px-4 py-2.5">について</a>
<a href="#" class="min-h-11 px-4 py-2.5">お問い合わせ</a>
</nav>
<!-- 適切なスペーシング付きのスタックナビゲーション -->
<nav class="flex flex-col">
<a href="#" class="py-3 px-4 min-h-11 border-b border-gray-100">リンク 1</a>
<a href="#" class="py-3 px-4 min-h-11 border-b border-gray-100">リンク 2</a>
<a href="#" class="py-3 px-4 min-h-11">リンク 3</a>
</nav>
<!-- 安全なスペーシング付きボタングループ -->
<div class="flex flex-wrap gap-3">
<button class="min-h-11 px-4 py-2">キャンセル</button>
<button class="min-h-11 px-4 py-2 bg-blue-600 text-white">確認</button>
</div>
コンテナクエリ (2025 ゲームチェンジャー)
コンテナクエリは コンポーネントレベルのレスポンシブ性 を可能にし、ビューポートサイズとは独立しています。
セットアップ
@import "tailwindcss";
@plugin "@tailwindcss/container-queries";
コンテナクエリブレークポイント
| クラス | 最小幅 |
|---|---|
@xs | 20rem (320px) |
@sm | 24rem (384px) |
@md | 28rem (448px) |
@lg | 32rem (512px) |
@xl | 36rem (576px) |
@2xl | 42rem (672px) |
@3xl | 48rem (768px) |
@4xl | 56rem (896px) |
@5xl | 64rem (1024px) |
実用的なコンテナクエリパターン
<!-- ビューポートではなく、コンテナに応答するカード -->
<article class="@container">
<div class="
flex flex-col @sm:flex-row
gap-4 p-4
bg-white rounded-xl shadow-sm
">
<img
src="..."
class="
w-full @sm:w-32 @lg:w-48
aspect-video @sm:aspect-square
object-cover rounded-lg
"
/>
<div class="flex-1 min-w-0">
<h3 class="text-base @md:text-lg @lg:text-xl font-semibold truncate">
カードタイトル
</h3>
<p class="
text-sm @md:text-base
text-gray-600
line-clamp-2 @lg:line-clamp-3
mt-2
">
利用可能なスペースに適応する説明...
</p>
<div class="mt-4 flex flex-wrap gap-2 @md:gap-3">
<span class="text-xs @md:text-sm px-2 py-1 bg-gray-100 rounded">タグ</span>
</div>
</div>
</div>
</article>
名前付きコンテナ
<div class="@container/sidebar w-64">
<nav class="
flex flex-col @lg/sidebar:flex-row
@lg/sidebar:items-center
gap-2 @lg/sidebar:gap-4
">
<a href="#">リンク 1</a>
<a href="#">リンク 2</a>
</nav>
</div>
<main class="@container/main flex-1">
<div class="
grid grid-cols-1
@md/main:grid-cols-2
@xl/main:grid-cols-3
gap-6
">
<!-- グリッドアイテムはメインコンテナに応答 -->
</div>
</main>
コンテナクエリとビューポートクエリを使い分ける
| コンテナクエリを使用 | ビューポートクエリを使用 |
|---|---|
| 再利用可能なコンポーネント | ページレベルのレイアウト |
| サイドバーウィジェット | ナビゲーションバー |
| カードグリッド | ヒーローセクション |
| 埋め込みコンテンツ | フルスクリーンセクション |
| CMS/動的コンテンツ | 固定アプリシェル |
レスポンシブレイアウトパターン
モバイルファーストグリッドシステム
<!-- 最小カード幅を持つオートレスポンシブグリッド -->
<div class="
grid gap-6
grid-cols-1
sm:grid-cols-2
lg:grid-cols-3
xl:grid-cols-4
">
<!-- カードは自動的にフロー -->
</div>
<!-- CSS Grid auto-fit (ブレークポイント不要) -->
<div class="grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-6">
<!-- 最小 280px でカードは自動的にフィット -->
</div>
<!-- CSS Grid auto-fill (固定サイズアイテム用) -->
<div class="grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-4">
<!-- 固定最小サイズ、フィルするために成長 -->
</div>
レスポンシブフレックスボックスパターン
<!-- スタックから行へ -->
<div class="flex flex-col md:flex-row gap-4">
<div class="flex-1">コンテンツ 1</div>
<div class="flex-1">コンテンツ 2</div>
</div>
<!-- 中央揃いアイテムでラップ -->
<div class="flex flex-wrap justify-center gap-4">
<div class="w-full sm:w-auto">アイテム 1</div>
<div class="w-full sm:w-auto">アイテム 2</div>
<div class="w-full sm:w-auto">アイテム 3</div>
</div>
<!-- モバイルスタック、デスクトップインラインとプッシュ -->
<div class="flex flex-col sm:flex-row sm:items-center gap-4">
<div class="flex-1">
<h3>タイトル</h3>
<p class="text-sm text-gray-600">説明</p>
</div>
<button class="sm:ml-auto min-h-11 px-4 py-2">アクション</button>
</div>
レスポンシブサイドバーレイアウト
<!-- 折りたたみ式サイドバー -->
<div class="flex min-h-screen">
<!-- サイドバー: モバイルで非表示、デスクトップで表示 -->
<aside class="
hidden lg:flex lg:flex-col
w-64 border-r bg-gray-50
">
<nav class="flex-1 p-4">...</nav>
</aside>
<!-- メインコンテンツ -->
<main class="flex-1 p-4 lg:p-8">
コンテンツ
</main>
</div>
<!-- モバイルドロワー + デスクトップサイドバー -->
<div class="relative flex min-h-screen">
<!-- モバイルドロワーオーバーレイ -->
<div class="
fixed inset-0 z-40 lg:hidden
bg-black/50
data-[open=false]:hidden
" data-open="false">
<aside class="w-64 h-full bg-white">
モバイルナビゲーション
</aside>
</div>
<!-- デスクトップサイドバー -->
<aside class="hidden lg:block w-64 border-r">
デスクトップナビゲーション
</aside>
<main class="flex-1">コンテンツ</main>
</div>
ホーリーグレイルレイアウト (2025)
<div class="min-h-screen grid grid-rows-[auto_1fr_auto]">
<!-- ヘッダー -->
<header class="sticky top-0 z-50 h-16 bg-white border-b shadow-sm">
<nav class="h-full max-w-7xl mx-auto px-4 flex items-center justify-between">
<Logo />
<ul class="hidden md:flex gap-6">...</ul>
<button class="md:hidden min-h-11 min-w-11">メニュー</button>
</nav>
</header>
<!-- メインコンテンツエリア (オプションのサイドバー付き) -->
<div class="
grid
grid-cols-1
md:grid-cols-[240px_1fr]
lg:grid-cols-[240px_1fr_280px]
gap-0
">
<nav class="hidden md:block border-r p-4">左ナビ</nav>
<main class="p-4 md:p-6 lg:p-8">メインコンテンツ</main>
<aside class="hidden lg:block border-l p-4">右サイドバー</aside>
</div>
<!-- フッター -->
<footer class="bg-gray-900 text-white py-8 md:py-12">
フッターコンテンツ
</footer>
</div>
レスポンシブ画像
アスペクト比コンテナ
<!-- すべてのサイズ全体でアスペクト比を維持 -->
<div class="aspect-video overflow-hidden rounded-lg">
<img src="..." class="w-full h-full object-cover" loading="lazy" />
</div>
<!-- レスポンシブアスペクト比 -->
<div class="aspect-square sm:aspect-video lg:aspect-[4/3] overflow-hidden">
<img src="..." class="w-full h-full object-cover" />
</div>
レスポンシブ画像サイズ
<!-- picture 要素を使用したアート方向 -->
<picture>
<source media="(min-width: 1024px)" srcset="large.jpg" />
<source media="(min-width: 640px)" srcset="medium.jpg" />
<img
src="small.jpg"
alt="説明"
class="w-full h-auto rounded-lg"
loading="lazy"
/>
</picture>
<!-- レスポンシブ srcset -->
<img
src="image-800.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w,
image-1600.jpg 1600w
"
sizes="
(min-width: 1280px) 1200px,
(min-width: 768px) 80vw,
100vw
"
alt="レスポンシブ画像"
class="w-full h-auto"
loading="lazy"
/>
レスポンシブタイポグラフィパターン
見出しの階層
<!-- モバイルファーストの見出しスケール -->
<h1 class="
text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl
font-bold leading-tight tracking-tight
">
メイン見出し
</h1>
<h2 class="
text-xl sm:text-2xl md:text-3xl lg:text-4xl
font-semibold leading-snug
">
セクション見出し
</h2>
<h3 class="
text-lg sm:text-xl md:text-2xl
font-medium
">
サブセクション見出し
</h3>
読みやすい本文テキスト
<!-- 最適な行の長さと間隔 -->
<article class="max-w-prose mx-auto">
<p class="
text-base md:text-lg
leading-relaxed md:leading-loose
text-gray-700 dark:text-gray-300
">
1 行あたり 45 ~ 75 文字の読みやすさに最適化された本文テキスト。
</p>
</article>
<!-- 行全体でバランスするテキスト -->
<h2 class="text-balance text-2xl md:text-3xl font-bold max-w-2xl">
この見出しは孤立を避けるために行全体でテキストをバランスします
</h2>
モバイルナビゲーションパターン
ハンバーガーから完全なナビゲーション
<nav class="relative">
<!-- デスクトップナビゲーション -->
<ul class="hidden md:flex items-center gap-6">
<li><a href="#" class="py-2 hover:text-blue-600">ホーム</a></li>
<li><a href="#" class="py-2 hover:text-blue-600">製品</a></li>
<li><a href="#" class="py-2 hover:text-blue-600">について</a></li>
<li><a href="#" class="py-2 hover:text-blue-600">お問い合わせ</a></li>
</ul>
<!-- モバイルメニューボタン -->
<button
class="md:hidden min-h-11 min-w-11 p-2"
aria-expanded="false"
aria-controls="mobile-menu"
aria-label="ナビゲーションメニューを切り替え"
>
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
</svg>
</button>
<!-- モバイルメニュー (JS で制御) -->
<div
id="mobile-menu"
class="
md:hidden
absolute top-full left-0 right-0
bg-white shadow-lg border-t
hidden
"
>
<ul class="py-2">
<li><a href="#" class="block px-4 py-3 min-h-11 hover:bg-gray-50">ホーム</a></li>
<li><a href="#" class="block px-4 py-3 min-h-11 hover:bg-gray-50">製品</a></li>
<li><a href="#" class="block px-4 py-3 min-h-11 hover:bg-gray-50">について</a></li>
<li><a href="#" class="block px-4 py-3 min-h-11 hover:bg-gray-50">お問い合わせ</a></li>
</ul>
</div>
</nav>
ボトムナビゲーション (モバイルアプリスタイル)
<!-- モバイル固定下部ナビゲーション -->
<nav class="
fixed bottom-0 inset-x-0 z-50
md:hidden
bg-white border-t shadow-lg
safe-area-pb
">
<ul class="flex justify-around">
<li>
<a href="#" class="
flex flex-col items-center
min-h-14 min-w-14 px-3 py-2
text-xs
text-gray-600 hover:text-blue-600
aria-current:text-blue-600
">
<svg class="h-6 w-6 mb-1">...</svg>
ホーム
</a>
</li>
<li>
<a href="#" class="flex flex-col items-center min-h-14 min-w-14 px-3 py-2 text-xs">
<svg class="h-6 w-6 mb-1">...</svg>
検索
</a>
</li>
<li>
<a href="#" class="flex flex-col items-center min-h-14 min-w-14 px-3 py-2 text-xs">
<svg class="h-6 w-6 mb-1">...</svg>
プロフィール
</a>
</li>
</ul>
</nav>
<!-- メインコンテンツへの重複防止用パディングを追加 -->
<main class="pb-20 md:pb-0">
コンテンツ
</main>
セーフエリア処理 (ノッチ付きデバイス)
@utility safe-area-pt {
padding-top: env(safe-area-inset-top);
}
@utility safe-area-pb {
padding-bottom: env(safe-area-inset-bottom);
}
@utility safe-area-pl {
padding-left: env(safe-area-inset-left);
}
@utility safe-area-pr {
padding-right: env(safe-area-inset-right);
}
@utility safe-area-p {
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}
<!-- ノッチを尊重するヘッダー -->
<header class="sticky top-0 safe-area-pt bg-white">
<div class="h-16 flex items-center px-4">
ナビゲーション
</div>
</header>
<!-- セーフエリア付きボトムナビゲーション -->
<nav class="fixed bottom-0 inset-x-0 safe-area-pb bg-white border-t">
ボトムナビゲーション
</nav>
モバイルのパフォーマンス最適化
遅延読み込み
<!-- 画像のネイティブ遅延読み込み -->
<img src="image.jpg" alt="..." loading="lazy" class="w-full h-auto" />
<!-- オンデマンドで読み込まれたビロー・フォールドコンテンツ -->
<div class="contents" data-lazy-load>
オンデマンドで読み込まれる重いコンポーネント
</div>
コンテンツの可視性
@utility content-auto {
content-visibility: auto;
contain-intrinsic-size: auto 500px;
}
<!-- オフスクリーンコンテンツのレンダリングをスキップ -->
<section class="content-auto">
画面外にある可能性がある大きなセクション
</section>
データ使用量削減
<!-- 低速接続時にシンプルなバージョンを表示 -->
<picture>
<source
srcset="video-poster.jpg"
media="(prefers-reduced-data: reduce)"
/>
<img src="animated.gif" alt="..." />
</picture>
レスポンシブテストチェックリスト
必須テスト
- 320px - サポートされている最小の幅 (古い iPhone)
- 375px - 最新 iPhone ベース
- 414px - 大型電話 (iPhone Plus/Max)
- 768px - iPad ポートレイト
- 1024px - iPad ランドスケープ / 小型ノートパソコン
- 1280px - 標準ノートパソコン
- 1440px - 大型デスクトップ
- 1920px - フル HD デスクトップ
品質チェック
- テキストはすべてのサイズで読みやすい
- タッチターゲットはモバイルで最小 44px
- ビューポートで水平スクロールなし
- 画像がコンテナをオーバーフローしない
- ナビゲーションはすべてのサイズでアクセス可能
- フォームはモバイルで使用可能
- モーダルはモバイル画面に適合
- テーブルにはモバイル代替がある
- パフォーマンスは 3G で 3 秒以下の LCP
レスポンシブビデオコンテナ
ビデオ用アスペクト比ユーティリティ
Tailwind のアスペクト比ユーティリティを使用して、すべての画面サイズでビデオの正しい比率を保ち、累積レイアウトシフト (CLS) を防ぎます:
<!-- 標準 16:9 ビデオコンテナ -->
<div class="aspect-video overflow-hidden rounded-lg bg-black">
<video class="w-full h-full object-cover" playsinline preload="metadata">
<source src="video.mp4" type="video/mp4" />
</video>
</div>
<!-- 縦型ビデオ (9:16) モバイルファーストのソーシャルコンテンツ用 -->
<div class="aspect-[9/16] overflow-hidden rounded-lg bg-black max-w-sm mx-auto">
<video class="w-full h-full object-cover" playsinline muted loop>
<source src="reel.mp4" type="video/mp4" />
</video>
</div>
<!-- 正方形ビデオ (1:1) ソーシャルフィードで一般的 -->
<div class="aspect-square overflow-hidden rounded-lg bg-black">
<video class="w-full h-full object-cover" playsinline preload="metadata">
<source src="square.mp4" type="video/mp4" />
</video>
</div>
<!-- レスポンシブアスペクト比 - モバイルで縦型、デスクトップでワイドスクリーン -->
<div class="aspect-[9/16] sm:aspect-video overflow-hidden rounded-lg bg-black">
<video class="w-full h-full object-contain" playsinline preload="metadata">
<source src="video.mp4" type="video/mp4" />
</video>
</div>
CLS を防ぐビデオプレースホルダ
定義された寸法なしのビデオはロード時にレイアウトシフトを引き起こします。アスペクト比コンテナを使用してスペースを予約します:
<!-- CLS セーフなビデオ (ポスターとスケルトンローダー付き) -->
<div class="relative aspect-video overflow-hidden rounded-lg bg-gray-900">
<!-- ビデオ読み込み中のスケルトンプレースホルダ -->
<div class="absolute inset-0 animate-pulse bg-gray-800" aria-hidden="true"></div>
<video
class="absolute inset-0 w-full h-full object-cover"
poster="/thumbnails/video-poster.jpg"
playsinline
preload="metadata"
>
<source src="video.mp4" type="video/mp4" />
</video>
</div>
<!-- ビデオサムネイルのレスポンシブグリッド (CLS ゼロ) -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="aspect-video overflow-hidden rounded-lg bg-gray-900">
<video class="w-full h-full object-cover" poster="/thumb1.jpg" preload="none" playsinline></video>
</div>
<div class="aspect-video overflow-hidden rounded-lg bg-gray-900">
<video class="w-full h-full object-cover" poster="/thumb2.jpg" preload="none" playsinline></video>
</div>
<div class="aspect-video overflow-hidden rounded-lg bg-gray-900">
<video class="w-full h-full object-cover" poster="/thumb3.jpg" preload="none" playsinline></video>
</div>
</div>
モバイルで全幅、デスクトップで制約付き
<!-- モバイルで全幅、デスクトップで最大幅の中央配置 -->
<div class="w-full lg:max-w-4xl lg:mx-auto">
<div class="aspect-video overflow-hidden lg:rounded-xl bg-black">
<video class="w-full h-full object-cover" playsinline preload="metadata">
<source src="hero.mp4" type="video/mp4" />
</video>
</div>
</div>
<!-- 全幅ヒーロービデオ背景 -->
<section class="relative w-full h-screen overflow-hidden">
<video
class="absolute inset-0 w-full h-full object-cover"
autoplay muted loop playsinline
preload="auto"
>
<source src="hero-bg.mp4" type="video/mp4" />
</video>
<!-- セーフパディング付きコンテンツオーバーレイ -->
<div class="relative z-10 flex items-center justify-center h-full px-4 sm:px-8">
<div class="text-center text-white max-w-2xl">
<h1 class="text-3xl sm:text-4xl lg:text-6xl font-bold">ヒロータイトル</h1>
<p class="mt-4 text-lg sm:text-xl">サブタイトルテキスト</p>
</div>
</div>
<!-- テキスト読みやすさのためのダークオーバーレイ -->
<div class="absolute inset-0 bg-black/40" aria-hidden="true"></div>
</section>
ビデオ UI のセーフゾーンオーバーレイ
ビデオプレーヤーコントロールと UI 要素は、タッチフレンドリーなサイズと適切な配置が必要です:
<!-- タッチセーフコントロール付きカスタムビデオプレーヤー -->
<div class="@container relative aspect-video overflow-hidden rounded-lg bg-black group">
<video class="w-full h-full object-cover" playsinline preload="metadata">
<source src="video.mp4" type="video/mp4" />
</video>
<!-- 再生/一時停止オーバーレイ - 中央、タッチフレンドリー -->
<button class="
absolute inset-0 flex items-center justify-center
bg-black/0 group-hover:bg-black/20 transition-colors
">
<span class="
w-16 h-16 sm:w-20 sm:h-20
flex items-center justify-center
rounded-full bg-white/90
shadow-lg
">
<svg class="w-8 h-8 sm:w-10 sm:h-10 text-gray-900 ml-1" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
</span>
</button>
<!-- ボトムコントロールバー - タッチターゲットを尊重 -->
<div class="
absolute bottom-0 inset-x-0
bg-gradient-to-t from-black/80 to-transparent
p-3 sm:p-4
flex items-center gap-3
opacity-0 group-hover:opacity-100 transition-opacity
">
<!-- プログレスバー - タッチするのに十分な高さ -->
<div class="flex-1 h-1 bg-white/30 rounded-full cursor-pointer">
<div class="h-full w-1/3 bg-white rounded-full relative">
<span class="absolute right-0 top-1/2 -translate-y-1/2 w-4 h-4 bg-white rounded-full -mr-2"></span>
</div>
</div>
<!-- 時間表示 -->
<span class="text-white text-xs sm:text-sm tabular-nums shrink-0">1:23 / 4:56</span>
<!-- 全画面ボタン - タッチフレンドリー最小サイズ -->
<button class="min-h-11 min-w-11 flex items-center justify-center text-white">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/>
</svg>
</button>
</div>
</div>
コンテナクエリのアダプティブビデオプレーヤー
ビデオプレーヤーコンポーネントがコンテナサイズに基づいてレイアウトを調整します --- サイドバー、メインコンテンツエリア、またはモーダルに同じプレーヤーが表示される場合に便利です:
<!-- コンテナに応答するビデオプレーヤー -->
<div class="@container">
<div class="
flex flex-col @lg:flex-row
gap-4 @lg:gap-6
bg-gray-950 rounded-xl overflow-hidden
">
<!-- ビデオエリア -->
<div class="
w-full @lg:flex-1
aspect-video
overflow-hidden
">
<video class="w-full h-full object-cover" playsinline preload="metadata">
<source src="video.mp4" type="video/mp4" />
</video>
</div>
<!-- 情報パネル - 狭い場合はビデオ下、広い場合は隣 -->
<div class="
p-4 @lg:p-6
@lg:w-80 @lg:overflow-y-auto
text-white
">
<h3 class="text-base @lg:text-lg font-semibold">ビデオタイトル</h3>
<p class="text-sm text-gray-400 mt-2 line-clamp-2 @lg:line-clamp-none">
コンテナがより広い場合により多くのテキストを表示するビデオ説明...
</p>
<!-- 関連ビデオ - 狭いコンテナで非表示 -->
<div class="hidden @xl:block mt-6 space-y-3">
<h4 class="text-sm font-medium text-gray-300">関連</h4>
<div class="space-y-2">
<div class="flex gap-3">
<div class="w-28 aspect-video bg-gray-800 rounded shrink-0"></div>
<div class="text-xs text-gray-400">関連ビデオ 1</div>
</div>
</div>
</div>
</div>
</div>
</div>
ベストプラクティスの概要
| プラクティス | 実装 |
|---|---|
| モバイルファーストユーティリティ | プレフィックスなし最初、その後 sm:、md:、lg: |
| タッチターゲット | min-h-11 min-w-11 (44px 最小) |
| 流動的タイポグラフィ | clamp(min, preferred, max) (rem + vw 付き) |
| 流動的スペーシング | パディングとマージンの clamp() |
| コンテナクエリ | コンポーネントレスポンシブ性用の @container |
| セーフエリア | ノッチ付きデバイス用の env(safe-area-inset-*) |
| 読みやすいテキスト | max-w-prose (65ch) と leading-relaxed |
| 遅延読み込み | ビロー・フォールド画像で loading="lazy" |
| タッチスペーシング | ターゲット間に gap-3 (12px) 最小 |
| ビューポートメタ | width=device-width, initial-scale=1 |
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- josiahsiegel
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/josiahsiegel/claude-plugin-marketplace / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。