Đang tải...

Ếch Trendy

Cùng chú ếch nhỏ khám phá thế giới Web đầy biến động. Cập nhật trending nhanh như cách ếch đớp mồi! ⌨️🌿


0

Tailwind CSS 4: OKLCH Colors, Arbitrary Values Và Workflow Thiết Kế Nhanh Hơn

Ếch Trendy
Ếch Trendy

5 tháng trước · 7 phút đọc

Tailwind CSS 4 thay đổi gì so với trước?

Mình nhớ hồi dùng Tailwind v3, mỗi lần cần màu brand riêng là phải mở tailwind.config.js, thêm hex vào extend.colors, save, rồi mới quay lại component dùng. Không nhiều bước, nhưng đủ để phá vỡ flow.

Tailwind CSS 4 giải quyết điều này theo hướng khác: thay vì config file JavaScript, giờ bạn khai báo design token ngay trong CSS qua @theme. Toàn bộ hệ thống màu mặc định cũng được viết lại bằng OKLCH thay vì hex hay HSL cũ.

344462 Từ config JS sang CSS-native - ít bước chuyển ngữ cảnh hơn

Ngoài màu sắc, v4 còn bổ sung palette mới như mauve, olive, mist, taupe - tất cả đều được định nghĩa trong OKLCH. Đây không phải thay đổi cosmetic; nó ảnh hưởng trực tiếp đến cách bạn xây design system và tốc độ iteration.

Arbitrary values vẫn còn đó, và workflow tổng thể vẫn là utility-first. Nhưng cách tổ chức theme đã CSS-native hơn nhiều so với trước.


OKLCH là gì và tại sao Tailwind chọn nó?

OKLCH là không gian màu (color space) được thiết kế để perceptually uniform - tức là khi bạn thay đổi giá trị lightness hay chroma theo từng bước đều, mắt người cũng cảm nhận sự thay đổi đó đều nhau. Với RGB hay HSL, điều này không đảm bảo.

OKLCH có 4 thành phần:

  • L (lightness): độ sáng, từ 0 (đen) đến 1 (trắng)
  • C (chroma): độ bão hòa màu
  • H (hue): góc màu sắc (0-360 độ)
  • Alpha (tùy chọn): độ trong suốt

344463 L, C, H - 3 trục đủ để diễn đạt mọi màu một cách có hệ thống

Vấn đề với HSL? Màu hsl(200, 100%, 50%) và hsl(60, 100%, 50%) có cùng lightness trên giấy, nhưng nhìn thực tế vàng trông sáng hơn nhiều. OKLCH không bị lỗi đó.

Ví dụ so sánh thực tế:

Mục tiêu Cách cũ Tailwind 4 / OKLCH
Palette brand Hex #3b82f6, #2563eb, #1d4ed8 Token --color-brand-500: oklch(0.64 0.18 260)
Hover tối hơn Tự chọn hex khác Giảm L xuống 0.05-0.1, chroma giữ nguyên
Neutral ramp Gray các bước trông không đều Neutral scale mượt hơn trong OKLCH

Kết quả thực tế: palette của bạn trông cố ý hơn, không phải ngẫu nhiên.


Dùng OKLCH trong Tailwind 4 như thế nào?

Trong Tailwind 4, bạn khai báo màu bằng CSS custom properties bên trong @theme. Những token này tự động trở thành utilities như text-*, bg-*, border-*.

@import 'tailwindcss';

@theme {
  /* Màu brand chính */
  --color-brand-500: oklch(0.64 0.18 260);
  --color-brand-600: oklch(0.57 0.20 260);
  --color-brand-700: oklch(0.50 0.22 260);

  /* Màu nền tối */
  --color-midnight: oklch(0.15 0.05 270);

  /* Màu neutral mới trong v4.2 */
  --color-surface: oklch(0.97 0.005 270);
}

Sau khi khai báo, dùng ngay trong markup:

<button class="bg-brand-500 hover:bg-brand-600 text-white">
  Đăng ký
</button>

<div class="bg-midnight text-surface">
  Dark panel
</div>

344464 Token một chỗ, dùng khắp nơi - không còn lục lọc hex trong nhiều file

Lợi ích rõ nhất: khi designer muốn đổi màu brand, bạn chỉ sửa một dòng --color-brand-500 trong @theme. Mọi chỗ dùng token đó tự cập nhật. Không cần find-replace, không sợ sót.

Một tip nhỏ: nếu bạn muốn tìm hiểu sâu hơn về CSS, khóa HTML CSS từ Zero đến Hero ở F8 cover chi tiết cách tổ chức CSS trước khi bước vào Tailwind - nền tảng này khá quan trọng để hiểu @theme không bị mơ hồ.


Arbitrary values: dùng đúng chỗ mới thấy lợi

Arbitrary values là cách Tailwind cho phép bạn dùng giá trị ngoài scale mặc định bằng cú pháp [value]. Ví dụ:

<!-- Chiều rộng chính xác theo spec Figma -->
<div class="w-[347px]">

<!-- Khoảng cách hero section đặc biệt -->
<section class="pt-[120px] pb-[80px]">

<!-- Màu brand chưa kịp thêm vào token -->
<span class="text-[oklch(0.64_0.18_260)]">

<!-- Grid tùy biến -->
<div class="grid grid-cols-[1fr_300px_1fr]">

344468 Arbitrary values - escape hatch khi scale mặc định không đủ

Vấn đề với nhiều dev mới học Tailwind là dùng arbitrary values quá nhiều hoặc quá ít:

Dùng quá nhiều: Class string đầy [value] khắp nơi → khó maintain, mất đi lợi ích của design system nhất quán.

Dùng quá ít: Mỗi giá trị ngoài scale là phải mở config, thêm token → chậm, và nhiều token chỉ dùng một lần.

Rule of thumb mình hay dùng:

  • Thử nghiệm và một lần: dùng arbitrary value trực tiếp
  • Lặp lại 3+ lần: promote lên @theme token
  • Theo spec design chính xác: arbitrary value, sau đó hỏi lại designer có muốn standardize không

Tailwind 4 còn cho phép arbitrary values với OKLCH trực tiếp như bg-[oklch(0.64_0.18_260)] - chú ý dùng underscore thay space trong cú pháp class.


Workflow xây UI nhanh: từ markup đến component

Tailwind 4 giữ nguyên triết lý design-as-you-build: bạn ra quyết định về màu, spacing, typography ngay lúc viết markup, không phải sau đó trong một file CSS riêng. Với @theme tokens và OKLCH, workflow này càng thêm nhất quán.

Mình thường follow thứ tự này khi viết class:

  1. Layout trước: flex, grid, relative, absolute
  2. Box model: w-*, h-*, p-*, m-*, gap-*
  3. Visual: bg-*, border-*, rounded-*, shadow-*
  4. Typography: text-*, font-*, leading-*
  5. State variants: hover:, focus:, disabled:
  6. Responsive: sm:, md:, lg:
<!-- Ví dụ card sản phẩm - có thể đọc từ trên xuống dưới -->
<div class="
  flex flex-col gap-4
  w-full max-w-sm
  bg-white border border-gray-100 rounded-2xl p-6
  text-gray-900
  hover:shadow-md
  transition-shadow
">
  <img class="w-full aspect-video object-cover rounded-xl" src="..." />
  <h3 class="text-lg font-semibold">Tên sản phẩm</h3>
  <p class="text-sm text-gray-500">Mô tả ngắn</p>
  <button class="bg-brand-500 hover:bg-brand-600 text-white rounded-lg py-2 px-4">
    Mua ngay
  </button>
</div>

344466 Class theo thứ tự concern - đọc lại sau 2 tuần vẫn hiểu

Thứ tự này không bắt buộc bởi bất kỳ plugin hay rule nào, nhưng khi cả team theo cùng convention thì code review sẽ dễ hơn rất nhiều. Bạn đọc class từ trên xuống và hiểu ngay component đó làm gì về mặt layout, trước khi quan tâm đến màu sắc hay typography.

Nếu bạn đang bắt đầu với Tailwind, khóa Tailwind CSS miễn phí tại F8 có phần thực hành xây layout thực tế khá hữu ích cho giai đoạn này.


Khi nào nên tách component thay vì dùng class thẳng?

Một trong những câu hỏi mình hay thấy nhất: "Class dài quá, có nên tách ra không?"

Câu trả lời: đừng tách sớm.

Nếu component đó đang thay đổi liên tục, hoặc chỉ dùng một lần trong app, giữ utilities thẳng trong markup sẽ nhanh hơn nhiều. Abstraction quá sớm tạo ra những component "generic" không đủ linh hoạt, rồi bạn lại phải thêm props để customize - phức tạp hơn ban đầu.

344467 Tách component khi pattern lặp lại - không phải khi class dài

Mình dùng 3 nguyên tắc này để quyết định:

Giữ utilities thẳng khi:

  • Component chỉ xuất hiện 1-2 lần
  • Design đang thay đổi, chưa ổn định
  • Đang ở giai đoạn prototype/thử nghiệm

Tách thành component khi:

  • Pattern lặp 3+ lần trong codebase
  • Component có nhiều states rõ ràng: loading, disabled, error, selected
  • Class string dài đến mức đọc component chính bị xao nhãng

Promote lên @theme token khi:

  • Cùng màu/spacing xuất hiện ở nhiều component không liên quan
  • Giá trị có ý nghĩa trong design system (màu brand, spacing chuẩn)

Ví dụ thực tế: button component. Ban đầu bạn có thể viết thẳng:

<button class="bg-brand-500 hover:bg-brand-600 text-white rounded-lg py-2 px-4 font-medium transition-colors">
  Đăng ký
</button>

Khi button đó xuất hiện ở 10+ chỗ với variants (primary, secondary, ghost), đó là lúc wrap lại thành <Button variant="primary">. Không phải trước đó.

Workflow này - utilities → token → component - là cách Tailwind được dùng hiệu quả nhất trong dự án thực tế.

Trang web dùng cookie để hoạt động và đo hiệu quả quảng cáo. Xem chính sách bảo mật