Tailwind CSS 4.0: Arbitrary Values và OKLCH Colors cho Responsive Design siêu linh hoạt

5 tháng trước · 8 phút đọc
Tailwind CSS 4.0 thay đổi gì so với v3?
Mình nhớ lần đầu đọc release notes của Tailwind CSS 4.0 - cảm giác giống như họ viết lại từ đầu vậy. Không phải vì thêm vài class mới, mà vì triết lý cốt lõi thay đổi hoàn toàn: CSS-first thay vì JS-first.
Trong v3, cấu hình nằm hết trong tailwind.config.js. Muốn thêm màu? Vào JS. Muốn custom spacing? Vào JS. Muốn extend theme? Vào JS. Mọi thứ đều phải qua một file JS trung gian trước khi ra CSS. v4 đảo ngược hoàn toàn điều đó.
CSS-first loại bỏ JS trung gian - config nằm thẳng trong CSS
Thay vì tailwind.config.js, bạn dùng directive @theme ngay trong file CSS:
Tailwind tự động generate CSS variables từ @theme, sau đó dùng được ngay trong toàn bộ utility classes. Không cần resolveConfig, không cần import JS theme vào component.
Một thay đổi nhỏ nhưng có impact lớn: default scale của v4 được mở rộng đáng kể. Trước đây p-7 không tồn tại (v3 nhảy từ p-6 lên p-8), bạn phải viết p-[28px]. Giờ p-7, p-9, gap-7, m-9 đều có sẵn - {{fact:fact_0}} giá trị spacing mới được thêm vào default scale.
Kết quả? Arbitrary values vẫn còn đó, nhưng bạn cần dùng ít hơn nhiều cho spacing thông thường.
Arbitrary values trong v4: mạnh hơn, ít đau đầu hơn
Arbitrary values [...] không phải tính năng mới - v3 đã có. Nhưng v4 nâng nó lên một tầm khác.
Vấn đề cũ với v3: dùng calc() hoặc var() trong arbitrary values thường cần escape ký tự hoặc viết khá awkward:
v4 giữ nguyên cú pháp này nhưng xử lý calc() và var() mượt hơn - không cần escape phức tạp. Quan trọng hơn, v4 thêm wildcard * support cho custom utilities:
Sau đó dùng: class="sidebar-w-[250px]" hoặc class="sidebar-w-[--custom-var]". Pattern này cho phép build utility system linh hoạt như Chakra nhưng không cần JS runtime.
Wildcard utility - viết một lần, dùng với bất kỳ giá trị nào
Arbitrary variants cũng được cải thiện. Bạn có thể combine container queries với arbitrary:
Một tip thực tế: arbitrary values vẫn cần dùng cho các trường hợp design cụ thể như pixel-perfect layout, custom breakpoint lẻ, hoặc giá trị từ design token của Figma. Nhưng cho spacing/sizing thông thường, default scale của v4 đủ cover {{fact:fact_1}} trường hợp phổ biến mà không cần đụng tới [...].
OKLCH color space: màu sắc đều hơn, đẹp hơn, dễ quản lý hơn
Bạn có bao giờ nhận thấy trong design system, màu blue-500 trông sáng hơn green-500 dù cùng "level 500"? Đó là vấn đề của HSL và HEX - chúng không phản ánh đúng độ sáng mà mắt người cảm nhận.
OKLCH giải quyết đúng vấn đề đó. Thay vì Hue/Saturation/Lightness theo kiểu máy tính, OKLCH dùng Lightness theo nhận thức thị giác (perceptual lightness). Kết quả: oklch(60% 0.15 260) (xanh dương) và oklch(60% 0.15 140) (xanh lá) sẽ có độ sáng thật sự bằng nhau khi mắt nhìn vào.
Cùng lightness value trong OKLCH = cùng độ sáng thật sự - không giống HEX/HSL
Trong Tailwind v4, dùng OKLCH qua CSS variables trong @theme:
Nhìn vào pattern: success, warning, danger đều dùng cùng lightness (60%) và chroma (0.15), chỉ khác hue. Điều đó đảm bảo 3 màu trông "nặng" bằng nhau trên giao diện - rất quan trọng cho badge, alert, button states.
Dark mode với OKLCH cũng cực sạch:
Browser support: OKLCH được hỗ trợ từ {{fact:fact_2}}. Với các project cần IE hay browser cũ hơn, fallback về HEX vẫn ổn.
Container queries native: responsive theo container, không chỉ theo viewport
Media queries có một điểm yếu kinh điển: chúng responsive theo viewport (cửa sổ trình duyệt), không phải theo container (element cha). Kết quả là cùng một component card, khi nằm trong sidebar hẹp vs nội dung chính rộng, nó không thể tự biết mình đang ở đâu để điều chỉnh.
Tailwind v3 giải quyết bằng plugin @tailwindcss/container-queries. v4 tích hợp thẳng vào core - không cần cài thêm gì.
Cùng component, tự reshape theo container - không phụ thuộc viewport
Breakpoints container mặc định trong v4: @xs (320px), @sm (384px), @md (448px), @lg (512px), @xl (576px), @2xl (672px). Custom breakpoint qua @theme:
Sau đó dùng: class="@sidebar:hidden @chart:block".
Tại sao quan trọng cho dashboard? Một widget chart khi nằm trong layout 3 cột sẽ compact hơn so với khi mở rộng sang full-width. Container queries cho phép widget tự điều chỉnh mà không cần JavaScript ResizeObserver hay CSS hack. Bạn viết component một lần, nó hoạt động đúng ở mọi vị trí.
Kết hợp với arbitrary variants: class="[@container(min-width:400px)_&]:flex-row" cho trường hợp cần precision cao hơn preset breakpoints.
Build responsive dashboard thực chiến với Tailwind v4
Đủ lý thuyết rồi - build thật đi. Mình sẽ dùng tất cả những gì đã nói để tạo một dashboard layout responsive hoàn chỉnh.
Bước 1: Setup CSS-first config
Bước 2: Layout shell
Dashboard responsive - widget tự điều chỉnh không cần JS
Mấy điểm đáng chú ý trong code trên:
gap-7vàp-9dùng được thẳng mà không cần[28px]hay[36px]w-[--sidebar-width]lấy giá trị từ CSS var định nghĩa trong@theme@md:grid-cols-2và@xl:grid-cols-4là container breakpoints, không phải viewportbg-[--color-brand-900]vàtext-[--color-brand-500]dùng OKLCH colors đã định nghĩa
Bạn có thể tải file demo để xem toàn bộ layout chạy thật: {{resource:resource_0}}
Migration từ v3 lên v4: những gì cần làm
Nếu bạn đang có project v3, migration lên v4 không phải đơn giản install rồi chạy - có một số breaking changes cần xử lý.
Những gì thay đổi:
tailwind.config.js không còn là cách chính để config. Bạn cần chuyển theme.extend vào @theme trong CSS:
Plugins cũng thay đổi. Thay vì plugins: [require('...')] trong JS, dùng @plugin directive:
Nếu trước đây dùng resolveConfig để access theme trong JavaScript:
4 bước migration từ v3 sang v4 - chú ý phần custom utilities
Quy trình migration an toàn:
- Chạy
npx tailwindcss@next init --cssđể tạo boilerplate CSS config mới - Copy từng phần
theme.extendtừ JS sang@themetrong CSS - Đổi màu HEX/HSL sang OKLCH (dùng công cụ convert online)
- Rewrite custom plugins thành
@utilitydirectives - Test kỹ purging - v4 có cơ chế detect class khác v3
Lưu ý cho dự án Việt: Nếu dùng font tiếng Việt (Be Vietnam Pro, SVN-Gilroy), khai báo thẳng trong @theme:
Nếu bạn mới bắt đầu với HTML/CSS và chưa quen với Tailwind, khóa HTML CSS từ Zero đến Hero trên F8 sẽ cho bạn nền tảng tốt trước khi đụng vào v4. Còn nếu muốn học responsive đúng bài bản, khóa Responsive Với Grid System cũng rất đáng xem.
Một điều mình thấy sau khi migrate 2 project: code CSS sạch hơn hẳn. Không còn file JS config lủng củng, không còn phải jump qua lại giữa CSS và config. Mọi thứ nằm trong CSS - đúng chỗ của nó.
