Thời lượng: 1 tuần
Level: Beginner
Yêu cầu: Modules 1-2 hoàn thành
Tổng quan Module
Module này dạy bạn cách thiết kế color system chuyên nghiệp với khả năng theming. Bạn sẽ học cách tạo color palette, semantic tokens, và implement dark mode.
Kết quả học tập
Sau module này, bạn sẽ:
- Thiết kế color palette cân đối
- Tạo semantic color tokens
- Implement light/dark mode switching
- Đảm bảo accessibility với color contrast
Bài 3.1: Thiết kế Color Palette
Lý thuyết
Color Scale:
Một color scale tốt cần 9-11 shades từ sáng nhất đến tối nhất:
/* Gray scale (9 shades) */
--gray-50: #F9FAFB; /* Lightest - backgrounds */
--gray-100: #F3F4F6;
--gray-200: #E5E7EB;
--gray-300: #D1D5DB; /* Borders */
--gray-400: #9CA3AF;
--gray-500: #6B7280; /* Placeholder text */
--gray-600: #4B5563; /* Secondary text */
--gray-700: #374151;
--gray-800: #1F2937; /* Primary text */
--gray-900: #111827; /* Darkest - headings */
/* Brand color (Blue) */
--blue-50: #EFF6FF;
--blue-100: #DBEAFE;
--blue-200: #BFDBFE;
--blue-300: #93C5FD;
--blue-400: #60A5FA;
--blue-500: #3B82F6; /* Base brand color */
--blue-600: #2563EB; /* Hover state */
--blue-700: #1D4ED8;
--blue-800: #1E40AF;
--blue-900: #1E3A8A;Quy tắc chọn màu:
- Base (500): Màu chính, dễ nhìn
- Hover (600): Tối hơn 10-15%
- Active (700): Tối hơn 20-25%
- Light (100-200): Cho backgrounds
- Dark (800-900): Cho text on light bg
Nguyên tắc then chốt
"Palette tốt = easy to use. Nếu designer phải suy nghĩ lâu để chọn shade 300 hay 400, palette đã thất bại."
Thực hành
Bài tập: Tạo color palette cho brand
Steps:
- Chọn Base Color (500):
--primary-500: #3B82F6; /* Your brand color */- Generate Scale (dùng tool):
- Test Contrast (WCAG AA):
/* Text on background phải đạt tỷ lệ 4.5:1 */
--text-on-primary: white; /* Check contrast với --primary-500 */- Create Semantic Tokens:
:root {
/* Brand */
--color-primary: var(--blue-500);
--color-primary-hover: var(--blue-600);
/* Status */
--color-success: var(--green-500);
--color-warning: var(--yellow-500);
--color-danger: var(--red-500);
--color-info: var(--blue-500);
/* Neutral */
--color-text-primary: var(--gray-900);
--color-text-secondary: var(--gray-600);
--color-text-tertiary: var(--gray-500);
--color-text-disabled: var(--gray-400);
--color-bg-primary: white;
--color-bg-secondary: var(--gray-50);
--color-bg-tertiary: var(--gray-100);
--color-border: var(--gray-300);
--color-border-hover: var(--gray-400);
}Nhiệm vụ:
- Generate 3 color scales: Gray, Brand, Accent
- Define semantic tokens
- Test contrast ratios (4.5:1 for text)
- Document usage guidelines
Câu hỏi thảo luận
- Palette Size: 9 shades đủ hay cần 11? Trade-offs?
- Naming:
--blue-500vs--primaryvs--brand-blue? - Accessibility: Làm sao đảm bảo mọi color combo đều WCAG AA?
Bài 3.2: Semantic Color Tokens
Lý thuyết
3 Layers của Color Tokens:
Layer 1: Primitive (Raw values)
--blue-500: #3B82F6;
--red-500: #EF4444;Layer 2: Semantic (Meaning-based)
--color-primary: var(--blue-500);
--color-danger: var(--red-500);Layer 3: Component (Specific usage)
--button-bg-primary: var(--color-primary);
--alert-bg-danger: var(--red-50);
--alert-text-danger: var(--red-700);Tại sao cần Semantic Tokens?
- Theming: Swap light/dark mode
- Rebranding: Change
--color-primary→ entire site updates - Consistency: Components dùng
--color-primary, không phải--blue-500
Nguyên tắc then chốt
"Components KHÔNG BAO GIỜ reference primitive tokens trực tiếp. Luôn qua semantic layer."
Thực hành
Bài tập: Thiết kế semantic token structure
Text Colors:
:root {
/* Primary text - for headings, important content */
--color-text-primary: var(--gray-900);
/* Secondary text - for descriptions, meta info */
--color-text-secondary: var(--gray-600);
/* Tertiary text - for labels, captions */
--color-text-tertiary: var(--gray-500);
/* Disabled text */
--color-text-disabled: var(--gray-400);
/* Inverted text (on dark backgrounds) */
--color-text-inverse: white;
/* Text on primary button */
--color-text-on-primary: white;
}Background Colors:
:root {
/* Canvas - main page background */
--color-bg-canvas: white;
/* Primary - cards, panels */
--color-bg-primary: white;
/* Secondary - hover states, subtle backgrounds */
--color-bg-secondary: var(--gray-50);
/* Tertiary - nested backgrounds */
--color-bg-tertiary: var(--gray-100);
/* Overlay - modal backdrops */
--color-bg-overlay: rgba(0, 0, 0, 0.5);
}Interactive Colors:
:root {
/* Links */
--color-link: var(--blue-600);
--color-link-hover: var(--blue-700);
--color-link-visited: var(--purple-600);
/* Focus ring */
--color-focus: var(--blue-500);
/* Selection */
--color-selection-bg: var(--blue-100);
--color-selection-text: var(--blue-900);
}Nhiệm vụ:
- Define 20+ semantic color tokens
- Group by category: text, bg, border, interactive
- Document when to use each token
- Create example components using tokens
Câu hỏi thảo luận
- Granularity: Có cần
--color-text-linkriêng hay dùng--color-primary? - Naming:
--color-bg-primaryvs--bg-color-primaryvs--primary-bg-color? - Component Tokens: Khi nào tạo token riêng cho component (vd:
--button-bg-primary)?
Bài 3.3: Dark Mode Implementation
Lý thuyết
Dark Mode Strategy:
Option 1: CSS Variables (Recommended)
/* Light mode (default) */
:root {
--color-text-primary: var(--gray-900);
--color-bg-primary: white;
}
/* Dark mode */
[data-theme="dark"] {
--color-text-primary: var(--gray-50);
--color-bg-primary: var(--gray-900);
}Option 2: Media Query
:root {
--color-text-primary: var(--gray-900);
}
@media (prefers-color-scheme: dark) {
:root {
--color-text-primary: var(--gray-50);
}
}Option 3: Class-based
.light {
--color-text-primary: var(--gray-900);
}
.dark {
--color-text-primary: var(--gray-50);
}Nguyên tắc then chốt
"Dark mode không phải 'invert colors'. Phải thiết kế lại cho readable, không chói mắt."
Thực hành
Bài tập: Implement dark mode toggle
1. Setup Tokens:
:root {
/* Light mode */
--color-text-primary: var(--gray-900);
--color-text-secondary: var(--gray-600);
--color-bg-primary: white;
--color-bg-secondary: var(--gray-50);
--color-border: var(--gray-300);
}
[data-theme="dark"] {
/* Dark mode - adjust for readability */
--color-text-primary: var(--gray-50);
--color-text-secondary: var(--gray-400);
--color-bg-primary: var(--gray-900);
--color-bg-secondary: var(--gray-800);
--color-border: var(--gray-700);
/* Brand colors may need adjustment */
--color-primary: var(--blue-400); /* Lighter for dark bg */
}2. React Toggle Component:
'use client';
import { useEffect, useState } from 'react';
import { Moon, Sun } from 'lucide-react';
export function ThemeToggle() {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
useEffect(() => {
// Load from localStorage
const saved = localStorage.getItem('theme') as 'light' | 'dark' | null;
const preferred = saved || (
window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
);
setTheme(preferred);
document.documentElement.setAttribute('data-theme', preferred);
}, []);
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
localStorage.setItem('theme', newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
};
return (
<button
onClick={toggleTheme}
className="theme-toggle"
aria-label={`Switch to ${theme === 'light' ? 'dark' : 'light'} mode`}
>
{theme === 'light' ? <Moon size={20} /> : <Sun size={20} />}
</button>
);
}3. Dark Mode Best Practices:
- Reduce Contrast: Dark bg không nên pure black (#000), dùng #111827
- Adjust Colors: Primary colors có thể cần lighter shade trong dark mode
- Test Readability: WCAG contrast vẫn phải đạt trong dark mode
- Persist Choice: Save preference to localStorage
- Respect System: Default to
prefers-color-scheme
Nhiệm vụ:
- Implement theme toggle
- Define dark mode token values
- Test contrast ratios in both modes
- Add smooth transitions
Câu hỏi thảo luận
- Default: Default light hay dark? Hay follows system?
- Images: Làm sao handle images trong dark mode? Invert? Replace?
- Shadows: Shadows trong dark mode có cần adjust không?
Tổng kết Module
Bạn đã học:
- Thiết kế color palette với 9-11 shades
- Tạo semantic color tokens (text, bg, border, interactive)
- Implement dark mode với CSS variables
Bước tiếp theo
Module 4 sẽ dạy về Component Architecture - thiết kế API, composition patterns, và compound components.