Đ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.0: Kỹ thuật responsive design nâng cao cho web dev Việt

Ếch Trendy
Ếch Trendy

6 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 4.0 - cảm giác như framework này vừa được viết lại từ đầu. Không phải nâng cấp nhỏ. Đây là một paradigm shift thật sự.

Điểm thay đổi lớn nhất: CSS-first configuration. Bạn không còn cần tailwind.config.js nữa. Thay vào đó, mọi thứ được khai báo trực tiếp trong file CSS thông qua các directive mới:

/* v4.0: Import và config trong CSS */
@import "tailwindcss";

@theme {
  --color-brand: oklch(0.7 0.2 240);
  --font-display: 'Be Vietnam Pro', sans-serif;
}

So với v3.x phải làm qua file JS riêng biệt, cách này giúp config gần với CSS thực tế hơn, dễ maintain hơn trong team.

342840 Từ JS config sang CSS-first - workflow đơn giản hơn hẳn

Nhưng cái thay đổi làm mình ấn tượng nhất là Oxide engine. Full build từ {{fact:fact_0}} nhờ engine mới này. Incremental rebuild - tức là khi bạn save file và chờ hot reload - nhanh hơn từ 8.8x đến 182x tùy dự án. Với những ai đang làm dự án Next.js lớn, con số này không phải nhỏ.

Ngoài ra, v4.0 còn tích hợp container queries native (không cần plugin riêng như v3), hỗ trợ màu OKLCH và color-mix(), và cơ chế custom variants linh hoạt hơn nhiều. Mình sẽ đi chi tiết từng phần bên dưới.


Container queries native: Responsive thật sự linh hoạt

Đây là tính năng mình thích nhất trong v4.0. Nếu bạn chưa biết container queries là gì: thay vì responsive dựa vào viewport (chiều rộng màn hình), bạn responsive dựa vào container chứa component đó.

Tại sao quan trọng? Xét một card sản phẩm trong e-commerce. Ở trang chủ, card nằm trong grid 4 cột. Ở sidebar, card nằm trong cột hẹp 200px. Cùng một component, hai context khác nhau hoàn toàn - và media queries thông thường không xử lý được trường hợp này.

342841 Container queries giải quyết vấn đề mà media queries không làm được

Trong v4.0, bạn chỉ cần:

<!-- Parent: khai báo là container -->
<div class="@container">
  <!-- Child: responsive dựa theo container -->
  <div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-4 gap-4">
    <div class="card @sm:flex-row @lg:flex-col">
      <!-- Nội dung card -->
    </div>
  </div>
</div>

Prefix @sm:, @lg: là container query variants - hoàn toàn native, không cần cài plugin. Breakpoint mặc định của Tailwind (sm, md, lg) vẫn hoạt động song song cho media queries.

Một use case thực tế cho dev Việt: dashboard quản lý với sidebar. Khi sidebar mở, content area thu hẹp - grid sản phẩm cần tự điều chỉnh từ 3 cột xuống 2 cột. Với media queries, bạn không biết content area rộng bao nhiêu. Với container queries, component tự lo.

/* Đặt named container cho debug dễ hơn */
.sidebar-layout {
  container-name: sidebar;
  container-type: inline-size;
}

Một lưu ý: arbitrary breakpoints với calc() hoặc var() có thể fail trong v4. Nếu bạn đang dùng [@123px:...] từ v3, cần đổi sang @min-w-[123px]:....


Advanced variants và @theme: Tùy chỉnh theo style Việt

Trong v3, muốn thêm custom variant phải viết plugin JS. Trong v4, bạn làm thẳng trong CSS:

/* Định nghĩa dark mode variant dạng class */
@custom-variant dark (&:where(.dark, .dark *));

/* Kết hợp nhiều điều kiện */
@custom-variant hover-dark (&:hover:where(.dark, .dark *));

Rồi dùng ngay trong HTML:

<button class="bg-white dark:bg-gray-900 hover-dark:bg-gray-700">
  Nút tùy chỉnh
</button>

342842 Variants tùy chỉnh - viết một lần, dùng khắp nơi

Phần @theme mới mới thật sự shine khi bạn xây design system cho dự án Việt. Tailwind 4.0 hỗ trợ màu OKLCH - một color space hiện đại hơn HEX/HSL, giúp màu sắc nhìn đồng đều hơn trên các màn hình.

@theme {
  /* Màu brand cho dự án Việt */
  --color-brand-primary: oklch(0.55 0.22 25);   /* Đỏ */
  --color-brand-secondary: oklch(0.85 0.18 95); /* Vàng */

  /* Font tiếng Việt */
  --font-body: 'Be Vietnam Pro', 'Roboto', sans-serif;
  --font-display: 'Lexend', sans-serif;

  /* Spacing tùy chỉnh */
  --spacing-safe: 1.5rem; /* Safe area cho mobile Việt hay dùng bottom nav */
}

Sau khi khai báo trong @theme, bạn dùng trực tiếp qua utility classes:

<h1 class="text-brand-primary font-display">
  Chào mừng đến Shopee Clone
</h1>

Không cần extend, không cần restart dev server. Config thay đổi ngay lập tức trong hot reload.

Nếu bạn muốn đi sâu vào HTML/CSS để có nền tảng vững trước khi học Tailwind, khóa HTML CSS Pro có phần về design system và responsive khá chi tiết.


Build responsive layout thực chiến: Card grid e-commerce

Lý thuyết đủ rồi. Mình sẽ build một product grid như Shopee/Tiki - thường thấy trong các dự án thực tế của dev Việt.

Yêu cầu:

  • Mobile: 2 cột
  • Tablet: 3 cột
  • Desktop full: 4 cột
  • Khi nằm trong sidebar (container hẹp): tự xuống 2 cột dù màn hình desktop
<!-- Layout chính -->
<div class="@container">
  <div class="
    grid gap-3
    grid-cols-2
    @md:grid-cols-3
    @xl:grid-cols-4
  ">
    <!-- Product card -->
    <div class="
      rounded-xl border border-gray-100
      hover:shadow-md transition-shadow
      @sm:flex-row @xl:flex-col
    ">
      <img
        class="w-full aspect-square object-cover rounded-t-xl"
        src="/product.jpg"
        alt="Sản phẩm"
      />
      <div class="p-3">
        <p class="text-sm text-gray-500 truncate">Áo thun nam</p>
        <p class="font-semibold text-red-600">129.000₫</p>
        <p class="text-xs line-through text-gray-400">199.000₫</p>
      </div>
    </div>
  </div>
</div>

342843 Grid tự thích nghi - không cần viết media query riêng cho từng context

Với dark mode, bạn không cần thêm gì vào component. Chỉ cần toggle class .dark trên <html>:

/* CSS: đã define variant ở @theme */
@custom-variant dark (&:where(.dark, .dark *));
<!-- Dark mode tự động áp dụng -->
<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100">
  ...
</div>

Muốn nâng cao hơn, kết hợp với CVA (Class Variance Authority) để tạo component variants rõ ràng:

import { cva } from 'class-variance-authority';

const cardVariants = cva(
  // Base classes
  'rounded-xl border transition-all',
  {
    variants: {
      featured: {
        true: 'border-red-500 shadow-red-100 shadow-md',
        false: 'border-gray-100 hover:shadow-sm'
      },
      size: {
        sm: '@sm:p-2',
        md: '@md:p-4',
        lg: '@lg:p-6'
      }
    },
    defaultVariants: { featured: false, size: 'md' }
  }
);

File demo dưới đây bạn có thể mở thẳng trong browser để xem product grid này hoạt động ra sao: {{resource:resource_0}}


Tối ưu build size và migrate từ v3 lên v4

Oxide engine trong v4.0 tự detect unused CSS thông minh hơn JIT của v3 - không cần cấu hình purge thủ công. Build size output nhỏ hơn {{fact:fact_1}} so với v3 theo benchmark của team Tailwind. Với Next.js hoặc Vite, đây là improvement đáng kể khi scale dự án.

Setup v4.0 với Vite:

npm install tailwindcss@next @tailwindcss/vite
// vite.config.ts
import tailwindcss from '@tailwindcss/vite';

export default {
  plugins: [tailwindcss()]
};
/* src/index.css - chỉ cần dòng này */
@import "tailwindcss";

Không cần postcss.config.js, không cần tailwind.config.js. Đơn giản hơn setup v3 khá nhiều.

342844 Migration từ v3 sang v4 - đừng làm ồ ạt một lúc

Migration từ v3: những điểm cần chú ý

Team Tailwind có cung cấp codemod tool để migrate tự động phần lớn config. Nhưng có một số chỗ cần tay:

  • tailwind.config.js → chuyển toàn bộ theme tokens sang @theme {} trong CSS
  • Custom plugins → viết lại bằng @utility hoặc @variant directive
  • [@123px:...] (arbitrary container breakpoints) → đổi sang @min-w-[123px]:...
  • Arbitrary values với calc() hoặc var() trong container queries → test kỹ, có thể fail

Mình khuyên migrate từng feature một, không làm ồ ạt. Bắt đầu từ @import@theme, sau đó mới đến custom variants. Dùng @source để fallback một phần config cũ nếu cần.

Checklist migration đầy đủ để bạn không bỏ sót: {{resource:resource_1}}

Sau khi migrate xong, chạy npm run build và so sánh output CSS size. Nếu thấy giảm đáng kể - bạn đang đi đúng hướng.


Plugins tùy chỉnh và design system cho dự án Việt

Trong v4.0, custom utilities không cần plugin JS nữa. Bạn viết thẳng trong CSS:

@import "tailwindcss";

@theme {
  --color-vn-red: oklch(0.52 0.22 25);
  --color-vn-yellow: oklch(0.87 0.19 93);
  --font-viet: 'Be Vietnam Pro', sans-serif;
}

/* Utility tùy chỉnh */
@utility text-balance-viet {
  text-wrap: balance;
  word-break: break-word; /* Tiếng Việt dài, dễ overflow */
  overflow-wrap: break-word;
}

@utility price-vnd {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

/* Component class */
@layer components {
  .btn-primary {
    @apply bg-vn-red text-white px-4 py-2 rounded-lg
           hover:brightness-90 transition-all
           font-semibold text-sm;
  }
}

Rồi dùng ngay:

<p class="text-balance-viet">
  Mô tả sản phẩm dài tiếng Việt tự wrap đẹp
</p>
<span class="price-vnd text-vn-red font-bold">
  1.299.000₫
</span>
<button class="btn-primary">Mua ngay</button>

342845 Design tokens tiếng Việt - nhất quán toàn dự án, dễ update sau này

Một điểm mình thích: OKLCH color space làm màu đỏ Việt Nam (--color-vn-red) trông đẹp và nhất quán hơn trên cả màn hình sRGB lẫn Display P3. HEX không đảm bảo được điều này.

Nếu team bạn đang build design system cần scale lớn, cân nhắc kết hợp với Storybook để document components. Mỗi utility và component class bạn define trong @utility đều có thể được test độc lập.

Cuối cùng: Tailwind 4.0 vẫn đang active development, một số edge cases có thể còn bug. Theo dõi {{resource:resource_2}} để cập nhật patches mới nhất.

Takeaways:

  • CSS-first config giảm boilerplate, dễ onboard thành viên mới
  • Container queries giải quyết responsive theo context, không chỉ theo viewport
  • Oxide engine cắt build time đáng kể - quan trọng trong CI/CD pipeline
  • @theme với OKLCH cho design token nhất quán, dễ maintain

Bắt đầu với một component nhỏ - product card hoặc button. Cảm nhận sự khác biệt. Sau đó migrate dần dần, không vội.