Color and surfaces have two distinct responsibilities in UI design:
- Color communicates state, intent, and semantic meaning (such as destructive actions, success states, or active focus).
- Surfaces establish spatial elevation and stacking order (where an element sits in the layout hierarchy).
A component should define its surface elevation based on its nesting context rather than relying on arbitrary fills that break when switching between light and dark themes.
1. Surface Levels across Themes
A component that draws its own surface on the page canvas must pick a true elevation level (bg-card with border-border), not a fill.
- ❌ The Error: Borrowing
bg-mutedas a container surface. In light mode,muted(0.97) is darker than the page (1.0), so the card reads as recessed into the canvas. In dark mode,muted(0.269) is brighter than the page (0.145), making it float forward. A fill has no stable elevation across themes. - ✅ The Fix: Use
bg-cardwithborder-border. A card maintains consistent elevation in both light and dark modes without inverting perceived depth.
import { DesignCase } from "@/components/design-case";
import { cn } from "@/lib/utils";
The 3-Tier Surface Scale
Every container on screen should pick from three canonical surface levels:
| Elevation Level | Semantic Token | Intended Usage |
|---|---|---|
| Page Base | bg-background | The root page canvas |
| In-place Surface | bg-card with border-border | Cards, tables, sidebars, content modules |
| Floating Surface | bg-popover with shadow | Dropdowns, menus, tooltips, dialogs |
2. Action Hierarchy and Visual Salience
A common temptation when styling action bars or modal footers is giving every button high-contrast visual weight.
- ❌ The Error: Styling every action button with a primary solid fill (
bg-primary). When every action shouts at equal volume, the user experiences decision paralysis and must read every single label to find the intended path. - ✅ The Fix: Strictly apply the Single Primary Action rule. Reserve
bg-primaryfor the single most critical or forward-progressing step. Downgrade supporting actions tooutline,ghost, orsecondary.
import { DesignCase } from "@/components/design-case";
const ACTIONS = ["Publish", "Preview", "Duplicate", "Archive"];💡 Accessibility Note: Never rely on color alone to convey state or danger. Always accompany color cues with descriptive text, icons, or standard ARIA roles so interfaces remain clear under grayscale, high-contrast, or forced-color modes.
3. Color Proportion: The 60-30-10 Rule
A common temptation when styling promotion or feature cards is painting large structural areas with the primary brand color to make the block feel "important".
- ❌ The Error: Flooding the header with a solid primary banner (
bg-primary). A decorative banner consumes ~40% of the card's surface. Because saturated color is the strongest visual attractor, the non-interactive header overpowers the actual CTA button below. When accent color is everywhere, it ceases to function as a focal cue. - ✅ The Fix: Strictly apply the 60-30-10 Rule (6-3-1 原则) to allocate visual real estate:
- 60% Dominant Base: A clean, unified neutral canvas (
bg-card) provides negative space and reading clarity. - 30% Structural Secondary: Content hierarchy is established purely through typography and subtle dividers (
text-muted-foreground,border-border), keeping the body calm. - 10% Targeted Accent: The primary color is held strictly in reserve for the interactive CTA button (
bg-primary), giving the user an instant, unmistakable focal anchor.
- 60% Dominant Base: A clean, unified neutral canvas (
Unlimited background tools and deep multi-step reasoning loops.
Unlimited background tools and deep multi-step reasoning loops.
import { Sparkles } from "lucide-react";
import { DesignCase } from "@/components/design-case";The 60-30-10 Allocation Table
| Visual Role | Target Area | Semantic Tokens | Interface Responsibility |
|---|---|---|---|
| Dominant Base | ~60% | bg-card, bg-background | Negative space, reading canvas, visual calm |
| Structural Secondary | ~30% | border-border, text-muted-foreground, bg-muted | Container boundaries, metadata labels, divider rules |
| Targeted Accent | ~10% | bg-primary, text-primary-foreground | Primary CTA button, interactive focal point |
Rules and Boundaries
- Semantic Tokens Only: Always use semantic design tokens like
bg-card,text-muted-foreground, andborder-border. Avoid hardcoded palette values likebg-zinc-800or#1c1c1c, which break theme customization and dark mode. - When Literal Colors Are Valid: Literal color values (e.g.
rgba(0,0,0,0.5)) are only appropriate when measuring against user-uploaded content (like image scrims), SVG mask stops, or shadows over photography.