Communitygithub.com

Samueladewole/claude-skills

建立具有可及性、響應式且高效能的前端元件,遵循設計系統最佳實務、現代 CSS 及框架無關的模式。

claude-skills 是什麼?

這項技能專為前端設計師與開發人員打造,協助他們運用現代最佳實務,建構美觀、可及且高效能的使用者介面。它涵蓋元件設計與開發、設計系統實施(使用設計令牌)、響應式設計(行動優先與流暢排版)、無障礙設計(WCAG 2.1 AA 等級)、現代 CSS 技術(如 Flexbox、Grid、容器查詢)以及效能最佳化(關鍵 CSS、延遲載入、程式碼分割)。此技能提供框架無關的模式,包含 React、Vue 和 Svelte 的範例,並包含一份完整的設計令牌樣式表、可複用的元件模式(按鈕、卡片、表單輸入)以及無障礙模式(跳過連結、焦點管理、ARIA 標籤)。它支援 Claude Code、Cursor 及 Codex 等 AI 代理平台,使開發人員能持續產出符合設計系統、無障礙且高效能的前端程式碼。

相容平台✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/Samueladewole/claude-skills/tree/HEAD/frontend-designer

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

前端設計師

一套全面的技能,供前端設計師與開發人員運用現代最佳實務,建構美觀、可及且高效能的使用者介面。

這項技能的作用

幫助前端設計師/開發人員處理:

  • 元件設計與開發 - 建立可重複使用、可及的元件
  • 設計系統 - 實作令牌、模式和文件
  • 響應式設計 - 行動優先、流暢排版
  • 無障礙設計 (WCAG 2.1) - 包容性設計模式
  • 現代 CSS - Flexbox、Grid、自訂屬性
  • 效能最佳化 - 快速、高效的前端
  • 框架模式 - React、Vue、Svelte 最佳實務
  • 設計轉程式碼 - Figma 到生產工作流程

為何這項技能很重要

沒有系統性方法時:

  • 不一致的元件實作
  • 無障礙問題
  • 響應式行為不佳
  • 重複的程式碼與樣式
  • 難以維護
  • 效能問題

有了這項技能:

  • 一致且可重複使用的元件
  • 預設符合 WCAG AA 規範
  • 行動優先的響應式設計
  • 與設計系統對齊
  • 可維護的程式碼庫
  • 快速、最佳化的交付

核心原則

1. 無障礙優先

  • WCAG 2.1 AA 為最低標準
  • 語意化 HTML
  • 鍵盤導航
  • 螢幕閱讀器支援
  • 焦點管理
  • 色彩對比

2. 行動優先響應式

  • 從行動裝置開始 (320px)
  • 漸進增強
  • 流暢排版
  • 彈性佈局
  • 觸控友善的目標

3. 效能預設

  • 最小化 CSS/JS
  • 延遲載入
  • 最佳化圖片
  • 關鍵 CSS
  • Tree Shaking

4. 元件驅動

  • 原子設計方法
  • 可重複使用的元件
  • 基於 Props 的客製化
  • 組合優先於繼承

5. 與設計系統對齊

  • 設計令牌
  • 一致的間距
  • 排版比例
  • 色彩調色盤
  • 元件庫

元件模式

按鈕元件

可及、彈性的按鈕模式:

// React 範例
interface ButtonProps {
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  loading?: boolean;
  children: React.ReactNode;
  onClick?: () => void;
}

export const Button: React.FC<ButtonProps> = ({
  variant = 'primary',
  size = 'md',
  disabled = false,
  loading = false,
  children,
  onClick,
  ...props
}) => {
  return (
    <button
      className={`btn btn--${variant} btn--${size}`}
      disabled={disabled || loading}
      onClick={onClick}
      aria-busy={loading}
      {...props}
    >
      {loading ? <Spinner /> : children}
    </button>
  );
};

CSS(含設計令牌):

.btn {
  /* 基本樣式 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);

  font-family: var(--font-sans);
  font-weight: 600;
  text-decoration: none;

  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;

  transition: all 0.2s ease;

  /* 無障礙 */
  min-height: 44px; /* WCAG 觸控目標 */

  &:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
  }

  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
}

/* 變體 */
.btn--primary {
  background: var(--color-primary);
  color: var(--color-on-primary);

  &:hover:not(:disabled) {
    background: var(--color-primary-hover);
  }
}

.btn--secondary {
  background: var(--color-secondary);
  color: var(--color-on-secondary);
}

.btn--ghost {
  background: transparent;
  color: var(--color-primary);
  border: 1px solid currentColor;
}

/* 尺寸 */
.btn--sm {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
}

.btn--md {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
}

.btn--lg {
  padding: var(--space-4) var(--space-6);
  font-size: var(--text-lg);
}

卡片元件

彈性、可及的卡片:

interface CardProps {
  variant?: 'elevated' | 'outlined' | 'filled';
  padding?: 'none' | 'sm' | 'md' | 'lg';
  interactive?: boolean;
  children: React.ReactNode;
}

export const Card: React.FC<CardProps> = ({
  variant = 'elevated',
  padding = 'md',
  interactive = false,
  children,
}) => {
  const Component = interactive ? 'button' : 'div';

  return (
    <Component
      className={`
        card
        card--${variant}
        card--padding-${padding}
        ${interactive ? 'card--interactive' : ''}
      `}
      {...(interactive && { role: 'button', tabIndex: 0 })}
    >
      {children}
    </Component>
  );
};

CSS:

.card {
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.card--elevated {
  box-shadow: var(--shadow-md);
}

.card--outlined {
  border: 1px solid var(--color-border);
}

.card--filled {
  background: var(--color-surface-variant);
}

.card--interactive {
  cursor: pointer;
  transition: transform 0.2s, box-shadow 0.2s;

  &:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
  }

  &:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
  }
}

.card--padding-sm { padding: var(--space-3); }
.card--padding-md { padding: var(--space-4); }
.card--padding-lg { padding: var(--space-6); }

表單輸入元件

可及的表單輸入:

interface InputProps {
  label: string;
  error?: string;
  hint?: string;
  required?: boolean;
  type?: 'text' | 'email' | 'password' | 'number';
}

export const Input: React.FC<InputProps> = ({
  label,
  error,
  hint,
  required = false,
  type = 'text',
  ...props
}) => {
  const id = useId();
  const hintId = `${id}-hint`;
  const errorId = `${id}-error`;

  return (
    <div className="input-wrapper">
      <label htmlFor={id} className="input-label">
        {label}
        {required && <span aria-label="required">*</span>}
      </label>

      {hint && (
        <p id={hintId} className="input-hint">
          {hint}
        </p>
      )}

      <input
        id={id}
        type={type}
        className={`input ${error ? 'input--error' : ''}`}
        aria-required={required}
        aria-invalid={!!error}
        aria-describedby={error ? errorId : hint ? hintId : undefined}
        {...props}
      />

      {error && (
        <p id={errorId} className="input-error" role="alert">
          {error}
        </p>
      )}
    </div>
  );
};

設計令牌

用於設計系統的 CSS 自訂屬性:

:root {
  /* 色彩 - 主要 */
  --color-primary: #0066FF;
  --color-primary-hover: #0052CC;
  --color-on-primary: #FFFFFF;

  /* 色彩 - 表面 */
  --color-surface: #FFFFFF;
  --color-surface-variant: #F5F5F5;
  --color-on-surface: #1A1A1A;

  /* 色彩 - 邊框 */
  --color-border: #E0E0E0;
  --color-border-hover: #BDBDBD;

  /* 色彩 - 語意 */
  --color-error: #D32F2F;
  --color-success: #388E3C;
  --color-warning: #F57C00;
  --color-info: #1976D2;

  /* 間距比例 (8px 基準) */
  --space-1: 0.25rem;  /* 4px */
  --space-2: 0.5rem;   /* 8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-5: 1.5rem;   /* 24px */
  --space-6: 2rem;     /* 32px */
  --space-8: 3rem;     /* 48px */
  --space-10: 4rem;    /* 64px */

  /* 排版比例 */
  --text-xs: 0.75rem;    /* 12px */
  --text-sm: 0.875rem;   /* 14px */
  --text-base: 1rem;     /* 16px */
  --text-lg: 1.125rem;   /* 18px */
  --text-xl: 1.25rem;    /* 20px */
  --text-2xl: 1.5rem;    /* 24px */
  --text-3xl: 1.875rem;  /* 30px */
  --text-4xl: 2.25rem;   /* 36px */

  /* 字型系列 */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "SF Mono", Monaco, "Cascadia Code", monospace;

  /* 行高 */
  --leading-tight: 1.25;
  --leading-normal: 1.5;
  --leading-relaxed: 1.75;

  /* 邊框圓角 */
  --radius-sm: 0.25rem;  /* 4px */
  --radius-md: 0.5rem;   /* 8px */
  --radius-lg: 1rem;     /* 16px */
  --radius-full: 9999px;

  /* 陰影 */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
  --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);

  /* 焦點環 */
  --color-focus: #0066FF;

  /* 過渡 */
  --transition-fast: 150ms ease;
  --transition-base: 200ms ease;
  --transition-slow: 300ms ease;
}

/* 深色模式 */
@media (prefers-color-scheme: dark) {
  :root {
    --color-surface: #1A1A1A;
    --color-surface-variant: #2A2A2A;
    --color-on-surface: #FFFFFF;
    --color-border: #3A3A3A;
  }
}

響應式設計模式

行動優先斷點

/* 行動優先方法 */
.container {
  padding: var(--space-4);

  /* 平板:768px 及以上 */
  @media (min-width: 48rem) {
    padding: var(--space-6);
  }

  /* 桌上型:1024px 及以上 */
  @media (min-width: 64rem) {
    padding: var(--space-8);
    max-width: 1200px;
    margin: 0 auto;
  }
}

流暢排版

/* 響應式排版 */
h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: var(--leading-tight);
}

h2 {
  font-size: clamp(1.5rem, 4vw, 2.5rem);
}

p {
  font-size: clamp(1rem, 2vw, 1.125rem);
  line-height: var(--leading-normal);
}

格線佈局

/* 響應式格線 */
.grid {
  display: grid;
  gap: var(--space-4);

  /* 自動調整欄位 (最小 280px) */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

/* 12 欄格線系統 */
.grid-12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--space-4);
}

.col-span-4 {
  grid-column: span 4;
}

/* 行動裝置上疊加 */
@media (max-width: 48rem) {
  .col-span-4 {
    grid-column: span 12;
  }
}

無障礙模式

跳過連結

export const SkipLink = () => (
  <a href="#main-content" className="skip-link">
    跳至主要內容
  </a>
);
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: var(--color-primary);
  color: var(--color-on-primary);
  padding: var(--space-2) var(--space-4);
  text-decoration: none;
  z-index: 100;

  &:focus {
    top: 0;
  }
}

焦點管理

// 含焦點鎖定的模態框
export const Modal = ({ isOpen, onClose, children }) => {
  const modalRef = useRef(null);

  useEffect(() => {
    if (isOpen) {
      // 儲存當前聚焦的元素
      const previouslyFocused = document.activeElement;

      // 聚焦模態框內第一個可聚焦元素
      const firstFocusable = modalRef.current?.querySelector(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      );
      firstFocusable?.focus();

      // 關閉時恢復焦點
      return () => previouslyFocused?.focus();
    }
  }, [isOpen]);

  if (!isOpen) return null;

  return (
    <div
      ref={modalRef}
      role="dialog"
      aria-modal="true"
      className="modal-overlay"
    >
      <div className="modal">
        {children}
      </div>
    </div>
  );
};

ARIA 標籤

// 含可及標籤的圖示按鈕
export const IconButton = ({ icon, label, ...props }) => (
  <button
    aria-label={label}
    className="icon-button"
    {...props}
  >
    <span aria-hidden="true">{icon}</span>
  </button>
);

// 載入狀態
export const LoadingButton = ({ loading, children, ...props }) => (
  <button
    aria-busy={loading}
    aria-live="polite"
    disabled={loading}
    {...props}
  >
    {loading ? '載入中...' : children}
  </button>
);

效能最佳化

關鍵 CSS

<!-- 內嵌關鍵 CSS -->
<style>
  /* 首屏樣式 */
  body { margin: 0; font-family: var(--font-sans); }
  .header { /* 關鍵 header 樣式 */ }
  .hero { /* 關鍵 hero 樣式 */ }
</style>

<!-- 非同步載入完整樣式表 -->
<link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'">

延遲載入圖片

export const LazyImage = ({ src, alt, ...props }) => (
  <img
    src={src}
    alt={alt}
    loading="lazy"
    decoding="async"
    {...props}
  />
);

程式碼分割

// React 延遲載入
const Dashboard = lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <Dashboard />
    </Suspense>
  );
}

現代 CSS 技術

容器查詢

.card {
  container-type: inline-size;
}

.card-content {
  display: flex;
  flex-direction: column;

  /* 當容器大於 400px 時切換為橫向佈局 */
  @container (min-width: 400px) {
    flex-direction: row;
  }
}

CSS Grid 自動調整

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--space-4);
}

主題自訂屬性

/* 淺色主題 (預設) */
:root {
  --bg: #ffffff;
  --text: #000000;
}

/* 深色主題 */
[data-theme="dark"] {
  --bg: #000000;
  --text: #ffffff;
}

body {
  background: var(--bg);
  color: var(--text);
}

元件庫結構

src/
├── components/
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.css
│   │   ├── Button.test.tsx
│   │   └── Button.stories.tsx
│   ├── Card/
│   ├── Input/
│   └── index.ts
├── tokens/
│   ├── colors.css
│   ├── spacing.css
│   ├── typography.css
│   └── index.css
├── utils/
│   ├── a11y.ts
│   └── responsive.ts
└── index.ts

使用此技能

產生元件

./scripts/generate_component.sh Button

建立元件包含:

  • TypeScript/JSX 檔案
  • CSS 模組
  • 測試檔案
  • Storybook 故事
  • 無障礙檢查

設計系統設定

./scripts/setup_design_system.sh

建立:

  • 設計令牌 (CSS 自訂屬性)
  • 基本樣式
  • 元件模板
  • 文件結構

無障礙稽核

./scripts/audit_accessibility.sh

檢查:

  • 色彩對比度
  • 鍵盤導航
  • ARIA 屬性
  • 語意化 HTML
  • 焦點管理

最佳實務

元件設計

✅ 請務必:

  • 使用語意化 HTML
  • 讓元件可透過鍵盤操作
  • 提供 ARIA 標籤
  • 支援淺色與深色模式

Individual skills in this repo

This repo contains 5 individual skills — each has its own dedicated page.

Samueladewole/claude-skills

Create API handoff documentation for frontend developers. Use when backend work is complete and needs to be documented for frontend integration, or user says 'create handoff', 'document API', 'frontend handoff', or 'API documentation'.

Samueladewole/claude-skills

Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling

Samueladewole/claude-skills

Document frontend data needs for backend developers. Use when frontend needs to communicate API requirements to backend, or user says 'backend requirements', 'what data do I need', 'API requirements', or is describing data needs for a UI.

Samueladewole/claude-skills

Master Next.js 14+ App Router with Server Components, streaming, parallel routes, and advanced data fetching. Use when building Next.js applications, implementing SSR/SSG, or optimizing React Server Components.

Samueladewole/claude-skills

Analyze a short-form video (TikTok, Instagram Reel, YouTube Short, or any MP4) to extract its full transcript, understand why it performed, and generate concrete repurposing ideas. Use this skill whenever the user asks to: analyze a video, understand why something went viral, reverse-engineer a creator's content, extract a transcript from a video, figure out what makes a video perform, or get repurposing ideas from a video. Also trigger when the user says things like "why did this perform", "what's the hook here", "can I repurpose this", "analyze this TikTok/Reel", or drops a video file path or URL.

相關技能