Quản lý variables trong design system: cấu trúc ba tầng cho sản phẩm có dark mode

Mình từng mở một file design system và thấy cùng một màu xám được nhập tay ở hơn chục chỗ, mỗi chỗ lệch nhau vài mã hex. Đổi thương hiệu một lần là phải sửa từng layer. Variables trong Figma sinh ra để chấm dứt chuyện đó, nhưng chỉ khi bạn tổ chức chúng có chủ đích. Bài này là cách mình dựng và quản lý variables cho một design system của sản phẩm di động có dark mode, kèm những quy ước mình thấy đáng giữ.

Bắt đầu từ cấu trúc file, không phải từ màu
Trước khi tạo biến nào, mình sắp xếp file. Các page nền tảng đứng đầu: Color, Typography, Spacing, Corner Radius, Shadows, Backdrop Blur, cộng thêm Anatomy và Design annotations. Sau đó mới đến Core Components, chia nhóm bằng những page phân cách để thanh Pages dễ quét.
Thứ tự này không chỉ để cho đẹp. Component phụ thuộc vào foundations, nên đặt foundations lên trước nhắc cả team rằng muốn sửa component thì nhìn lên trên xem token đã đủ chưa.

Tầng 1: Primitives, màu thô và không mang ý nghĩa
Collection đầu tiên chỉ chứa giá trị thô. Mỗi hue có một thang từ 100 đến 900, trong đó 500 là màu gốc. Riêng Grey có thêm 0, 850 và 950 vì dark mode cần nhiều bậc tối hơn. Collection này chỉ có một mode, và có một quy tắc: designer không bao giờ gắn primitives trực tiếp vào component.
Tên kiểu color/Primary/500 cho biết nó là màu gì, nhưng không cho biết dùng vào đâu. Chuyện “dùng vào đâu” thuộc về tầng sau.

Tầng 2: Semantic tokens, đặt tên theo vai trò
Đây là tầng quan trọng nhất. Mỗi token mô tả một vai trò: bg-surface, text-secondary, icon-disabled, stroke-brand-primary. Collection này có hai mode là Light và Dark, và mỗi mode trỏ về một primitive khác nhau.
Vài điều mình thấy hay khi làm dark mode:
- Nền chồng lớp càng nổi càng sáng. Canvas dùng Grey/950, container dùng Grey/900, surface dùng Grey/850, surface phụ dùng Grey/800.
- Các nền nhạt kiểu
subtlekhông cần màu mới. Ở dark mode mình dùng chính màu gốc với độ trong suốt khoảng 15 đến 20 phần trăm. - Màu trạng thái đậm hơn một bậc: ví dụ Error dùng Red/500 ở Light và Red/600 ở Dark để không chói trên nền tối.
Nhờ vậy một button chỉ cần gắn Colors/Main/Primary/solid. Chuyển mode của layer từ Light sang Dark, mọi thứ tự đổi theo.

Mỗi collection một việc
Mình tách variables thành nhiều collection thay vì gom hết vào một. Mỗi collection chứa đúng một loại giá trị: màu thô, màu theme, typography, spacing, stroke, radius, icon size, định dạng ngày giờ, định dạng dữ liệu và kiểu tiêu đề. Cách này có ba lợi ích: dễ tìm, dễ phân quyền sửa và dễ publish từng phần.
Ba quy ước nhỏ giúp bảng Variables gọn gàng:
- Đánh số 01 đến 10 ở đầu tên để Figma tự xếp đúng thứ tự.
- Collection bắt đầu bằng dấu gạch dưới là bộ nội bộ, không dành cho người dùng thư viện chọn.
- Đặt tên theo vai trò (
text-secondary), không theo màu (grey-600). Khi màu đổi, tên vẫn đúng.

Thang số cũng là variables
Không chỉ màu. Spacing, corner radius, stroke weight và icon size đều là biến kiểu Number. Spacing có 18 bước từ 0 đến 256, radius có 8 bước đến 999 cho hình tròn, stroke có 3 bước, icon size có 13 bước từ 10 đến 128.
Lợi ích lớn nhất là kỷ luật: designer chọn từ thang có sẵn thay vì gõ số lẻ như 13 hay 22. Muốn đổi cảm giác cả sản phẩm, chẳng hạn bo góc mềm hơn, bạn đổi giá trị của vài biến radius thay vì sửa từng layer.

Typography: size và line-height đi thành cặp
Collection typography có 36 biến: hai biến font family (heading và body), bốn biến font weight, và mỗi vai trò chữ có một cặp font size và line-height. Text style trong Figma chỉ việc gắn vào các biến này. Khi cần chỉnh thang chữ, bạn sửa ở một nơi và mọi text style cập nhật theo.

Dùng mode để đổi cả bộ kiểu chữ
Mình thích nhất collection “Title Type”. Nó có bốn mode (32, 24, 20, 16), mỗi mode trỏ tới một cỡ chữ tiêu đề, line-height, letter-spacing và cỡ chữ phụ tương ứng. Một component tiêu đề duy nhất, đổi mode là đổi cả bộ. Không cần tạo bốn biến thể và cũng không phải nhớ chỉnh letter-spacing bằng tay.

Biến String cho dữ liệu hiển thị
Variables có bốn kiểu: Color, Number, String và Boolean. Mình tận dụng cả String. Một collection lưu chuỗi mẫu cho các định dạng dữ liệu như số điện thoại hoặc email, với ba mode: hiện đầy đủ và hai kiểu che. Một collection khác lưu định dạng ngày giờ theo hai locale. Mock-up nào cũng lấy dữ liệu mẫu từ đây, nên bản thiết kế và bản thật cùng một quy ước và không còn cảnh mỗi màn hình một kiểu ngày.

Shadow và blur thì dùng style
Variables chưa lưu được hiệu ứng, nên bóng đổ và blur vẫn nằm ở Effect styles. Mình đặt tên chúng theo cùng một thang xs, sm, md, lg, xl để dễ nhớ như các thang còn lại. Bóng đổ trong hệ thống này rất nhẹ, độ đậm chỉ từ 3 đến 9 phần trăm.

Checklist quản lý variables
Sau khi dựng xong, phần khó là giữ cho nó không hỏng theo thời gian. Mình dùng danh sách này:
- Không gắn primitives vào component. Luôn đi qua semantic token.
- Đặt scope cho từng biến. Biến nền chỉ nên hiện khi chọn fill, biến spacing chỉ hiện ở gap và padding. Danh sách chọn ngắn lại thấy rõ.
- Đổi tên thay vì xóa. Figma gắn biến theo ID nên đổi tên không làm đứt liên kết, còn xóa biến đang dùng thì có.
- Kiểm tra cả hai mode mỗi khi thêm token. Token mới mà thiếu giá trị Dark là lỗi dễ lọt nhất.
- Quét màu gắn tay. Chọn cả frame, mở Selection colors, thấy màu nào chưa gắn biến thì thay bằng token.
- Ghi lại thay đổi. Mỗi lần publish library, viết vài dòng ghi chú để team biết vừa đổi gì.
- Giữ chuỗi tham chiếu ngắn. Primitive, semantic, rồi dừng. Càng nhiều tầng trung gian càng khó truy ngược.
Kết
Variables không làm design system tốt lên một mình. Cái tạo ra khác biệt là quy ước: tầng nào chứa gì, đặt tên ra sao và ai được sửa. Nếu bạn đang bắt đầu, hãy làm ba việc trước: tách primitives khỏi semantic, đặt tên theo vai trò, và dựng Light và Dark ngay từ đầu. Phần còn lại có thể thêm dần.
Nếu bạn đang dựng design system và muốn trao đổi, cứ nhắn mình qua mục liên hệ nhe!