Visual Design Foundations
Build cohesive, accessible visual systems using typography, color, spacing, and iconography fundamentals.
When to Use This Skill
-
Establishing design tokens for a new project
-
Creating or refining a spacing and sizing system
-
Selecting and pairing typefaces
-
Building accessible color palettes
-
Designing icon systems and visual assets
-
Improving visual hierarchy and readability
-
Auditing designs for visual consistency
-
Implementing dark mode or theming
Core Systems
- Typography Scale
Modular Scale (ratio-based sizing):
:root { --font-size-xs: 0.75rem; /* 12px / --font-size-sm: 0.875rem; / 14px / --font-size-base: 1rem; / 16px / --font-size-lg: 1.125rem; / 18px / --font-size-xl: 1.25rem; / 20px / --font-size-2xl: 1.5rem; / 24px / --font-size-3xl: 1.875rem; / 30px / --font-size-4xl: 2.25rem; / 36px / --font-size-5xl: 3rem; / 48px */ }
Line Height Guidelines:
Text Type Line Height
Headings 1.1 - 1.3
Body text 1.5 - 1.7
UI labels 1.2 - 1.4
- Spacing System
8-point grid (industry standard):
:root { --space-1: 0.25rem; /* 4px / --space-2: 0.5rem; / 8px / --space-3: 0.75rem; / 12px / --space-4: 1rem; / 16px / --space-5: 1.25rem; / 20px / --space-6: 1.5rem; / 24px / --space-8: 2rem; / 32px / --space-10: 2.5rem; / 40px / --space-12: 3rem; / 48px / --space-16: 4rem; / 64px */ }
- Color System
Semantic color tokens:
:root { /* Brand */ --color-primary: #2563eb; --color-primary-hover: #1d4ed8; --color-primary-active: #1e40af;
/* Semantic */ --color-success: #16a34a; --color-warning: #ca8a04; --color-error: #dc2626; --color-info: #0891b2;
/* Neutral */ --color-gray-50: #f9fafb; --color-gray-100: #f3f4f6; --color-gray-200: #e5e7eb; --color-gray-300: #d1d5db; --color-gray-400: #9ca3af; --color-gray-500: #6b7280; --color-gray-600: #4b5563; --color-gray-700: #374151; --color-gray-800: #1f2937; --color-gray-900: #111827; }
Quick Start: Design Tokens in Tailwind
// tailwind.config.js module.exports = { theme: { extend: { fontFamily: { sans: ["Inter", "system-ui", "sans-serif"], mono: ["JetBrains Mono", "monospace"], }, fontSize: { xs: ["0.75rem", { lineHeight: "1rem" }], sm: ["0.875rem", { lineHeight: "1.25rem" }], base: ["1rem", { lineHeight: "1.5rem" }], lg: ["1.125rem", { lineHeight: "1.75rem" }], xl: ["1.25rem", { lineHeight: "1.75rem" }], "2xl": ["1.5rem", { lineHeight: "2rem" }], }, colors: { brand: { 50: "#eff6ff", 500: "#3b82f6", 600: "#2563eb", 700: "#1d4ed8", }, }, spacing: { // Extends default with custom values 18: "4.5rem", 88: "22rem", }, }, }, };
Typography Best Practices
Font Pairing
Safe combinations:
-
Heading: Inter / Body: Inter (single family)
-
Heading: Playfair Display / Body: Source Sans Pro (contrast)
-
Heading: Space Grotesk / Body: IBM Plex Sans (geometric)
Responsive Typography
/* Fluid typography using clamp() */ h1 { font-size: clamp(2rem, 5vw + 1rem, 3.5rem); line-height: 1.1; }
p { font-size: clamp(1rem, 2vw + 0.5rem, 1.125rem); line-height: 1.6; max-width: 65ch; /* Optimal reading width */ }
Font Loading
/* Prevent layout shift */ @font-face { font-family: "Inter"; src: url("/fonts/Inter.woff2") format("woff2"); font-display: swap; font-weight: 400 700; }
Color Theory
Contrast Requirements (WCAG)
Element Minimum Ratio
Body text 4.5:1 (AA)
Large text (18px+) 3:1 (AA)
UI components 3:1 (AA)
Enhanced 7:1 (AAA)
Dark Mode Strategy
:root { --bg-primary: #ffffff; --bg-secondary: #f9fafb; --text-primary: #111827; --text-secondary: #6b7280; --border: #e5e7eb; }
[data-theme="dark"] { --bg-primary: #111827; --bg-secondary: #1f2937; --text-primary: #f9fafb; --text-secondary: #9ca3af; --border: #374151; }
Color Accessibility
// Check contrast programmatically function getContrastRatio(foreground: string, background: string): number { const getLuminance = (hex: string) => { const rgb = hexToRgb(hex); const [r, g, b] = rgb.map((c) => { c = c / 255; return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); }); return 0.2126 * r + 0.7152 * g + 0.0722 * b; };
const l1 = getLuminance(foreground); const l2 = getLuminance(background); const lighter = Math.max(l1, l2); const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05); }
Spacing Guidelines
Component Spacing
Card padding: 16-24px (--space-4 to --space-6) Section gap: 32-64px (--space-8 to --space-16) Form field gap: 16-24px (--space-4 to --space-6) Button padding: 8-16px vertical, 16-24px horizontal Icon-text gap: 8px (--space-2)
Visual Rhythm
/* Consistent vertical rhythm */ .prose > * + * { margin-top: var(--space-4); }
.prose > h2 + * { margin-top: var(--space-2); }
.prose > * + h2 { margin-top: var(--space-8); }
Iconography
Icon Sizing System
:root { --icon-xs: 12px; --icon-sm: 16px; --icon-md: 20px; --icon-lg: 24px; --icon-xl: 32px; }
Icon Component
interface IconProps { name: string; size?: "xs" | "sm" | "md" | "lg" | "xl"; className?: string; }
const sizeMap = { xs: 12, sm: 16, md: 20, lg: 24, xl: 32, };
export function Icon({ name, size = "md", className }: IconProps) {
return (
<svg
width={sizeMap[size]}
height={sizeMap[size]}
className={cn("inline-block flex-shrink-0", className)}
aria-hidden="true"
>
<use href={/icons.svg#${name}} />
</svg>
);
}
Best Practices
-
Establish Constraints: Limit choices to maintain consistency
-
Document Decisions: Create a living style guide
-
Test Accessibility: Verify contrast, sizing, touch targets
-
Use Semantic Tokens: Name by purpose, not appearance
-
Design Mobile-First: Start with constraints, add complexity
-
Maintain Vertical Rhythm: Consistent spacing creates harmony
-
Limit Font Weights: 2-3 weights per family is sufficient
Common Issues
-
Inconsistent Spacing: Not using a defined scale
-
Poor Contrast: Failing WCAG requirements
-
Font Overload: Too many families or weights
-
Magic Numbers: Arbitrary values instead of tokens
-
Missing States: Forgetting hover, focus, disabled
-
No Dark Mode Plan: Retrofitting is harder than planning