CSS Custom Properties Complete Guide - Master CSS Variables Like a Pro
Learn CSS Custom Properties (CSS Variables) from scratch. Discover how to create reusable, maintainable styles with variables, theming, and dynamic styling techniques.
Bạn có bao giờ tự hỏi làm thế nào các trang web lớn như Twitter, GitHub hay Airbnb quản lý hàng trăm màu sắc, khoảng cách và kích thước font một cách nhất quán? Bí mật nằm ở CSS Custom Properties — còn được gọi là CSS Variables.

Nếu bạn vẫn đang copy-paste cùng một giá trị màu sắc hoặc khoảng cách vào nhiều nơi trong file CSS, thì bài viết này sẽ thay đổi hoàn toàn cách bạn viết CSS. Hãy tưởng tượng việc bạn có thể thay đổi toàn bộ giao diện website chỉ bằng cách chỉnh sửa một dòng code. Đó chính là sức mạnh của CSS Custom Properties.
CSS Custom Properties là gì?
CSS Custom Properties (thuộc tính tùy chỉnh CSS) cho phép bạn lưu trữ các giá trị cụ thể để tái sử dụng khắp tài liệu của mình. Tương tự như biến trong lập trình, nhưng áp dụng cho CSS.
Cú pháp cực kỳ đơn giản:
/* Định nghĩa biến */
--primary-color: #3498db;
--spacing-unit: 8px;
--font-size-base: 16px;
/* Sử dụng biến */
.button {
background-color: var(--primary-color);
padding: var(--spacing-unit);
font-size: calc(var(--font-size-base) * 1.25);
}
Điểm khác biệt quan trọng: tên biến phải bắt đầu bằng hai dấu gạch ngang (--), và để sử dụng, bạn cần hàm var().
Tại sao nên dùng CSS Custom Properties?
1. Dễ dàng bảo trì
Thay vì tìm kiếm và thay đổi cùng một giá trị ở 50 nơi khác nhau, bạn chỉ cần sửa ở một chỗ:
/* Trước đây — phải sửa ở 50 nơi */
.header { background: #3498db; }
.footer { background: #3498db; }
.sidebar { background: #3498db; }
.card { border-color: #3498db; }
/* ... và 46 nơi nữa ... */
/* Với CSS Variables — chỉ sửa 1 nơi */
:root {
--primary-color: #3498db;
}
2. Hỗ trợ Dark Mode dễ dàng
Đây là một trong những use-case phổ biến nhất:
:root {
--bg-color: #ffffff;
--text-color: #333333;
--card-bg: #f5f5f5;
}
[data-theme="dark"] {
--bg-color: #1a1a2e;
--text-color: #e0e0e0;
--card-bg: #16213e;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
}
.card {
background-color: var(--card-bg);
}
Chỉ cần thêm data-theme="dark" vào thẻ <html>, toàn bộ giao diện sẽ chuyển sang dark mode!
3. Tính kế thừa và phạm vi (Scope)
CSS Variables hoạt động theo nguyên tắc scope giống như JavaScript:
/* Biến toàn cục — có thể truy cập từ mọi nơi */
:root {
--primary-color: #3498db;
}
/* Override trong component cụ thể */
.sidebar {
--primary-color: #e74c3c;
}
.sidebar .button {
/* Sử dụng --primary-color = #e74c3c (từ .sidebar) */
background-color: var(--primary-color);
}
.main-content .button {
/* Sử dụng --primary-color = #3498db (từ :root) */
background-color: var(--primary-color);
}
4. Tích hợp với JavaScript
Bạn có thể đọc và thay đổi CSS Variables trực tiếp từ JavaScript:
// Đọc giá trị
const primaryColor = getComputedStyle(document.documentElement)
.getPropertyValue('--primary-color')
.trim();
// Thay đổi giá trị
document.documentElement.style.setProperty('--primary-color', '#e74c3c');
// Xóa biến
document.documentElement.style.removeProperty('--primary-color');
Điều này mở ra khả năng tạo các hệ thống design động, theme switcher, hoặc thậm chí là công cụ drag-and-drop customization.
Cú pháp chi tiết
Khai báo biến
Biến được khai báo bên trong một selector (thường là :root):
:root {
/* Màu sắc */
--color-primary: #3498db;
--color-secondary: #2ecc71;
--color-danger: #e74c3c;
/* Khoảng cách */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 32px;
--space-2xl: 48px;
/* Typography */
--font-family-base: 'Inter', sans-serif;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.25rem;
--font-size-xl: 1.5rem;
/* Border radius */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
--radius-full: 9999px;
/* Shadows */
--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);
}
Sử dụng biến với var()
.card {
background-color: var(--color-primary);
padding: var(--space-lg);
border-radius: var(--radius-md);
box-shadow: var(--shadow-md);
font-family: var(--font-family-base);
}
Fallback values
Nếu biến không được định nghĩa, bạn có thể cung cấp giá trị mặc định:
.button {
/* Nếu --btn-color không tồn tại, dùng #3498db */
background-color: var(--btn-color, #3498db);
/* Có thể lồng var() — fallback cũng là một var() */
color: var(--btn-text-color, var(--text-color, white));
}
Kết hợp với calc()
CSS Variables hoạt động tuyệt vời với calc() để tính toán động:
.container {
--base-spacing: 16px;
padding: calc(var(--base-spacing) * 2);
gap: calc(var(--base-spacing) * 1.5);
}
h1 {
--font-scale: 2.5;
font-size: calc(var(--font-size-base) * var(--font-scale));
}
Thực hành: Xây dựng Design System với CSS Variables
Hãy cùng xây dựng một design system nhỏ hoàn chỉnh:
Bước 1: Định nghĩa tokens
:root {
/* Colors */
--color-brand: #6366f1;
--color-brand-hover: #4f46e5;
--color-brand-light: #e0e7ff;
--color-surface: #ffffff;
--color-surface-alt: #f8fafc;
--color-border: #e2e8f0;
--color-text: #1e293b;
--color-text-muted: #64748b;
--color-text-inverse: #ffffff;
/* Spacing scale */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
/* Typography */
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'Fira Code', monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
--text-4xl: 2.25rem;
/* Borders */
--radius-sm: 0.25rem;
--radius-md: 0.375rem;
--radius-lg: 0.5rem;
--radius-xl: 0.75rem;
--radius-full: 9999px;
/* Shadows */
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04);
/* Transitions */
--transition-fast: 150ms ease;
--transition-normal: 250ms ease;
--transition-slow: 350ms ease;
}
Bước 2: Tạo components sử dụng tokens
/* Button */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--space-2);
padding: var(--space-2) var(--space-4);
font-family: var(--font-sans);
font-size: var(--text-sm);
font-weight: 600;
line-height: 1;
border: none;
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--transition-fast);
}
.btn-primary {
background-color: var(--color-brand);
color: var(--color-text-inverse);
}
.btn-primary:hover {
background-color: var(--color-brand-hover);
box-shadow: var(--shadow-md);
transform: translateY(-1px);
}
.btn-secondary {
background-color: var(--color-surface-alt);
color: var(--color-text);
border: 1px solid var(--color-border);
}
.btn-secondary:hover {
background-color: var(--color-border);
}
/* Card */
.card {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-6);
box-shadow: var(--shadow-sm);
transition: box-shadow var(--transition-normal);
}
.card:hover {
box-shadow: var(--shadow-lg);
}
.card-header {
margin-bottom: var(--space-4);
}
.card-title {
font-size: var(--text-xl);
font-weight: 700;
color: var(--color-text);
margin: 0;
}
.card-body {
font-size: var(--text-base);
color: var(--color-text-muted);
line-height: 1.6;
}
/* Input */
.input {
width: 100%;
padding: var(--space-2) var(--space-3);
font-family: var(--font-sans);
font-size: var(--text-base);
color: var(--color-text);
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.input:focus {
outline: none;
border-color: var(--color-brand);
box-shadow: 0 0 0 3px var(--color-brand-light);
}
.input::placeholder {
color: var(--color-text-muted);
}
Bước 3: Tạo dark mode
[data-theme="dark"] {
--color-surface: #0f172a;
--color-surface-alt: #1e293b;
--color-border: #334155;
--color-text: #f1f5f9;
--color-text-muted: #94a3b8;
--color-text-inverse: #0f172a;
--color-brand-light: #312e81;
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.5);
}
Mẹo nâng cao
Dynamic theming với JavaScript
// Theme Switcher
const themes = ['light', 'dark', 'midnight'];
let currentTheme = 0;
function toggleTheme() {
currentTheme = (currentTheme + 1) % themes.length;
document.documentElement.setAttribute('data-theme', themes[currentTheme]);
localStorage.setItem('theme', themes[currentTheme]);
}
// Restore saved theme
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
document.documentElement.setAttribute('data-theme', savedTheme);
}
Responsive spacing
:root {
--space-responsive: var(--space-4);
}
@media (min-width: 768px) {
:root {
--space-responsive: var(--space-6);
}
}
.section {
padding: var(--space-responsive);
}
Animation với CSS Variables
.spinner {
--spinner-size: 40px;
--spinner-color: var(--color-brand);
width: var(--spinner-size);
height: var(--spinner-size);
border: 3px solid var(--color-border);
border-top-color: var(--spinner-color);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
Browser Support
CSS Custom Properties được hỗ trợ bởi tất cả các trình duyệt hiện đại:
| Trình duyệt | Phiên bản hỗ trợ |
|---|---|
| Chrome | 49+ |
| Firefox | 31+ |
| Safari | 9.1+ |
| Edge | 15+ |
| Opera | 36+ |
| Samsung Internet | 5.0+ |
Với hơn 95% người dùng web hiện nay sử dụng trình duyệt hỗ trợ CSS Variables, bạn hoàn toàn có thể yên tâm sử dụng trong dự án thực tế.
Nếu cần hỗ trợ trình duyệt cũ, bạn có thể dùng PostCSS với plugin postcss-custom-properties để transpile biến thành giá trị cụ thể.
Tổng kết
CSS Custom Properties là một trong những tính năng mạnh mẽ nhất của CSS hiện đại. Chúng giúp:
- ✅ Giảm thiểu code trùng lặp — định nghĩa một lần, sử dụng vô hạn
- ✅ Dễ dàng bảo trì — thay đổi một nơi, cập nhật toàn bộ
- ✅ Hỗ trợ theming linh hoạt — light/dark mode, multi-theme
- ✅ Tích hợp JavaScript mượt mà — thay đổi động tại runtime
- ✅ Tương thích tốt — supported bởi mọi trình duyệt hiện đại
Hãy bắt đầu áp dụng CSS Variables ngay hôm nay. Bạn sẽ ngạc nhiên trước sự sạch sẽ và hiệu quả của code sau khi refactor!
Bạn đã sử dụng CSS Custom Properties trong dự án nào chưa? Chia sẻ trải nghiệm của bạn dưới phần bình luận nhé!