关于 responsive-design-system
用于使用 CSS 和 Tailwind 构建移动优先响应式布局的技能,涵盖断点、流式尺寸、容器查询、自适应组件和视口测试。
主要功能
- 01定义响应式断点
- 02流式调整字体与间距
- 03使用容器查询
- 04构建自适应布局与组件
- 05应用响应式图片模式
- 06测试不同视口尺寸
适用场景
- 01创建适用于手机到桌面的布局
- 02让卡片根据容器调整
- 03检查移动端表格和触控区域
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ patricio0312rev/ skills --skill responsive-design-system安装后在 Claude Code 中输入/responsive-design-system确认已加载。
详细介绍
响应式设计系统
使用现代 CSS 特性和 Tailwind 构建自适应、移动优先的布局。
核心工作流
- 定义断点:建立响应式断点系统
- 设置流体排版:使用基于 Clamp 的响应式字体
- 创建布局网格:构建响应式网格系统
- 添加容器查询:实现组件级响应
- 构建响应式组件:采用自适应模式
- 跨设备测试:在所有视口中验证
断点系统
Tailwind 默认断点
| 断点 | 最小宽度 | 目标设备 |
|---|---|---|
sm | 640px | 大屏手机(横屏) |
md | 768px | 平板电脑 |
lg | 1024px | 笔记本电脑 |
xl | 1280px | 台式电脑 |
2xl | 1536px | 大屏幕 |
自定义断点
// tailwind.config.js
module.exports = {
theme: {
screens: {
'xs': '475px',
'sm': '640px',
'md': '768px',
'lg': '1024px',
'xl': '1280px',
'2xl': '1536px',
'3xl': '1920px',
// Max-width breakpoints
'max-sm': { max: '639px' },
'max-md': { max: '767px' },
'max-lg': { max: '1023px' },
// Range breakpoints
'tablet': { min: '768px', max: '1023px' },
// Feature queries
'touch': { raw: '(hover: none) and (pointer: coarse)' },
'stylus': { raw: '(hover: none) and (pointer: fine)' },
'mouse': { raw: '(hover: hover) and (pointer: fine)' },
},
},
};
流体排版
CSS Clamp 函数
/* globals.css */
:root {
/* Fluid type scale: min, preferred, max */
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.125rem, 1rem + 0.6vw, 1.25rem);
--text-xl: clamp(1.25rem, 1.1rem + 0.75vw, 1.5rem);
--text-2xl: clamp(1.5rem, 1.2rem + 1.5vw, 2rem);
--text-3xl: clamp(1.875rem, 1.4rem + 2.25vw, 2.5rem);
--text-4xl: clamp(2.25rem, 1.5rem + 3.75vw, 3.5rem);
--text-5xl: clamp(3rem, 1.8rem + 6vw, 5rem);
/* Fluid spacing */
--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, 1rem + 2.5vw, 3rem);
--space-xl: clamp(2rem, 1.2rem + 4vw, 5rem);
}
Tailwind 流体排版
// tailwind.config.js
const plugin = require('tailwindcss/plugin');
module.exports = {
theme: {
extend: {
fontSize: {
'fluid-xs': 'clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem)',
'fluid-sm': 'clamp(0.875rem, 0.8rem + 0.35vw, 1rem)',
'fluid-base': 'clamp(1rem, 0.9rem + 0.5vw, 1.125rem)',
'fluid-lg': 'clamp(1.125rem, 1rem + 0.6vw, 1.25rem)',
'fluid-xl': 'clamp(1.25rem, 1.1rem + 0.75vw, 1.5rem)',
'fluid-2xl': 'clamp(1.5rem, 1.2rem + 1.5vw, 2rem)',
'fluid-3xl': 'clamp(1.875rem, 1.4rem + 2.25vw, 2.5rem)',
'fluid-4xl': 'clamp(2.25rem, 1.5rem + 3.75vw, 3.5rem)',
'fluid-5xl': 'clamp(3rem, 1.8rem + 6vw, 5rem)',
},
},
},
};
用法
<h1 class="text-fluid-4xl font-bold">Responsive Headline</h1>
<p class="text-fluid-base">Body text that scales smoothly.</p>
容器查询
启用容器查询
// tailwind.config.js
module.exports = {
theme: {
extend: {
containers: {
'xs': '320px',
'sm': '384px',
'md': '448px',
'lg': '512px',
'xl': '576px',
'2xl': '672px',
},
},
},
};
容器查询用法
<div class="@container">
<div class="flex flex-col @md:flex-row @lg:gap-8">
<div class="@md:w-1/2">
<h2 class="text-lg @lg:text-2xl">Card Title</h2>
</div>
<div class="@md:w-1/2">
<p class="text-sm @lg:text-base">Card content</p>
</div>
</div>
</div>
<div class="@container/main">
<div class="@lg/main:grid-cols-3">...</div>
</div>
响应式卡片组件
// components/ResponsiveCard.tsx
export function ResponsiveCard({ title, description, image }: CardProps) {
return (
<article className="@container">
<div className="flex flex-col @sm:flex-row gap-4 p-4 bg-white rounded-lg shadow">
<img
src={image}
alt=""
className="w-full @sm:w-32 @md:w-48 h-32 @sm:h-auto object-cover rounded"
/>
<div className="flex-1">
<h3 className="text-lg @md:text-xl font-semibold">{title}</h3>
<p className="text-sm @md:text-base text-gray-600 mt-2">
{description}
</p>
<button className="mt-4 px-4 py-2 bg-blue-500 text-white rounded @md:px-6">
Learn More
</button>
</div>
</div>
</article>
);
}
响应式网格布局
自动适配网格
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
</div>
<div class="grid gap-6" style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr))">
</div>
仪表板布局
// components/DashboardLayout.tsx
export function DashboardLayout({ sidebar, main }: LayoutProps) {
return (
<div className="min-h-screen flex flex-col lg:flex-row">
{/* Sidebar: Full width on mobile, fixed width on desktop */}
<aside className="w-full lg:w-64 xl:w-80 bg-gray-900 text-white">
<div className="p-4 lg:sticky lg:top-0">{sidebar}</div>
</aside>
{/* Main content */}
<main className="flex-1 p-4 md:p-6 lg:p-8">
<div className="max-w-7xl mx-auto">{main}</div>
</main>
</div>
);
}
圣杯布局
export function HolyGrailLayout({ header, sidebar, main, aside, footer }: LayoutProps) {
return (
<div className="min-h-screen grid grid-rows-[auto_1fr_auto]">
<header className="bg-white border-b px-4 py-3">
{header}
</header>
<div className="grid grid-cols-1 md:grid-cols-[240px_1fr] lg:grid-cols-[240px_1fr_240px]">
<aside className="hidden md:block bg-gray-50 p-4 border-r">
{sidebar}
</aside>
<main className="p-4 md:p-6 overflow-auto">
{main}
</main>
<aside className="hidden lg:block bg-gray-50 p-4 border-l">
{aside}
</aside>
</div>
<footer className="bg-gray-900 text-white px-4 py-6">
{footer}
</footer>
</div>
);
}
响应式图像
Srcset 和 Sizes
<img
src="/images/hero-800.jpg"
srcset="
/images/hero-400.jpg 400w,
/images/hero-800.jpg 800w,
/images/hero-1200.jpg 1200w,
/images/hero-1600.jpg 1600w
"
sizes="(max-width: 640px) 100vw,
(max-width: 1024px) 75vw,
50vw"
alt="Hero image"
class="w-full h-auto"
/>
Next.js Image
import Image from 'next/image';
export function ResponsiveImage({ src, alt }: ImageProps) {
return (
<div className="relative aspect-video w-full">
<Image
src={src}
alt={alt}
fill
sizes="(max-width: 640px) 100vw,
(max-width: 1024px) 75vw,
50vw"
className="object-cover"
/>
</div>
);
}
使用 Picture 实现艺术指导
<picture>
<source
media="(max-width: 639px)"
srcset="/images/hero-mobile.jpg"
/>
<source
media="(max-width: 1023px)"
srcset="/images/hero-tablet.jpg"
/>
<img
src="/images/hero-desktop.jpg"
alt="Hero"
class="w-full h-auto"
/>
</picture>
响应式导航
移动端菜单模式
'use client';
import { useState } from 'react';
import { Menu, X } from 'lucide-react';
export function ResponsiveNav({ links }: NavProps) {
const [isOpen, setIsOpen] = useState(false);
return (
<nav className="relative">
{/* Desktop Navigation */}
<div className="hidden md:flex items-center gap-8">
{links.map((link) => (
<a key={link.href} href={link.href} className="hover:text-blue-500">
{link.label}
</a>
))}
</div>
{/* Mobile Menu Button */}
<button
onClick={() => setIsOpen(!isOpen)}
className="md:hidden p-2"
aria-label="Toggle menu"
>
{isOpen ? <X size={24} /> : <Menu size={24} />}
</button>
{/* Mobile Navigation */}
{isOpen && (
<div className="absolute top-full left-0 right-0 bg-white shadow-lg md:hidden">
{links.map((link) => (
<a
key={link.href}
href={link.href}
className="block px-4 py-3 border-b hover:bg-gray-50"
>
{link.label}
</a>
))}
</div>
)}
</nav>
);
}
响应式表格
横向滚动
<div class="overflow-x-auto">
<table class="min-w-full">
</table>
</div>
移动端堆叠显示
export function ResponsiveTable({ headers, rows }: TableProps) {
return (
<>
{/* Desktop Table */}
<table className="hidden md:table w-full">
<thead>
<tr>
{headers.map((header) => (
<th key={header} className="px-4 py-2 text-left">{header}</th>
))}
</tr>
</thead>
<tbody>
{rows.map((row, i) => (
<tr key={i}>
{row.map((cell, j) => (
<td key={j} className="px-4 py-2">{cell}</td>
))}
</tr>
))}
</tbody>
</table>
{/* Mobile Cards */}
<div className="md:hidden space-y-4">
{rows.map((row, i) => (
<div key={i} className="bg-white p-4 rounded-lg shadow">
{row.map((cell, j) => (
<div key={j} className="flex justify-between py-2 border-b last:border-0">
<span className="font-medium text-gray-600">{headers[j]}</span>
<span>{cell}</span>
</div>
))}
</div>
))}
</div>
</>
);
}
触控友好的目标区域
/* Minimum touch target size: 44x44px */
.touch-target {
min-height: 44px;
min-width: 44px;
}
/* Tailwind equivalent */
@layer components {
.btn-touch {
@apply min-h-[44px] min-w-[44px] px-4 py-2;
}
}
<button class="min-h-[44px] min-w-[44px] px-4 py-2 bg-blue-500 text-white rounded">
Click Me
</button>
<a href="#" class="inline-block py-3 px-4">
Touch-friendly link
</a>
响应式间距
// tailwind.config.js
module.exports = {
theme: {
extend: {
spacing: {
// Fluid spacing
'fluid-1': 'clamp(0.25rem, 0.5vw, 0.5rem)',
'fluid-2': 'clamp(0.5rem, 1vw, 1rem)',
'fluid-4': 'clamp(1rem, 2vw, 2rem)',
'fluid-8': 'clamp(2rem, 4vw, 4rem)',
'fluid-16': 'clamp(4rem, 8vw, 8rem)',
},
},
},
};
<section class="py-fluid-8 px-fluid-4">
<h2 class="mb-fluid-4">Section Title</h2>
<p>Content with responsive spacing</p>
</section>
测试响应式设计
设备测试清单
## Viewport Testing
- [ ] 320px (iPhone SE)
- [ ] 375px (iPhone 12/13)
- [ ] 390px (iPhone 14 Pro)
- [ ] 428px (iPhone 14 Pro Max)
- [ ] 768px (iPad)
- [ ] 1024px (iPad Pro / Small laptop)
- [ ] 1280px (Laptop)
- [ ] 1440px (Desktop)
- [ ] 1920px (Full HD)
- [ ] 2560px (QHD)
## Orientation Testing
- [ ] Portrait mode
- [ ] Landscape mode
## Interaction Testing
- [ ] Touch interactions
- [ ] Hover states (mouse)
- [ ] Keyboard navigation
最佳实践
- 移动优先:从移动端样式开始,再为更大屏幕增强样式
- 使用相对单位:优先使用
rem、em、%、vw/vh,而非px - 在真实设备上测试:模拟器无法发现所有问题
- 使用流体尺寸而非固定尺寸:使用
clamp()实现平滑缩放 - 容器查询:用于组件级响应
- 触控目标:交互元素的最小尺寸为 44x44px
- 内容优先级:在移动端优先显示最重要的内容
- 性能:提供尺寸合适的图像
输出检查清单
每个响应式实现都应包含:
- 移动优先方案
- 已定义且保持一致的断点
- 使用 clamp() 实现流体排版
- 组件使用容器查询
- 使用 srcset 提供响应式图像
- 触控友好的点击目标(44px 及以上)
- 已在真实设备上测试
- 防止横向滚动
- 导航可适配屏幕尺寸
- 表格在移动端易于阅读
评论
支持 Markdown