Communitygithub.com

Samueladewole/claude-skills

构建可访问、响应式且高性能的前端组件,遵循设计系统最佳实践、现代CSS和框架无关的模式。

claude-skills 是什么?

该技能是为前端设计师和开发者打造的一套综合性指南,专注于构建美观、可访问且高性能的用户界面。它提供了从组件设计、设计系统实施到响应式布局、无障碍性(WCAG 2.1)和性能优化的完整工作流程。技能涵盖了React、Vue、Svelte等主流框架的最佳实践,并提供了设计到代码的转换方法,例如从Figma到生产环境的流程。通过遵循该技能,用户可以确保其代码库的一致性、可维护性,并默认符合WCAG AA标准。该技能适用于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 example
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 { /* 关键头部样式 */ }
  .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.

相关技能