Skip to main content

kb-design-system

Reference data, not a reviewer. Validate design system tokens for WCAG AA/AAA contrast. Compute color token contrast, focus ring validation (WCAG 2.4.13), motion tokens, and spacing for touch targets across frameworks.

소스 정보

저장소
Community-Access/accessibility-agents
최근 소스 활동
2026년 9월 22일 02:24
감지된 SKILL.md 언어
영어
스타
421
포크
49

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
kb-design-system
description
Reference data, not a reviewer. Validate design system tokens for WCAG AA/AAA contrast. Compute color token contrast, focus ring validation (WCAG 2.4.13), motion tokens, and spacing for touch targets across frameworks.
license
MIT
disable-model-invocation
true
user-invocable
false
metadata
{"tier":"reference","domain":"cross-cutting","output":"none","effort":"low","title":"Design System"}
## Design System Accessibility Skill This skill provides reference data for design token contrast validation, focus ring compliance, and spacing audits. Used by `design-system-auditor.agent.md`. --- ## WCAG Contrast Ratio - Computation Reference ### Step 1: Linearize sRGB Channel For each channel `C` in `[0, 255]`: ```text c = C / 255 c_lin = c / 12.92 if c <= 0.04045 c_lin = ((c + 0.055) / 1.055)^2.4 otherwise ``` ### Step 2: Relative Luminance ```text L = 0.2126 * R_lin + 0.7152 * G_lin + 0.0722 * B_lin ``` ### Step 3: Contrast Ratio ```text ratio = (L_lighter + 0.05) / (L_darker + 0.05) ``` ### Quick JavaScript Implementation ```js function relativeLuminance(hex) { const c = hex.replace('#', '').match(/.{2}/g) .map(h => parseInt(h, 16) / 255) .map(c => c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)); return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]; } function contrastRatio(hex1, hex2) { const L1 = relativeLuminance(hex1); const L2 = relativeLuminance(hex2); const lighter = Math.max(L1, L2); const darker = Math.min(L1, L2); return (lighter + 0.05) / (darker + 0.05); } // Example contrastRatio('#6B7280', '#FFFFFF'); // 5.74:1 - PASSES AA (was a common misconception) contrastRatio('#9CA3AF', '#FFFFFF'); // 2.85:1 - FAILS AA ``` ### HSL to Hex Conversion (for CSS variable tokens) Many design systems store colors as HSL triplets (e.g., shadcn/ui, Radix): ```js function hslToHex(h, s, l) { s /= 100; l /= 100; const a = s * Math.min(l, 1 - l); const f = n => { const k = (n + h / 30) % 12; return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); }; return '#' + [f(0), f(8), f(4)] .map(x => Math.round(x * 255).toString(16).padStart(2, '0')) .join(''); } // shadcn/ui: --muted-foreground: 215.4 16.3% 46.9% hslToHex(215.4, 16.3, 46.9); // -> approximately #6B7280 ``` --- ## WCAG Contrast Thresholds Each WCAG contrast threshold, with use case, AA, AAA and notes. | Use Case | AA | AAA | Notes | |----------|-----|-----|-------| | Normal text (< 18pt / < 14pt bold) | 4.5:1 | 7:1 | Most body text | | Large text (>= 18pt / >= 14pt bold) | 3:1 | 4.5:1 | Headings, display text | | UI components (borders, icons) | 3:1 | - | Input borders, icon buttons | | Focus indicators (WCAG 2.4.13, 2.2) | 3:1 | - | Against adjacent colors | | Placeholder text | 4.5:1 | - | Counts as normal text | | Disabled state | Exempt | Exempt | Documented exemption | | Logo / brand | Exempt | Exempt | No requirement | | Decorative content | Exempt | Exempt | Must be marked decorative | --- ## Framework Token Paths - Complete Reference ### Tailwind CSS ```js // tailwind.config.js / tailwind.config.ts module.exports = { theme: { // Base colors (Tailwind default palette) colors: { // All color scales: slate, gray, zinc, neutral, stone, red, orange, amber, // yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, // purple, fuchsia, pink, rose // Each scale: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950 }, extend: { colors: { // Custom semantic colors - CHECK ALL PAIRS brand: { primary: '#...', secondary: '#...' }, background: '#...', foreground: '#...', muted: '#...', 'muted-foreground': '#...', accent: '#...', 'accent-foreground': '#...', destructive: '#...', 'destructive-foreground': '#...', card: '#...', 'card-foreground': '#...', popover: '#...', 'popover-foreground': '#...', border: '#...', // UI component - check 3:1 against background input: '#...', // UI component - check 3:1 against background ring: '#...', // Focus ring - check 3:1 against background primary: '#...', 'primary-foreground': '#...', secondary: '#...', 'secondary-foreground': '#...', }, ringColor: { DEFAULT: '...' }, // Focus state ringWidth: { DEFAULT: '2px' }, // Must be >= 2px for WCAG 2.4.13 } } } ``` ### shadcn/ui / Radix CSS Variables ```css /* globals.css - HSL triplets without hsl() wrapper */ :root { --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; --primary: 222.2 47.4% 11.2%; --primary-foreground: 210 40% 98%; --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; /* HIGH RISK - check on --background */ --accent: 210 40% 96.1%; --accent-foreground: 222.2 47.4% 11.2%; --destructive: 0 84.2% 60.2%; /* HIGH RISK - red on white */ --destructive-foreground: 210 40% 98%; --border: 214.3 31.8% 91.4%; /* UI component - check 3:1 */ --input: 214.3 31.8% 91.4%; /* UI component - check 3:1 */ --ring: 222.2 84% 4.9%; /* Focus ring - check 3:1 */ } .dark { --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; /* ... all dark mode variants */ } ``` ### Material UI (MUI) v5+ ```js // Token paths in createTheme() palette: { primary: { main: '#1976d2', // text-on-white: 4.56:1 light: '#42a5f5', // text-on-white: 2.86:1 (do not use as text color) dark: '#1565c0', // text-on-white: 5.91:1 contrastText: '#fff', // check on main }, secondary: { main: '#9c27b0', // text-on-white: 4.56:1 (barely) light: '#ba68c8', // text-on-white: 2.55:1 dark: '#7b1fa2', contrastText: '#fff', }, error: { main: '#d32f2f', // text-on-white: 5.08:1 light: '#ef5350', // text-on-white: 3.04:1 }, warning: { main: '#ed6c02', // text-on-white: 2.94:1 COMMON FAILURE light: '#ff9800', // text-on-white: 2.02:1 dark: '#e65100', // text-on-white: 3.84:1 (still fails!) contrastText: 'rgba(0, 0, 0, 0.87)', // check on warning.main }, info: { main: '#0288d1', // text-on-white: 4.54:1 (barely) light: '#03a9f4', // text-on-white: 2.88:1 }, success: { main: '#2e7d32', // text-on-white: 7.24:1 light: '#4caf50', // text-on-white: 2.52:1 }, text: { primary: 'rgba(0,0,0,0.87)', // -> ~#212121: 16.07:1 on white secondary: 'rgba(0,0,0,0.6)', // -> ~#666: 5.74:1 on white disabled: 'rgba(0,0,0,0.38)', // -> ~#9E9E9E: 2.34:1 (exempt when disabled) }, background: { paper: '#fff', default: '#fafafa' }, action: { active: 'rgba(0,0,0,0.54)', // ~4.48:1 for small icons disabled: 'rgba(0,0,0,0.26)', // exempt when disabled } } ``` ### Chakra UI v2/v3 ```js // Token paths in extendTheme() const theme = extendTheme({ colors: { // Direct palette values brand: { 50: '#f5f3ff', 500: '#7C3AED', 600: '#6D28D9', 700: '#5B21B6', 900: '#2E1065' }, gray: { 50: '#F9FAFB', 100: '#F3F4F6', 200: '#E5E7EB', 300: '#D1D5DB', 400: '#9CA3AF', // text-on-white: 2.85:1 500: '#6B7280', // text-on-white: 4.48:1 (near-miss) 600: '#4B5563', // text-on-white: 7.44:1 700: '#374151', 800: '#1F2937', 900: '#111827' }, }, semanticTokens: { colors: { 'chakra-body-text': { default: 'gray.800', _dark: 'whiteAlpha.900' }, 'chakra-body-bg': { default: 'white', _dark: 'gray.800' }, 'chakra-placeholder-color': { default: 'gray.400', _dark: 'whiteAlpha.400' }, // gray.400 on white = 2.85:1 - placeholder fails AA } }, components: { Button: { variants: { solid: (props) => ({ bg: `${props.colorScheme}.500`, // check colorScheme.500 on white color: 'white', // white on colorScheme.500 - check 3:1 }), ghost: (props) => ({ color: `${props.colorScheme}.600`, // text-on-white variant }), } } } }); ``` ### Style Dictionary (W3C Design Tokens) ```json { "color": { "text": { "primary": { "$value": "#111827", "$type": "color" }, "secondary": { "$value": "#6B7280", "$type": "color" }, // 4.48:1 on white
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기