mirror of
https://github.com/wshobson/agents.git
synced 2026-03-18 09:37:15 +00:00
feat(ui-design): add comprehensive UI/UX design plugin v1.0.0
New plugin covering mobile (iOS, Android, React Native) and web applications with modern design patterns, accessibility, and design systems. Components: - 9 skills: design-system-patterns, accessibility-compliance, responsive-design, mobile-ios-design, mobile-android-design, react-native-design, web-component-design, interaction-design, visual-design-foundations - 4 commands: design-review, create-component, accessibility-audit, design-system-setup - 3 agents: ui-designer, accessibility-expert, design-system-architect Marketplace updated: - Version bumped to 1.3.4 - 102 agents (+3), 116 skills (+9)
This commit is contained in:
493
plugins/ui-design/skills/responsive-design/SKILL.md
Normal file
493
plugins/ui-design/skills/responsive-design/SKILL.md
Normal file
@@ -0,0 +1,493 @@
|
||||
---
|
||||
name: responsive-design
|
||||
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.
|
||||
---
|
||||
|
||||
# Responsive Design
|
||||
|
||||
Master modern responsive design techniques to create interfaces that adapt seamlessly across all screen sizes and device contexts.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- Implementing mobile-first responsive layouts
|
||||
- Using container queries for component-based responsiveness
|
||||
- Creating fluid typography and spacing scales
|
||||
- Building complex layouts with CSS Grid and Flexbox
|
||||
- Designing breakpoint strategies for design systems
|
||||
- Implementing responsive images and media
|
||||
- Creating adaptive navigation patterns
|
||||
- Building responsive tables and data displays
|
||||
|
||||
## Core Capabilities
|
||||
|
||||
### 1. Container Queries
|
||||
- Component-level responsiveness independent of viewport
|
||||
- Container query units (cqi, cqw, cqh)
|
||||
- Style queries for conditional styling
|
||||
- Fallbacks for browser support
|
||||
|
||||
### 2. Fluid Typography & Spacing
|
||||
- CSS clamp() for fluid scaling
|
||||
- Viewport-relative units (vw, vh, dvh)
|
||||
- Fluid type scales with min/max bounds
|
||||
- Responsive spacing systems
|
||||
|
||||
### 3. Layout Patterns
|
||||
- CSS Grid for 2D layouts
|
||||
- Flexbox for 1D distribution
|
||||
- Intrinsic layouts (content-based sizing)
|
||||
- Subgrid for nested grid alignment
|
||||
|
||||
### 4. Breakpoint Strategy
|
||||
- Mobile-first media queries
|
||||
- Content-based breakpoints
|
||||
- Design token integration
|
||||
- Feature queries (@supports)
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Modern Breakpoint Scale
|
||||
|
||||
```css
|
||||
/* Mobile-first breakpoints */
|
||||
/* Base: Mobile (< 640px) */
|
||||
@media (min-width: 640px) { /* sm: Landscape phones, small tablets */ }
|
||||
@media (min-width: 768px) { /* md: Tablets */ }
|
||||
@media (min-width: 1024px) { /* lg: Laptops, small desktops */ }
|
||||
@media (min-width: 1280px) { /* xl: Desktops */ }
|
||||
@media (min-width: 1536px) { /* 2xl: Large desktops */ }
|
||||
|
||||
/* Tailwind CSS equivalent */
|
||||
/* 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) */
|
||||
```
|
||||
|
||||
## Key Patterns
|
||||
|
||||
### Pattern 1: Container Queries
|
||||
|
||||
```css
|
||||
/* Define a containment context */
|
||||
.card-container {
|
||||
container-type: inline-size;
|
||||
container-name: card;
|
||||
}
|
||||
|
||||
/* Query the container, not the viewport */
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Container query units */
|
||||
.card-title {
|
||||
/* 5% of container width, clamped between 1rem and 2rem */
|
||||
font-size: clamp(1rem, 5cqi, 2rem);
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// React component with container queries
|
||||
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>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 2: Fluid Typography
|
||||
|
||||
```css
|
||||
/* Fluid type scale using clamp() */
|
||||
:root {
|
||||
/* Min size, preferred (fluid), max size */
|
||||
--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);
|
||||
}
|
||||
|
||||
/* Usage */
|
||||
h1 { font-size: var(--text-4xl); }
|
||||
h2 { font-size: var(--text-3xl); }
|
||||
h3 { font-size: var(--text-2xl); }
|
||||
p { font-size: var(--text-base); }
|
||||
|
||||
/* Fluid spacing scale */
|
||||
: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);
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// Utility function for fluid values
|
||||
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)`;
|
||||
}
|
||||
|
||||
// Generate fluid type scale
|
||||
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),
|
||||
};
|
||||
```
|
||||
|
||||
### Pattern 3: CSS Grid Responsive Layout
|
||||
|
||||
```css
|
||||
/* Auto-fit grid - items wrap automatically */
|
||||
.grid-auto {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
/* Auto-fill grid - maintains empty columns */
|
||||
.grid-auto-fill {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* Responsive grid with named areas */
|
||||
.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; }
|
||||
```
|
||||
|
||||
```tsx
|
||||
// Responsive grid component
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
// Usage with 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>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 4: Responsive Navigation
|
||||
|
||||
```tsx
|
||||
function ResponsiveNav({ items }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<nav className="relative">
|
||||
{/* Mobile menu button */}
|
||||
<button
|
||||
className="lg:hidden p-2"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
aria-expanded={isOpen}
|
||||
aria-controls="nav-menu"
|
||||
>
|
||||
<span className="sr-only">Toggle navigation</span>
|
||||
{isOpen ? <X /> : <Menu />}
|
||||
</button>
|
||||
|
||||
{/* Navigation links */}
|
||||
<ul
|
||||
id="nav-menu"
|
||||
className={cn(
|
||||
// Base: hidden on mobile
|
||||
'absolute top-full left-0 right-0 bg-background border-b',
|
||||
'flex flex-col',
|
||||
// Mobile: slide down
|
||||
isOpen ? 'flex' : 'hidden',
|
||||
// Desktop: always visible, horizontal
|
||||
'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>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 5: Responsive Images
|
||||
|
||||
```tsx
|
||||
// Responsive image with art direction
|
||||
function ResponsiveHero() {
|
||||
return (
|
||||
<picture>
|
||||
{/* Art direction: different crops for different screens */}
|
||||
<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" />
|
||||
|
||||
{/* Fallback */}
|
||||
<img
|
||||
src="/hero-mobile.jpg"
|
||||
alt="Hero image description"
|
||||
className="w-full h-auto"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
/>
|
||||
</picture>
|
||||
);
|
||||
}
|
||||
|
||||
// Responsive image with srcset for resolution switching
|
||||
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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 6: Responsive Tables
|
||||
|
||||
```tsx
|
||||
// Responsive table with horizontal scroll
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
// Card-based table for mobile
|
||||
function ResponsiveDataTable({ data, columns }) {
|
||||
return (
|
||||
<>
|
||||
{/* Desktop table */}
|
||||
<table className="hidden md:table w-full">
|
||||
{/* ... standard table */}
|
||||
</table>
|
||||
|
||||
{/* Mobile cards */}
|
||||
<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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Viewport Units
|
||||
|
||||
```css
|
||||
/* Standard viewport units */
|
||||
.full-height {
|
||||
height: 100vh; /* May cause issues on mobile */
|
||||
}
|
||||
|
||||
/* Dynamic viewport units (recommended for mobile) */
|
||||
.full-height-dynamic {
|
||||
height: 100dvh; /* Accounts for mobile browser UI */
|
||||
}
|
||||
|
||||
/* Small viewport (minimum) */
|
||||
.min-full-height {
|
||||
min-height: 100svh;
|
||||
}
|
||||
|
||||
/* Large viewport (maximum) */
|
||||
.max-full-height {
|
||||
max-height: 100lvh;
|
||||
}
|
||||
|
||||
/* Viewport-relative font sizing */
|
||||
.hero-title {
|
||||
/* 5vw with min/max bounds */
|
||||
font-size: clamp(2rem, 5vw, 4rem);
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Mobile-First**: Start with mobile styles, enhance for larger screens
|
||||
2. **Content Breakpoints**: Set breakpoints based on content, not devices
|
||||
3. **Fluid Over Fixed**: Use fluid values for typography and spacing
|
||||
4. **Container Queries**: Use for component-level responsiveness
|
||||
5. **Test Real Devices**: Simulators don't catch all issues
|
||||
6. **Performance**: Optimize images, lazy load off-screen content
|
||||
7. **Touch Targets**: Maintain 44x44px minimum on mobile
|
||||
8. **Logical Properties**: Use inline/block for internationalization
|
||||
|
||||
## Common Issues
|
||||
|
||||
- **Horizontal Overflow**: Content breaking out of viewport
|
||||
- **Fixed Widths**: Using px instead of relative units
|
||||
- **Viewport Height**: 100vh issues on mobile browsers
|
||||
- **Font Size**: Text too small on mobile
|
||||
- **Touch Targets**: Buttons too small to tap accurately
|
||||
- **Aspect Ratio**: Images squishing or stretching
|
||||
- **Z-Index Stacking**: Overlays breaking on different screens
|
||||
|
||||
## Resources
|
||||
|
||||
- [CSS Container Queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries)
|
||||
- [Utopia Fluid Type Calculator](https://utopia.fyi/type/calculator/)
|
||||
- [Every Layout](https://every-layout.dev/)
|
||||
- [Responsive Images Guide](https://web.dev/responsive-images/)
|
||||
- [CSS Grid Garden](https://cssgridgarden.com/)
|
||||
Reference in New Issue
Block a user