responsive-design
コンテナクエリ、流体タイポグラフィ、CSS Grid、モバイルファーストのブレークポイント戦略を用いて、モダンなレスポンシブレイアウトを実装します。アダプティブなインターフェースの構築、流動的なレイアウトの実装、またはコンポーネントレベルのレスポンシブ対応が必要な際に使用してください。
description の原文を見る
Implement modern responsive layouts using container queries, fluid typography, CSS Grid, and mobile-first breakpoint strategies. Use when building adaptive interfaces, implementing fluid layouts, or creating component-level responsive behavior.
SKILL.md 本文
レスポンシブデザイン
すべてのスクリーンサイズとデバイスコンテキストにシームレスに対応するインターフェースを作成するために、最新のレスポンシブデザイン技術をマスターします。
このスキルを使う場面
- モバイルファーストのレスポンシブレイアウト実装
- コンポーネントベースのレスポンシブ性のためのコンテナクエリ使用
- 流動的なタイポグラフィとスペーシングスケール作成
- CSS GridとFlexboxを使用した複雑なレイアウト構築
- デザインシステムのブレークポイント戦略設計
- レスポンシブ画像とメディア実装
- 適応的なナビゲーションパターン作成
- レスポンシブテーブルとデータ表示構築
コア機能
1. コンテナクエリ
- ビューポートに依存しないコンポーネントレベルのレスポンシブ性
- コンテナクエリユニット (cqi, cqw, cqh)
- 条件付きスタイリング用のスタイルクエリ
- ブラウザサポート用のフォールバック
2. 流動的なタイポグラフィ & スペーシング
- 流動的スケーリング用のCSS clamp()
- ビューポート相対単位 (vw, vh, dvh)
- min/maxで制限された流動的なタイプスケール
- レスポンシブスペーシングシステム
3. レイアウトパターン
- 2次元レイアウト用のCSS Grid
- 1次元配分用のFlexbox
- 本質的なレイアウト (コンテンツベースのサイジング)
- ネストされたグリッド配置用のSubgrid
4. ブレークポイント戦略
- モバイルファーストメディアクエリ
- コンテンツベースのブレークポイント
- デザイントークン統合
- フィーチャークエリ (@supports)
クイックリファレンス
モダンブレークポイントスケール
/* モバイルファースト ブレークポイント */
/* ベース: モバイル (< 640px) */
@media (min-width: 640px) {
/* sm: 横向きスマートフォン、小型タブレット */
}
@media (min-width: 768px) {
/* md: タブレット */
}
@media (min-width: 1024px) {
/* lg: ノートパソコン、小型デスクトップ */
}
@media (min-width: 1280px) {
/* xl: デスクトップ */
}
@media (min-width: 1536px) {
/* 2xl: 大型デスクトップ */
}
/* Tailwind CSS同等 */
/* sm: @media (min-width: 640px) */
/* md: @media (min-width: 768px) */
/* lg: @media (min-width: 1024px) */
/* xl: @media (min-width: 1280px) */
/* 2xl: @media (min-width: 1536px) */
キーパターン
パターン1: コンテナクエリ
/* 包含コンテキストを定義 */
.card-container {
container-type: inline-size;
container-name: card;
}
/* ビューポートではなくコンテナをクエリ */
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1rem;
}
.card-image {
aspect-ratio: 1;
}
}
@container card (min-width: 600px) {
.card {
grid-template-columns: 250px 1fr;
}
.card-title {
font-size: 1.5rem;
}
}
/* コンテナクエリユニット */
.card-title {
/* コンテナ幅の5%, 1remから2remの間にクランプ */
font-size: clamp(1rem, 5cqi, 2rem);
}
// コンテナクエリを使用したReactコンポーネント
function ResponsiveCard({ title, image, description }) {
return (
<div className="@container">
<article className="flex flex-col @md:flex-row @md:gap-4">
<img
src={image}
alt=""
className="w-full @md:w-48 @lg:w-64 aspect-video @md:aspect-square object-cover"
/>
<div className="p-4 @md:p-0">
<h2 className="text-lg @md:text-xl @lg:text-2xl font-semibold">
{title}
</h2>
<p className="mt-2 text-muted-foreground @md:line-clamp-3">
{description}
</p>
</div>
</article>
</div>
);
}
パターン2: 流動的なタイポグラフィ
/* clamp()を使用した流動的なタイプスケール */
:root {
/* 最小サイズ、推奨値(流動的)、最大サイズ */
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);
--text-xl: clamp(1.25rem, 1rem + 1.25vw, 1.5rem);
--text-2xl: clamp(1.5rem, 1.25rem + 1.25vw, 2rem);
--text-3xl: clamp(1.875rem, 1.5rem + 1.875vw, 2.5rem);
--text-4xl: clamp(2.25rem, 1.75rem + 2.5vw, 3.5rem);
}
/* 使用例 */
h1 {
font-size: var(--text-4xl);
}
h2 {
font-size: var(--text-3xl);
}
h3 {
font-size: var(--text-2xl);
}
p {
font-size: var(--text-base);
}
/* 流動的スペーシングスケール */
:root {
--space-xs: clamp(0.25rem, 0.2rem + 0.25vw, 0.5rem);
--space-sm: clamp(0.5rem, 0.4rem + 0.5vw, 0.75rem);
--space-md: clamp(1rem, 0.8rem + 1vw, 1.5rem);
--space-lg: clamp(1.5rem, 1.2rem + 1.5vw, 2.5rem);
--space-xl: clamp(2rem, 1.5rem + 2.5vw, 4rem);
}
// 流動的な値のためのユーティリティ関数
function fluidValue(
minSize: number,
maxSize: number,
minWidth = 320,
maxWidth = 1280,
) {
const slope = (maxSize - minSize) / (maxWidth - minWidth);
const yAxisIntersection = -minWidth * slope + minSize;
return `clamp(${minSize}rem, ${yAxisIntersection.toFixed(4)}rem + ${(slope * 100).toFixed(4)}vw, ${maxSize}rem)`;
}
// 流動的なタイプスケール生成
const fluidTypeScale = {
sm: fluidValue(0.875, 1),
base: fluidValue(1, 1.125),
lg: fluidValue(1.25, 1.5),
xl: fluidValue(1.5, 2),
"2xl": fluidValue(2, 3),
};
パターン3: CSS Gridレスポンシブレイアウト
/* オートフィットグリッド - アイテムが自動的にラップ */
.grid-auto {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
gap: 1.5rem;
}
/* オートフィルグリッド - 空の列を保持 */
.grid-auto-fill {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
/* 名前付き領域を使用したレスポンシブグリッド */
.page-layout {
display: grid;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
gap: 1rem;
}
@media (min-width: 768px) {
.page-layout {
grid-template-columns: 1fr 300px;
grid-template-areas:
"header header"
"main sidebar"
"footer footer";
}
}
@media (min-width: 1024px) {
.page-layout {
grid-template-columns: 250px 1fr 300px;
grid-template-areas:
"header header header"
"nav main sidebar"
"footer footer footer";
}
}
.header {
grid-area: header;
}
.main {
grid-area: main;
}
.sidebar {
grid-area: sidebar;
}
.footer {
grid-area: footer;
}
// レスポンシブグリッドコンポーネント
function ResponsiveGrid({ children, minItemWidth = "250px", gap = "1.5rem" }) {
return (
<div
className="grid"
style={{
gridTemplateColumns: `repeat(auto-fit, minmax(min(${minItemWidth}, 100%), 1fr))`,
gap,
}}
>
{children}
</div>
);
}
// Tailwindでの使用例
function ProductGrid({ products }) {
return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-6">
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
パターン4: レスポンシブナビゲーション
function ResponsiveNav({ items }) {
const [isOpen, setIsOpen] = useState(false);
return (
<nav className="relative">
{/* モバイルメニューボタン */}
<button
className="lg:hidden p-2"
onClick={() => setIsOpen(!isOpen)}
aria-expanded={isOpen}
aria-controls="nav-menu"
>
<span className="sr-only">ナビゲーション切り替え</span>
{isOpen ? <X /> : <Menu />}
</button>
{/* ナビゲーションリンク */}
<ul
id="nav-menu"
className={cn(
// ベース: モバイルで非表示
"absolute top-full left-0 right-0 bg-background border-b",
"flex flex-col",
// モバイル: スライドダウン
isOpen ? "flex" : "hidden",
// デスクトップ: 常に表示、水平
"lg:static lg:flex lg:flex-row lg:border-0 lg:bg-transparent",
)}
>
{items.map((item) => (
<li key={item.href}>
<a
href={item.href}
className={cn(
"block px-4 py-3",
"lg:px-3 lg:py-2",
"hover:bg-muted lg:hover:bg-transparent lg:hover:text-primary",
)}
>
{item.label}
</a>
</li>
))}
</ul>
</nav>
);
}
パターン5: レスポンシブ画像
// アートディレクション付きレスポンシブ画像
function ResponsiveHero() {
return (
<picture>
{/* アートディレクション: 異なるスクリーンに異なるクロップ */}
<source
media="(min-width: 1024px)"
srcSet="/hero-wide.webp"
type="image/webp"
/>
<source
media="(min-width: 768px)"
srcSet="/hero-medium.webp"
type="image/webp"
/>
<source srcSet="/hero-mobile.webp" type="image/webp" />
{/* フォールバック */}
<img
src="/hero-mobile.jpg"
alt="ヒーロー画像の説明"
className="w-full h-auto"
loading="eager"
fetchpriority="high"
/>
</picture>
);
}
// 解像度切り替え用のsrcset付きレスポンシブ画像
function ProductImage({ product }) {
return (
<img
src={product.image}
srcSet={`
${product.image}?w=400 400w,
${product.image}?w=800 800w,
${product.image}?w=1200 1200w
`}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
alt={product.name}
className="w-full h-auto object-cover"
loading="lazy"
/>
);
}
パターン6: レスポンシブテーブル
// 水平スクロール付きレスポンシブテーブル
function ResponsiveTable({ data, columns }) {
return (
<div className="w-full overflow-x-auto">
<table className="w-full min-w-[600px]">
<thead>
<tr>
{columns.map((col) => (
<th key={col.key} className="text-left p-3">
{col.label}
</th>
))}
</tr>
</thead>
<tbody>
{data.map((row, i) => (
<tr key={i} className="border-t">
{columns.map((col) => (
<td key={col.key} className="p-3">
{row[col.key]}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
// モバイル用カードベーステーブル
function ResponsiveDataTable({ data, columns }) {
return (
<>
{/* デスクトップテーブル */}
<table className="hidden md:table w-full">
{/* ... 標準的なテーブル */}
</table>
{/* モバイルカード */}
<div className="md:hidden space-y-4">
{data.map((row, i) => (
<div key={i} className="border rounded-lg p-4 space-y-2">
{columns.map((col) => (
<div key={col.key} className="flex justify-between">
<span className="font-medium text-muted-foreground">
{col.label}
</span>
<span>{row[col.key]}</span>
</div>
))}
</div>
))}
</div>
</>
);
}
ビューポートユニット
/* 標準ビューポートユニット */
.full-height {
height: 100vh; /* モバイルで問題を引き起こす可能性 */
}
/* 動的ビューポートユニット (モバイルに推奨) */
.full-height-dynamic {
height: 100dvh; /* モバイルブラウザUI対応 */
}
/* 小さなビューポート (最小) */
.min-full-height {
min-height: 100svh;
}
/* 大きなビューポート (最大) */
.max-full-height {
max-height: 100lvh;
}
/* ビューポート相対フォントサイズ */
.hero-title {
/* min/maxで制限された5vw */
font-size: clamp(2rem, 5vw, 4rem);
}
ベストプラクティス
- モバイルファースト: モバイルスタイルから始め、より大きなスクリーン向けに拡張
- コンテンツブレークポイント: デバイスではなくコンテンツに基づいてブレークポイントを設定
- 固定値より流動的: タイポグラフィとスペーシングに流動的な値を使用
- コンテナクエリ: コンポーネントレベルのレスポンシブ性に使用
- 実デバイスでテスト: シミュレーターはすべての問題をキャッチしない
- パフォーマンス: 画像を最適化し、画面外コンテンツを遅延読み込み
- タッチターゲット: モバイルでは最小44x44pxを維持
- 論理プロパティ: 国際化のためにinline/blockを使用
よくある問題
- 水平オーバーフロー: コンテンツがビューポート外に飛び出す
- 固定幅: pxの代わりに相対単位を使用していない
- ビューポート高さ: モバイルブラウザの100vh問題
- フォントサイズ: モバイルでテキストが小さすぎる
- タッチターゲット: ボタンがタップするのに小さすぎる
- アスペクト比: 画像が歪んだり伸びたりする
- Z-Indexスタッキング: 異なるスクリーンでオーバーレイが破損
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- wshobson
- リポジトリ
- wshobson/agents
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/wshobson/agents / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。