Ai web-design
CSS implementation patterns for layout, typography, color, spacing, and responsive design. Complements ui-design (fundamentals) with code-focused examples.
git clone https://github.com/wpank/ai
T=$(mktemp -d) && git clone --depth=1 https://github.com/wpank/ai "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/design-systems/web-design" ~/.claude/skills/wpank-ai-web-design && rm -rf "$T"
skills/design-systems/web-design/SKILL.mdWeb Design Patterns
CSS implementation patterns for production-grade interfaces. For design fundamentals and decision-making, see
ui-design. This skill focuses on code.
See also:
for typography/color/spacing theory,ui-designfor creative aesthetics.frontend-design
Installation
OpenClaw / Moltbot / Clawbot
npx clawhub@latest install web-design
Layout Principles
Use CSS Grid for two-dimensional layouts and Flexbox for one-dimensional flow. Choose the right tool for each context.
| Layout Need | Tool | Why |
|---|---|---|
| Page-level structure | CSS Grid () | Named regions, explicit row/column control |
| Navigation bars | Flexbox | Single-axis alignment, spacing with |
| Card grids | Grid ( / ) | Responsive without media queries |
| Centering | Grid () | Shortest, most reliable centering |
| Sidebar + content | Grid () | Proportional sizing with fixed sidebar |
| Stacking overlaps | Grid + | Layer elements without |
Spatial Composition
Go beyond predictable layouts. Intentional asymmetry, overlapping elements, and grid-breaking accents create visual interest. Use grid stacking (
grid-area: 1/1) instead of position: absolute for overlapping elements. Choose generous negative space for luxury/editorial aesthetics, or controlled density for data-rich interfaces — the choice must be intentional.
Typography
Typography carries 90% of a design's personality. Choose fonts that match the interface's purpose.
| Context | Display Font Direction | Body Font Direction | Example Pairing |
|---|---|---|---|
| Editorial / magazine | High-contrast serif | Neutral humanist sans | Playfair Display + Source Sans 3 |
| SaaS dashboard | Geometric sans | Matching weight sans | DM Sans + DM Mono (data) |
| Creative portfolio | Expressive display | Clean readable sans | Syne + Outfit |
| E-commerce luxury | Thin modern serif | Elegant sans | Cormorant Garamond + Jost |
| Developer tooling | Monospace display | Monospace body | JetBrains Mono + IBM Plex Mono |
Type Scale
Use a consistent ratio. A 1.25 (major third) scale works for most interfaces:
text-xs 0.64rem, text-sm 0.8rem, text-base 1rem, text-lg 1.25rem, text-xl 1.563rem, text-2xl 1.953rem, text-3xl 2.441rem, text-4xl 3.052rem. Set body text to 1rem (16px minimum), line-height 1.5 for body, 1.1–1.2 for headings. Limit line length to 60–75ch.
Color
Building a Palette
Every palette needs five functional roles:
| Role | Purpose | Example Usage |
|---|---|---|
| Primary | Brand identity, primary actions | Buttons, links, active states |
| Neutral | Text, borders, backgrounds | Body text, cards, dividers |
| Accent | Secondary actions, highlights | Tags, badges, secondary buttons |
| Success / Warning / Error | Semantic feedback | Toasts, form validation, status |
| Surface | Layered backgrounds | Cards on page, modals on overlay |
Contrast and Depth
Create depth through surface layering, not just shadows:
:root { --surface-0: hsl(220 15% 8%); /* page background */ --surface-1: hsl(220 15% 12%); /* card */ --surface-2: hsl(220 15% 16%); /* raised element */ --surface-3: hsl(220 15% 20%); /* popover / modal */ }
Use HSL or OKLCH for perceptually uniform color manipulation. Dominant color with sharp accents outperforms evenly-distributed palettes. Always verify WCAG contrast: 4.5:1 for normal text, 3:1 for large text.
Spacing
Consistent spacing creates rhythm. Use an 8px base unit (or 4px for dense UIs):
| Token | Value | Use |
|---|---|---|
| 0.25rem (4px) | Inline icon gaps, tight padding |
| 0.5rem (8px) | Input padding, compact lists |
| 0.75rem (12px) | Button padding, card inner spacing |
| 1rem (16px) | Default element spacing |
| 1.5rem (24px) | Section padding, card gaps |
| 2rem (32px) | Section separation |
| 3rem (48px) | Major section breaks |
| 4rem (64px) | Page-level vertical rhythm |
Apply spacing consistently: use
gap on Grid/Flexbox containers instead of margins on children. This eliminates margin-collapse bugs and simplifies responsive adjustments.
Visual Hierarchy
Guide the eye through deliberate contrast in size, weight, color, and space.
Hierarchy Techniques
| Technique | How | Impact |
|---|---|---|
| Size contrast | Hero heading 3–4x body size | Immediate focal point |
| Weight contrast | Bold headings + regular body | Scannability |
| Color contrast | Primary text vs muted secondary | Information layering |
| Spatial grouping | Tight spacing within groups, wide between | Gestalt proximity |
| Elevation | Shadows / surface layers | Interactive affordance |
| Whitespace isolation | Empty space around key element | Emphasis through absence |
Practical Pattern — Card Hierarchy
Layer hierarchy within cards: eyebrow (xs, uppercase, muted) → title (xl, semibold) → body (base, secondary color, 1.6 line-height) → action (spaced apart with
margin-top). Use surface color for separation and consistent padding from spacing tokens.
Responsive Design
Breakpoint Strategy
| Breakpoint | Target | Approach |
|---|---|---|
| Mobile | Single column, stacked navigation, touch targets ≥ 44px |
| Tablet | Two-column options, collapsible sidebars |
| Desktop | Full layout, hover interactions enabled |
| Wide | Max-width container (1280px), prevent ultra-wide line lengths |
Fluid Techniques
Prefer fluid sizing over rigid breakpoints where possible:
/* Fluid typography — scales between 640px and 1440px viewport */ h1 { font-size: clamp(2rem, 1.5rem + 2.5vw, 3.5rem); } /* Fluid spacing */ section { padding-block: clamp(2rem, 1rem + 4vw, 6rem); } /* Intrinsic grid — no media queries needed */ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); gap: var(--space-6); }
Use container queries (
@container) for component-level responsiveness when a component's layout should respond to its container, not the viewport.
Accessibility
Accessibility is not optional. Build it in from the start.
| Requirement | Implementation | Standard |
|---|---|---|
| Color contrast | 4.5:1 normal text, 3:1 large text / UI | WCAG 2.1 AA |
| Keyboard navigation | All interactive elements focusable and operable | WCAG 2.1.1 |
| Focus indicators | Visible ring, 2px+ offset | WCAG 2.4.7 |
| Semantic HTML | Use , , , etc. | WCAG 1.3.1 |
| Alt text | Descriptive for informational images, for decorative | WCAG 1.1.1 |
| Motion safety | Respect | WCAG 2.3.3 |
| Touch targets | Minimum 44×44px interactive areas | WCAG 2.5.8 |
| ARIA when needed | , , only when native semantics insufficient | WCAG 4.1.2 |
/* Robust focus indicator */ :focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } /* Respect motion preferences */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
Component Design
Anatomy of a Well-Designed Component
Every UI component should have clear states, consistent spacing, and predictable behavior:
| State | Visual Treatment | Example |
|---|---|---|
| Default | Base styling | Button at rest |
| Hover | Subtle shift — background, shadow, or scale | lightens 5-10% |
| Active / Pressed | Compressed feel — reduced shadow, slight inset | |
| Focus | High-visibility ring, no outline removal | ring |
| Disabled | Reduced opacity, | |
| Loading | Spinner or skeleton, disabled interaction | Inline spinner replacing label |
Design Token Architecture
Structure tokens in three layers for maintainability:
/* Layer 1: Primitive values */ --blue-500: oklch(0.55 0.2 250); --gray-100: oklch(0.95 0.005 250); --radius-md: 0.5rem; /* Layer 2: Semantic aliases */ --color-primary: var(--blue-500); --color-surface: var(--gray-100); --radius-button: var(--radius-md); /* Layer 3: Component-specific */ --btn-bg: var(--color-primary); --btn-radius: var(--radius-button); --btn-padding: var(--space-2) var(--space-4);
This three-layer approach allows theme switching by remapping Layer 2 without touching components.
Interaction Patterns
Motion and Animation
Use motion to communicate state changes, not to decorate. Focus on high-impact moments:
| Interaction | Duration | Easing | Purpose |
|---|---|---|---|
| Button hover | 150ms | | Acknowledge interaction |
| Modal open | 250ms | | Draw attention |
| Modal close | 200ms | | Quick dismissal |
| Page transition | 300ms | | Maintain spatial context |
| Stagger reveal | 50–80ms delay per item | | Sequential content loading |
| Micro-feedback | 100ms | | Toggle, checkbox, switch |
/* Staggered entrance animation */ .stagger-item { opacity: 0; translate: 0 1rem; animation: reveal 0.5s ease-out forwards; } .stagger-item:nth-child(1) { animation-delay: 0ms; } .stagger-item:nth-child(2) { animation-delay: 60ms; } .stagger-item:nth-child(3) { animation-delay: 120ms; } @keyframes reveal { to { opacity: 1; translate: 0 0; } }
Scroll-Driven Effects
Use native
animation-timeline: scroll() (behind @supports) for parallax and reveal effects without JavaScript. Wrap in feature detection to gracefully degrade.
Design Quality Checklist
Before shipping, verify against these criteria:
- Typography: Intentional font pairing, consistent scale, readable line lengths
- Color: Cohesive palette, WCAG contrast met, semantic feedback colors defined
- Spacing: Consistent rhythm using spacing tokens, no ad-hoc pixel values
- Hierarchy: Clear visual flow — eye path follows intended reading order
- Responsiveness: Tested at mobile, tablet, desktop; no horizontal overflow
- Accessibility: Keyboard navigable, focus visible, screen-reader tested, motion-safe
- States: All interactive elements have hover, active, focus, disabled, and loading states
- Personality: Design has a clear point-of-view — not generic template aesthetic
- Performance: Images optimized, fonts subset, animations GPU-accelerated (
,transform
)opacity - Dark mode: If supported, surfaces use layered lightness, not inverted colors