Tailwind CSS 2026 và Modern CSS: 7 kỹ thuật làm UI nhanh hơn, sạch hơn

một tháng trước · 6 phút đọc
Mình đã viết CSS kiểu cũ quá lâu
Hồi 2022, mình vẫn còn viết BEM, tạo file _card.scss, lồng selector 4 tầng. Mỗi lần designer thay màu là mình phải mở 3 file khác nhau. Kết quả? Codebase sau 6 tháng không ai dám đụng vào.
Tailwind CSS thay đổi workflow đó hoàn toàn. Nhưng đến 2026, chỉ biết Tailwind thôi chưa đủ. Phiên bản 4.0 đã thay đổi khá nhiều thứ, và kết hợp với modern CSS features như container queries hay :has(), bạn có thể làm những thứ trước đây cần đến JavaScript.
Bài này mình tổng hợp 7 kỹ thuật thực tế, kèm code chạy được, để bạn dùng ngay.
Từ file SCSS lồng nhau đến utility classes - workflow đã thay đổi hoàn toàn
Kỹ thuật 1: @theme - design tokens ngay trong CSS
Tailwind 4.0 không còn bắt bạn phải mở tailwind.config.js để thay màu nữa. Token giờ sống trong CSS, qua directive @theme.
Sau đó dùng trực tiếp trong Tailwind class hoặc CSS thuần:
Token khai báo một lần, dùng ở cả utility class lẫn CSS thuần - không còn drift
Lợi ích thực tế: khi designer đổi brand color, bạn chỉ sửa một dòng trong @theme. Mọi component tự cập nhật.
Một lưu ý quan trọng: đừng nhét tất cả vào @theme. Chỉ token nào thật sự thuộc design system - màu, spacing, radius, shadow, font - mới cần ở đây. Giá trị one-off vẫn nên dùng arbitrary value.
Kỹ thuật 2: Container queries - responsive theo vùng chứa, không phải viewport
Vấn đề của responsive thuần breakpoint: một card trong sidebar và card trong main content có cùng viewport width, nhưng không gian thật sự chúng nhận được khác nhau hoàn toàn.
Container queries giải quyết đúng bài toán này.
Tailwind 4 có sẵn @container, @sm:, @md:, @lg: variants. Không cần plugin thêm.
Cùng component, khác container - card tự điều chỉnh layout mà không cần breakpoint viewport
Khi nào nên dùng container queries thay vì breakpoints thông thường? Khi component được tái sử dụng ở nhiều layout khác nhau - card, widget dashboard, sidebar block, toolbar. Khi component chỉ xuất hiện ở một chỗ cố định, breakpoint viewport vẫn đơn giản hơn và đủ dùng.
Kỹ thuật 3: :has() selector - parent selector đã đến
Trước đây, để style một card khác đi khi nó chứa ảnh, bạn cần thêm class JS hoặc tạo component variant riêng. Với :has(), không cần nữa.
:has() thay thế một phần JS state management cho UI patterns đơn giản
Lưu ý thực tế: :has() rất mạnh nhưng dễ lạm dụng. Mình có quy tắc đơn giản - dùng :has() khi logic đơn giản (có/không có element), dùng JS khi state phức tạp hơn hoặc cần animate. Selector quá dài và lồng nhiều tầng sẽ làm CSS khó debug hơn là giúp ích.
Kỹ thuật 4: CSS nesting native - bỏ Sass chỉ để lồng selector
Native CSS nesting giờ được hỗ trợ trên tất cả major browsers. Điều này không có nghĩa là bạn nên lồng mọi thứ - nhưng với component CSS cục bộ, nesting giúp code đọc dễ hơn nhiều.
Native nesting giảm nhu cầu Sass thuần túy - nhưng Tailwind vẫn tốt hơn cho phần lớn styling
Mình vẫn dùng Sass không? Có, nhưng ít hơn. Sass vẫn có giá trị ở mixins, functions, và @each/@for loop cho các trường hợp generate utility phức tạp. Còn nếu bạn chỉ cần Sass để lồng selector, thì giờ không cần nữa.
Nếu bạn đang học Sass từ đầu, khóa Ngôn ngữ Sass cover chi tiết khi nào Sass vẫn có giá trị so với CSS native.
Kỹ thuật 5: OKLCH colors - palette nhất quán hơn HSL
Bạn đã bao giờ tạo palette màu bằng HSL, nhưng khi xem trên màn hình thực tế, màu ở lightness 50% và 70% trông không đều nhau về độ sáng cảm nhận?
Đó là vấn đề của HSL. OKLCH giải quyết điều này bằng cách map màu sắc gần hơn với cách mắt người cảm nhận.
So sánh với cách cũ:
OKLCH tạo gradient đều hơn về mặt cảm nhận thị giác - dark mode palette dễ làm hơn nhiều
Ứng dụng thực tế nhất của OKLCH: dark mode. Với HSL, bạn thường phải điều chỉnh tay từng màu khi chuyển sang dark theme. Với OKLCH và token hóa trong @theme, bạn có thể tính toán màu dark mode một cách có hệ thống hơn.
