Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Bài 17 — Multi-brand & Theming với Tokens

Product Design Essentials Bài 17/60

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn vừa xây xong một design system gọn gàng cho công ty. Mọi nút bấm, mọi tiêu đề, mọi khoảng cách đều dùng token đàng hoàng. Mọi thứ chạy mượt. Rồi một sáng thứ Hai, sếp gọi bạn vào phòng họp: "Tuần sau chúng ta ra mắt thương hiệu con thứ hai, màu tím thay vì cam, font khác, bo góc mềm hơn. Và à, khách hàng enterprise vừa ký hợp đồng white-label, họ muốn nguyên app mang màu thương hiệu của họ. Em làm được không?"

Nếu design system của bạn chỉ có một bộ token cứng nhắc, câu trả lời thành thật sẽ là: "Em phải làm lại gần như từ đầu." Còn nếu bạn đã thiết kế token với tư duy theming ngay từ đầu, câu trả lời sẽ là: "Em đổi một file token, ba mươi phút sau có bản preview cho anh xem."

Đó chính là khác biệt mà bài này dạy bạn. Ở Bài 16 chúng ta đã dựng kiến trúc token ba tầng (primitive, semantic, component). Bài 17 này lấy đúng kiến trúc đó và đẩy nó lên một cấp: làm thế nào để một bộ component duy nhất có thể "khoác" nhiều bộ áo khác nhau — nhiều thương hiệu, nhiều chế độ sáng tối, nhiều dịp lễ — mà không phải đụng vào logic hay vẽ lại UI. Đây là kỹ năng phân biệt một designer biết vẽ đẹp với một designer biết xây hệ thống vận hành ở quy mô lớn. Trong bối cảnh các startup Việt Nam ngày càng đi theo mô hình SaaS đa khách hàng và các tập đoàn lớn sở hữu nhiều thương hiệu con, đây không còn là kỹ năng "có thì tốt" mà là yêu cầu thực tế.

Khái niệm cốt lõi

Theming là gì, và tại sao token là chìa khóa

Theming nghĩa là thay đổi diện mạo (màu sắc, typography, độ bo góc, đổ bóng, khoảng cách) của toàn bộ giao diện bằng cách hoán đổi giá trị, trong khi cấu trúc và hành vi của giao diện giữ nguyên. Nói cách khác: cùng một bộ xương component, nhiều bộ da khác nhau.

Token là chìa khóa vì nó tạo ra một lớp gián tiếp (indirection). Component không bao giờ tham chiếu trực tiếp đến màu #FF6B00. Nó tham chiếu đến color.action.primary.background. Khi bạn đổi theme, bạn chỉ đổi cái mà token đó trỏ tới, còn component không hề hay biết. Đây chính là lý do tầng semantic token ở Bài 16 quan trọng đến vậy — nó là điểm "công tắc" để toàn bộ theme đổi cùng lúc.

Bốn use case kinh điển của theming

1. White-label SaaS — đổi thương hiệu theo từng khách hàng. Bạn xây một sản phẩm, bán cho nhiều doanh nghiệp, mỗi doanh nghiệp muốn app mang logo, màu, font của họ. Một nền tảng quản lý nhà hàng có thể được dùng bởi Phúc Long, Highlands và một chuỗi cà phê nhỏ ở Đà Nẵng — mỗi bên nhìn vào app đều thấy "đây là app của riêng tôi".

2. Sub-brand — công ty mẹ và các thương hiệu con. Một tập đoàn sở hữu nhiều thương hiệu chia sẻ chung nền tảng nhưng cần bản sắc riêng. Ví dụ điển hình ở Việt Nam là hệ sinh thái của một tập đoàn lớn với mảng xe, mảng bất động sản, mảng giáo dục — mỗi mảng có màu sắc riêng nhưng vẫn cảm nhận được "cùng một nhà".

3. Light/dark mode — theming thu nhỏ. Đây là dạng theming dễ thấy nhất và là bài tập tuyệt vời để hiểu nguyên lý. Sáng và tối thực chất chỉ là hai theme, khác nhau ở giá trị màu nền và màu chữ. Nếu bạn làm tốt light/dark, bạn đã nắm 80% tư duy multi-brand.

4. Theming theo mùa/dịp lễ. Tết, Giáng sinh, Black Friday — nhiều sản phẩm "khoác áo lễ" tạm thời: đổi màu accent sang đỏ vàng dịp Tết, thêm họa tiết. Nếu hệ thống token tốt, đây chỉ là một theme bật lên trong hai tuần rồi tắt đi, không cần dev sửa code.

Theme khác nhau ở đâu, giống nhau ở đâu

Điều quan trọng nhất cần hiểu: không phải mọi token đều thay đổi giữa các theme. Một design system multi-brand tốt phân biệt rõ ba nhóm:

  • Token thay đổi theo brand (brand-specific): màu thương hiệu, font chữ, độ bo góc đặc trưng, phong cách đổ bóng. Đây là "cá tính" của thương hiệu.
  • Token cố định (global/shared): thường là khoảng cách (spacing), kích thước lưới, các quy tắc về z-index, breakpoint responsive. Một nút bấm cao 44px để chạm tay thoải mái thì brand nào cũng nên giữ — đây là vấn đề trải nghiệm, không phải bản sắc.
  • Token có ràng buộc (constrained): màu có thể đổi nhưng phải đảm bảo độ tương phản đạt chuẩn WCAG. Brand được tự do chọn màu, nhưng hệ thống phải ngăn họ chọn chữ xám nhạt trên nền trắng gây mất khả năng đọc.
Hiểu sự phân biệt này giúp bạn quyết định token nào đưa vào "lớp theme" có thể hoán đổi, token nào để ở lớp nền tảng bất biến.

Cơ chế "mode" trong token

Cách hiện đại để tổ chức theming là dùng khái niệm mode (chế độ) trong cùng một bộ token. Thay vì có ba file token riêng cho ba brand, bạn có một bộ token semantic, và mỗi token có nhiều giá trị tương ứng với từng mode. Ví dụ token color.surface.background sẽ có giá trị trắng ở mode "Light", giá trị xám đen ở mode "Dark", giá trị kem nhạt ở mode "Brand-Phúc-Long". Figma gọi cơ chế này là Variables với multiple modes (chúng ta đã gặp ở Bài 12); trong code nó thường được thể hiện bằng cách đổi một thuộc tính data-theme trên thẻ gốc và để CSS variables tự cập nhật theo.

Tình huống thực tế

Tình huống 1 — White-label cho nền tảng đặt lịch spa "BeautyOS"

Một startup ở TP.HCM xây nền tảng quản lý và đặt lịch cho ngành làm đẹp, đặt tên BeautyOS. Họ bán theo mô hình SaaS cho 120 spa và thẩm mỹ viện. Năm đầu, mỗi khi một spa lớn ký hợp đồng và đòi "app mang màu thương hiệu của tôi", đội của họ phải tạo một nhánh code riêng, sửa tay hàng chục màu, mất trung bình 5 ngày làm việc cho mỗi khách. Sau 15 khách họ có 15 nhánh code, mỗi lần sửa bug phải vá 15 chỗ — một cơn ác mộng bảo trì.

Họ làm lại theo hướng token. Đội design tạo một bộ semantic token chuẩn, rồi định nghĩa một "brand pack" cho mỗi khách: chỉ gồm khoảng 12 giá trị — màu primary, màu secondary, màu accent, font tiêu đề, font nội dung, độ bo góc, và logo. Khi khách mới ký hợp đồng, một nhân viên không cần biết code điền 12 giá trị này vào một bảng cấu hình, hệ thống tự sinh ra theme. Thời gian onboarding một thương hiệu giảm từ 5 ngày xuống còn nửa ngày, và quan trọng hơn là chỉ còn một nhánh code duy nhất cho 120 khách.

Bài học: Khi bạn thiết kế cho white-label, hãy xác định "bề mặt brand tối thiểu" — tập hợp nhỏ nhất các token cần đổi để ra một thương hiệu mới. Càng nhỏ càng dễ vận hành. Nếu để khách tùy biến hàng trăm giá trị, bạn vừa tạo gánh nặng cho họ vừa tạo rủi ro vỡ giao diện cho mình.

Tình huống 2 — Tập đoàn đa thương hiệu và bài toán "cùng nhà nhưng khác mặt"

Một tập đoàn fintech giả định tên FinViet sở hữu ba sản phẩm: FinViet Pay (ví điện tử, màu xanh dương tin cậy), FinViet Invest (đầu tư, màu xanh lá tăng trưởng) và FinViet Young (sản phẩm cho Gen Z, màu tím năng động, bo góc to, font trẻ trung). Ba sản phẩm cùng đội thiết kế, cùng base component, nhưng cảm giác hoàn toàn khác nhau.

Họ cấu trúc token thành hai lớp rõ ràng. Lớp nền tảng dùng chung: spacing theo thang 4px, chiều cao nút 48px, quy tắc khoảng cách giữa các phần tử, hệ thống đổ bóng theo độ cao. Lớp brand: bảng màu, gia đình font, và radius. Khi build FinViet Young, đội chỉ kích hoạt brand pack "Young" — nút bấm vẫn cao 48px (đảm bảo trải nghiệm chạm nhất quán toàn tập đoàn), nhưng bo góc nhảy từ 8px lên 20px và màu chuyển sang tím. Người dùng cảm nhận được sự trẻ trung mà không hề biết bên dưới là cùng một bộ component với FinViet Pay nghiêm túc.

Một chi tiết tinh tế họ học được: ban đầu họ để mỗi brand tự do chọn cả spacing, kết quả là ba app có nhịp điệu khác nhau, đội QA mất nhiều thời gian, và cảm giác "cùng nhà" biến mất. Sau đó họ khóa spacing về lớp nền tảng, chỉ cho brand đổi màu/font/radius — và cảm giác hệ sinh thái quay trở lại.

Bài học: Với sub-brand, sự khác biệt nên nằm ở bản sắc (màu, font, radius), còn sự thống nhất nên nằm ở cấu trúc (spacing, kích thước, nhịp điệu). Quyết định cái gì được phép đổi quan trọng không kém việc đổi nó như thế nào.

Tình huống 3 — Theme Tết tạm thời cho một sàn TMĐT

Một sàn thương mại điện tử muốn "khoác áo Tết" trong ba tuần trước Tết Nguyên đán: nút chính chuyển từ cam sang đỏ may mắn, thêm sắc vàng kim cho các huy hiệu khuyến mãi, một vài họa tiết hoa mai ở header. Năm trước, việc này được làm bằng cách dev hardcode màu đỏ rải rác khắp nơi, đến khi hết Tết phải đi tìm gỡ từng chỗ, sót vài màn hình vẫn đỏ đến tận tháng Ba.

Năm nay đội design tạo một mode token tên "Tet" chồng lên theme mặc định. Mode này chỉ ghi đè đúng những token cần đổi: color.action.primary.background, color.accent.promo, và một token nền header. Mọi thứ khác kế thừa từ theme gốc. Khi đến ngày, đội vận hành chỉ bật cờ "theme = Tet" trên hệ thống; hết ba tuần, tắt cờ đi, mọi thứ trở về cam ngay lập tức, không sót một pixel.

Bài học: Theme theo dịp nên là một lớp "overlay" mỏng, chỉ ghi đè vài token và kế thừa phần còn lại — đừng tạo một theme đầy đủ song song. Cách này vừa nhẹ, vừa dễ bật/tắt, vừa không bỏ sót.

Hướng dẫn từng bước

Đây là quy trình bạn có thể áp dụng để chuyển một design system đơn brand thành multi-brand:

Bước 1 — Kiểm tra tầng semantic đã đủ "kín" chưa. Trước khi nghĩ đến theme thứ hai, hãy chắc chắn không còn component nào trỏ thẳng vào primitive (kiểu color.blue.500) hay giá trị thô (#1A73E8). Mọi thứ phải đi qua semantic token. Nếu còn rò rỉ, theme mới sẽ không "thấm" tới những chỗ đó. Đây là bước nền tảng, đừng bỏ qua.

Bước 2 — Phân loại token theo nhóm. Lập một bảng và xếp từng semantic token vào một trong ba cột: "đổi theo brand", "cố định toàn hệ thống", "đổi nhưng có ràng buộc". Đây là quyết định chiến lược quan trọng nhất của cả quá trình. Hãy mời thêm một kỹ sư và một người am hiểu thương hiệu cùng quyết.

Bước 3 — Định nghĩa "brand pack" — bề mặt tối thiểu. Từ nhóm "đổi theo brand", rút gọn xuống tập nhỏ nhất các giá trị một thương hiệu mới cần cung cấp. Lý tưởng là dưới 15–20 giá trị. Đây sẽ là "hợp đồng" giữa hệ thống và mỗi brand.

Bước 4 — Dựng theme mặc định bằng mode. Trong Figma, tạo một collection Variables với mode "Default". Trong code, đây là bộ giá trị CSS variable ở :root. Đảm bảo theme mặc định chạy hoàn hảo trước khi thêm theme thứ hai.

Bước 5 — Thêm theme thứ hai và kiểm thử song song. Nhân bản mode, đổi đúng các giá trị trong brand pack, rồi rà soát toàn bộ component dưới theme mới. Đây là lúc lỗi "rò rỉ" ở bước 1 lộ ra. Dùng một trang "showcase" gom tất cả component lại để soi nhanh.

Bước 6 — Cài đặt cơ chế chuyển theme. Thống nhất với engineer cách bật theme: thường là một thuộc tính data-theme trên thẻ gốc kích hoạt một bộ CSS variable tương ứng. Một dòng đổi attribute là cả app đổi theme.

Bước 7 — Kiểm tra ràng buộc tự động. Với nhóm "có ràng buộc", thiết lập kiểm tra độ tương phản cho mọi cặp màu chữ/nền trong mỗi theme. Lý tưởng là tích hợp vào quy trình để theme mới không thể "lọt" nếu vi phạm WCAG.

Lỗi thường gặp & mẹo

Lỗi: Hardcode giá trị "chỉ chỗ này thôi". Câu "chỗ này đặc biệt, để màu cứng cho nhanh" là kẻ thù số một của theming. Mỗi giá trị hardcode là một điểm sẽ không đổi khi sang theme khác, và bạn sẽ phát hiện ra nó vào đúng lúc tệ nhất — khi demo cho khách. Mẹo: định kỳ quét code/file design tìm mã màu thô và giá trị lẻ.

Lỗi: Cho brand tùy biến quá nhiều. Nghe có vẻ hào phóng khi cho khách đổi mọi thứ, nhưng càng nhiều biến số càng nhiều cách để giao diện vỡ. Mẹo: giữ brand pack nhỏ và có chủ đích; cái gì không thuộc bản sắc thương hiệu thì khóa lại.

Lỗi: Quên kiểm tra độ tương phản cho từng theme. Một cặp màu đẹp ở theme sáng có thể thành thảm họa ở theme tối hoặc theme tím. Đừng giả định — hãy đo từng theme độc lập. Đây cũng là cầu nối tới Bài 28 về accessibility.

Lỗi: Đặt tên token theo brand cụ thể. Token tên color.phuclong.green sẽ thành vô nghĩa khi áp cho khách khác. Tên semantic phải mô tả vai trò (color.action.primary), không mô tả thương hiệu hay màu cụ thể.

Mẹo: Dùng light/dark làm bài tập khởi động. Nếu nhóm bạn chưa từng làm multi-brand, hãy làm light/dark trước. Nó dùng đúng cơ chế mode, ít rủi ro hơn, và cho bạn niềm tin trước khi đụng tới brand thật.

Mẹo: Một trang showcase là vũ khí mạnh nhất. Gom mọi component và trạng thái vào một trang, rồi gạt qua lại giữa các theme. Mọi lỗi rò rỉ token sẽ hiện ra trong vài giây.

Bài tập thực hành

  • Phân loại token (30 phút): Lấy 20 semantic token bất kỳ từ một dự án bạn đang làm (hoặc tự liệt kê), xếp mỗi token vào một trong ba nhóm: đổi theo brand / cố định / có ràng buộc. Viết một câu lý giải cho mỗi quyết định khó.
  • Thiết kế brand pack (45 phút): Cho một nền tảng white-label giả định (ví dụ app giao đồ ăn cho các chuỗi nhà hàng), liệt kê tập tối thiểu các giá trị một thương hiệu mới cần cung cấp. Cố gắng giữ dưới 15 giá trị và giải thích vì sao mỗi cái cần có mặt.
  • Dựng hai theme trong Figma (60 phút): Tạo một collection Variables với hai mode. Mode 1 là brand "nghiêm túc" (xanh dương, radius 8px), mode 2 là brand "trẻ trung" (tím, radius 20px). Áp vào ít nhất một nút bấm và một thẻ card, rồi gạt qua lại để thấy cả hai cùng đổi.
  • Audit rò rỉ (30 phút): Lấy một màn hình bất kỳ, đi qua từng phần tử và tìm xem có chỗ nào đang dùng giá trị cứng thay vì token không. Ghi lại từng điểm rò rỉ — đây chính là kiểu lỗi sẽ phá theme của bạn.

Tóm tắt

Theming là khả năng cho cùng một bộ component khoác nhiều bộ áo — nhiều thương hiệu, sáng/tối, hay dịp lễ — bằng cách hoán đổi giá trị token thay vì sửa giao diện. Nền tảng của nó là tầng semantic token kín kẽ, nơi không component nào trỏ thẳng vào màu thô. Bốn use case chính là white-label SaaS, sub-brand cùng tập đoàn, light/dark mode, và theme theo mùa.

Quyết định chiến lược quan trọng nhất không phải là "đổi như thế nào" mà là "cái gì được phép đổi": token bản sắc (màu, font, radius) nên thay đổi theo brand, còn token cấu trúc (spacing, kích thước, nhịp điệu) nên cố định để giữ cảm giác thống nhất, và token màu phải có ràng buộc tương phản để đảm bảo dễ đọc. Hãy giữ "brand pack" — bề mặt tối thiểu của mỗi thương hiệu — càng nhỏ càng tốt; triển khai bằng cơ chế mode; và dùng một trang showcase cùng việc kiểm tra tương phản từng theme để bắt lỗi sớm. Làm tốt điều này, bạn biến yêu cầu "tuần sau ra thương hiệu mới" từ một dự án nhiều ngày thành một thao tác nửa buổi.