Layout & Spacing — Container, Display, Flexbox, Grid
Tổng quan
Layout và spacing là nền tảng của mọi giao diện web. Tailwind CSS v4 cung cấp bộ utility cực mạnh cho display, position, flexbox, grid, spacing, sizing, overflow và scrollbar — tất cả đều map trực tiếp đến CSS nhưng nhanh hơn nhờ không phải viết CSS rời.
"Tailwind cung cấp utility class map 1-1 với CSS properties —
flex=display: flex,grid-cols-3=grid-template-columns: repeat(3, 1fr). Điểm mạnh: responsive variants (md:flex,lg:grid-cols-4) viết ngay trong HTML không cần media query riêng. Container queries cũng có sẵn (@container,@md:grid-cols-2) từ v4.0."
1. Display
Các giá trị display được ánh xạ thành class:
| Class | CSS | Ghi chú |
|---|---|---|
block | display: block | |
inline | display: inline | |
inline-block | display: inline-block | |
inline-flex | display: inline-flex | Flex container nhưng inline |
flex | display: flex | |
inline-grid | display: inline-grid | |
grid | display: grid | |
flow-root | display: flow-root | Clear float không cần clearfix |
hidden | display: none | Ẩn element, xóa khỏi flow |
contents | display: contents | Element bị "bỏ qua", children lên thay |
table, table-row, table-cell, table-caption, table-column, table-column-group, table-footer-group, table-header-group, table-row-group | display: table; v.v... | Layout kiểu bảng |
Ví dụ cơ bản
<!-- Block vs Inline -->
<div class="block bg-blue-200 p-2 mb-2">Block — chiếm full width</div>
<span class="inline bg-green-200 p-2">Inline 1</span>
<span class="inline bg-green-200 p-2">Inline 2</span>
<!-- Inline-flex — container flex nhưng không ngắt dòng -->
<span class="inline-flex items-center gap-2 bg-yellow-200 px-3 py-1 rounded-full">
<span class="w-2 h-2 bg-green-500 rounded-full"></span>
Online
</span>
<!-- Contents — bỏ qua wrapper -->
<div class="grid grid-cols-2 gap-4">
<div class="contents">
<div class="bg-red-200 p-4">Item 1</div>
<div class="bg-red-200 p-4">Item 2</div>
</div>
</div>
contents hữu ích khi nào? Khi bạn có wrapper component nhưng không muốn nó ảnh hưởng đến grid/flex layout của parent. Ví dụ: <Card> component render children trực tiếp vào grid cha mà không tạo wrapper div thừa.Bài tập 1: Navigation bar với flex và hidden cho mobile toggle
Yêu cầu: Tạo navigation bar có logo bên trái, menu links ở giữa, button bên phải. Trên mobile (< 768px), menu links ẩn đi và hiển thị hamburger button.
<nav class="flex items-center justify-between px-6 py-4 bg-white shadow">
<!-- Logo -->
<a href="#" class="text-xl font-bold text-blue-600">Brand</a>
<!-- Menu links — ẩn trên mobile, hiện từ md trở lên -->
<div class="hidden md:flex items-center gap-6">
<a href="#" class="text-gray-700 hover:text-blue-600 transition-colors">Home</a>
<a href="#" class="text-gray-700 hover:text-blue-600 transition-colors">Features</a>
<a href="#" class="text-gray-700 hover:text-blue-600 transition-colors">Pricing</a>
<a href="#" class="text-gray-700 hover:text-blue-600 transition-colors">About</a>
</div>
<!-- Button bên phải -->
<button class="hidden md:block bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors">
Get Started
</button>
<!-- Hamburger — chỉ hiện trên mobile -->
<button class="md:hidden text-gray-700">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"/>
</svg>
</button>
</nav>
hidden md:flex là pattern mobile-first kinh điển trong Tailwind — element bắt đầu ở trạng thái ẩn, hiện ra từ breakpoint chỉ định.Bài tập 2: Hide/show sidebar với hidden + breakpoint variants
Yêu cầu: Layout có sidebar bên trái. Trên mobile, sidebar bị ẩn, chỉ hiện khi bấm toggle. Trên desktop (lg), sidebar luôn hiện.
<div class="flex min-h-screen">
<!-- Overlay — chỉ trên mobile khi sidebar mở -->
<div class="fixed inset-0 bg-black/50 z-10 lg:hidden" id="overlay"></div>
<!-- Sidebar — ẩn mobile mặc định, luôn hiện trên lg -->
<aside class="fixed lg:static inset-y-0 left-0 z-20 w-64 bg-gray-900 text-white
-translate-x-full lg:translate-x-0 transition-transform duration-300"
id="sidebar">
<div class="p-6">
<h2 class="text-xl font-bold mb-6">Sidebar</h2>
<nav class="flex flex-col gap-3">
<a href="#" class="text-gray-300 hover:text-white transition-colors">Dashboard</a>
<a href="#" class="text-gray-300 hover:text-white transition-colors">Analytics</a>
<a href="#" class="text-gray-300 hover:text-white transition-colors">Settings</a>
</nav>
</div>
</aside>
<!-- Main content -->
<main class="flex-1 p-6 bg-gray-100">
<button class="lg:hidden mb-4 px-3 py-2 bg-gray-800 text-white rounded"
onclick="document.getElementById('sidebar').classList.toggle('-translate-x-full')">
Toggle Sidebar
</button>
<h1 class="text-2xl font-bold">Main Content</h1>
</main>
</div>
fixed lg:static — thay đổi hoàn toàn positioning context giữa mobile và desktop. Kết hợp -translate-x-full lg:translate-x-0 để slide in/out trên mobile.2. Position
| Class | CSS |
|---|---|
static | position: static |
fixed | position: fixed |
absolute | position: absolute |
relative | position: relative |
sticky | position: sticky |
Inset utilities (inset-*, top-*, right-*, bottom-*, left-*)
<!-- Fixed to top -->
<div class="fixed top-0 inset-x-0 bg-white shadow z-50">Fixed Header</div>
<!-- Absolute centered -->
<div class="relative h-64 bg-gray-200">
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-blue-500 text-white p-4 rounded">
Centered
</div>
</div>
<!-- Sticky -->
<div class="sticky top-4 bg-yellow-200 p-2 z-10">Sticky — dừng ở top 16px</div>
Z-Index
<div class="z-0 bg-red-200 p-4">z-0</div>
<div class="z-10 bg-blue-200 p-4">z-10</div>
<div class="z-20 bg-green-200 p-4">z-20</div>
<div class="z-30 bg-purple-200 p-4">z-30</div>
<div class="z-40 bg-yellow-200 p-4">z-40</div>
<div class="z-50 bg-pink-200 p-4">z-50</div>
<div class="z-auto bg-gray-200 p-4">z-auto</div>
Bài tập 3: Fixed header luôn trên cùng khi scroll
Yêu cầu: Header cố định trên cùng, không bị nội dung đè lên khi scroll. Nội dung bên dưới cuộn bình thường.
<div class="min-h-[200vh]">
<!-- Fixed header -->
<header class="fixed top-0 inset-x-0 z-50 bg-white/80 backdrop-blur-md shadow-sm">
<div class="max-w-6xl mx-auto flex items-center justify-between px-6 py-4">
<span class="text-xl font-bold">My App</span>
<nav class="flex gap-4">
<a href="#" class="text-gray-600 hover:text-gray-900">Home</a>
<a href="#" class="text-gray-600 hover:text-gray-900">About</a>
<a href="#" class="text-gray-600 hover:text-gray-900">Contact</a>
</nav>
</div>
</header>
<!-- Nội dung — đẩy xuống bằng pt-20 để không bị header che -->
<main class="pt-20 px-6">
<h1 class="text-3xl font-bold mb-4">Page Content</h1>
<p class="text-gray-600 mb-4">Scroll xuống để thấy header vẫn cố định trên cùng.</p>
<!-- Thêm nhiều nội dung để test scroll -->
<div class="space-y-4">
<div class="h-48 bg-gray-100 rounded-lg"></div>
<div class="h-48 bg-gray-100 rounded-lg"></div>
<div class="h-48 bg-gray-100 rounded-lg"></div>
<div class="h-48 bg-gray-100 rounded-lg"></div>
</div>
</main>
</div>
fixed top-0 inset-x-0 = dính top + full width. bg-white/80 backdrop-blur-md = header trong suốt nhẹ với blur nền phía sau — hiệu ứng phổ biến trên landing page hiện đại.Bài tập 4: Sticky sidebar trong blog layout
Yêu cầu: Blog layout 2 cột — nội dung chính bên trái, sidebar bên phải. Sidebar sticky — luôn trong viewport khi scroll bài viết dài.
<div class="max-w-6xl mx-auto px-6 py-8">
<div class="flex flex-col lg:flex-row gap-8">
<!-- Main content -->
<article class="flex-1 min-w-0">
<h1 class="text-3xl font-bold mb-4">Bài viết dài</h1>
<div class="prose max-w-none">
<p class="mb-4">Nội dung bài viết rất dài...</p>
<!-- Giả lập nội dung dài -->
<div class="space-y-4">
<div class="h-32 bg-gray-100 rounded"></div>
<div class="h-32 bg-gray-100 rounded"></div>
<div class="h-32 bg-gray-100 rounded"></div>
<div class="h-32 bg-gray-100 rounded"></div>
<div class="h-32 bg-gray-100 rounded"></div>
<div class="h-32 bg-gray-100 rounded"></div>
</div>
</div>
</article>
<!-- Sticky sidebar -->
<aside class="w-full lg:w-80">
<div class="sticky top-24 space-y-6">
<div class="bg-gray-50 rounded-lg p-6">
<h3 class="font-bold mb-2">Mục lục</h3>
<ul class="space-y-2 text-sm text-gray-600">
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>
</div>
<div class="bg-blue-50 rounded-lg p-6">
<h3 class="font-bold mb-2">Bài viết liên quan</h3>
<ul class="space-y-2 text-sm text-blue-600">
<li>Bài viết A</li>
<li>Bài viết B</li>
</ul>
</div>
</div>
</aside>
</div>
</div>
top-24? Vì thường có fixed header cao ~96px (24 trong scale Tailwind = 6rem). top-24 giúp sidebar dính ở vị trí ngay dưới header, không bị che.Bài tập 5: Absolute positioned badge trên card
Yêu cầu: Card sản phẩm có badge "Sale" hoặc "New" ở góc trên bên phải, dùng absolute bên trong relative container.
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 p-6">
<!-- Card 1 — badge "New" -->
<div class="relative bg-white rounded-xl shadow-md overflow-hidden group">
<span class="absolute top-3 right-3 bg-green-500 text-white text-xs font-bold px-2 py-1 rounded-full z-10">
New
</span>
<div class="h-48 bg-gradient-to-br from-blue-400 to-purple-500"></div>
<div class="p-4">
<h3 class="font-bold">Sản phẩm A</h3>
<p class="text-gray-600 text-sm">Mô tả ngắn gọn</p>
</div>
</div>
<!-- Card 2 — badge "Sale" -->
<div class="relative bg-white rounded-xl shadow-md overflow-hidden">
<span class="absolute top-3 right-3 bg-red-500 text-white text-xs font-bold px-2 py-1 rounded-full z-10">
-30%
</span>
<div class="h-48 bg-gradient-to-br from-pink-400 to-orange-400"></div>
<div class="p-4">
<h3 class="font-bold">Sản phẩm B</h3>
<p class="text-gray-600 text-sm">Đang giảm giá</p>
</div>
</div>
<!-- Card 3 — double badge -->
<div class="relative bg-white rounded-xl shadow-md overflow-hidden">
<div class="absolute top-3 right-3 flex flex-col gap-1 z-10">
<span class="bg-red-500 text-white text-xs font-bold px-2 py-1 rounded-full">Sale</span>
<span class="bg-blue-500 text-white text-xs font-bold px-2 py-1 rounded-full">Hot</span>
</div>
<div class="h-48 bg-gradient-to-br from-teal-400 to-cyan-500"></div>
<div class="p-4">
<h3 class="font-bold">Sản phẩm C</h3>
<p class="text-gray-600 text-sm">Bán chạy nhất</p>
</div>
</div>
</div>
absolute luôn cần cha relative (hoặc absolute/fixed). Nếu không có, element sẽ absolute so với viewport.3. Container & Container Queries (v4.0 NEW)
Container queries cho phép component responsive dựa trên kích thước của chính nó, không phải viewport.
Container class và directive
| Class | CSS | Ghi chú |
|---|---|---|
@container | container-type: inline-size | Kích hoạt container query |
@container-normal | container-type: normal | Style container (không query size) |
@sm:, @md:, @lg:, @xl: | Container query variants | Điều kiện dựa trên width của container gần nhất |
@container-size-* (v4.3) | Custom container size | @container-size-md, @container-size-lg... |
<!-- Container query: card thay đổi layout dựa trên width của chính nó -->
<div class="@container border rounded-lg p-4">
<div class="flex flex-col @md:flex-row gap-4">
<div class="w-full @md:w-1/3 aspect-square bg-gray-200 rounded"></div>
<div class="flex-1">
<h3 class="text-lg @md:text-xl font-bold">Card Title</h3>
<p class="text-gray-600 @md:mt-2">Card description here.</p>
</div>
</div>
</div>
Bài tập 6: Card component thay đổi layout dựa trên width của chính nó
Yêu cầu: Card khi nằm trong container nhỏ (< 320px) hiển thị dạng dọc (image trên, text dưới). Khi container > 400px (@md), hiển thị dạng ngang (image trái, text phải). Khi > 640px (@lg), có thêm badge, tag, và nút CTA.
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 p-6">
<!-- Column trái: width nhỏ → card dạng dọc -->
<div>
<div class="@container">
<div class="bg-white border rounded-xl overflow-hidden
flex flex-col @md:flex-row
@lg:shadow-lg @lg:hover:shadow-xl @lg:transition-shadow">
<!-- Image -->
<div class="w-full @md:w-2/5 @lg:w-1/3 aspect-video @md:aspect-square bg-gradient-to-br from-violet-400 to-indigo-500 relative">
<!-- Badge chỉ hiện từ @lg -->
<span class="hidden @lg:block absolute top-3 left-3 bg-white/90 text-xs font-bold px-2 py-1 rounded-full backdrop-blur-sm">
Featured
</span>
</div>
<!-- Content -->
<div class="p-4 @md:p-5 @lg:p-6 flex-1 flex flex-col justify-between">
<div>
<!-- Tags chỉ hiện từ @lg -->
<div class="hidden @lg:flex gap-2 mb-2">
<span class="text-xs bg-indigo-50 text-indigo-600 px-2 py-0.5 rounded-full">Design</span>
<span class="text-xs bg-indigo-50 text-indigo-600 px-2 py-0.5 rounded-full">UI/UX</span>
</div>
<h3 class="font-bold text-gray-900 @lg:text-lg">Product Design Principles</h3>
<p class="text-sm text-gray-600 mt-1 @lg:mt-2 line-clamp-2 @lg:line-clamp-3">
Learn how to design better products with proven principles and methodologies
that top companies use every day.
</p>
</div>
<!-- CTA button chỉ hiện từ @lg -->
<button class="hidden @lg:inline-flex mt-3 text-sm font-medium text-indigo-600 hover:text-indigo-700">
Read more →
</button>
</div>
</div>
</div>
</div>
<!-- Column phải: width lớn hơn → card dạng ngang với full feature -->
<div>
<div class="@container">
<div class="bg-white border rounded-xl overflow-hidden
flex flex-col @md:flex-row
@lg:shadow-lg @lg:hover:shadow-xl @lg:transition-shadow">
<!-- Image -->
<div class="w-full @md:w-2/5 @lg:w-1/3 aspect-video @md:aspect-square bg-gradient-to-br from-amber-400 to-orange-500 relative">
<span class="hidden @lg:block absolute top-3 left-3 bg-white/90 text-xs font-bold px-2 py-1 rounded-full backdrop-blur-sm">
Popular
</span>
</div>
<!-- Content -->
<div class="p-4 @md:p-5 @lg:p-6 flex-1 flex flex-col justify-between">
<div>
<div class="hidden @lg:flex gap-2 mb-2">
<span class="text-xs bg-orange-50 text-orange-600 px-2 py-0.5 rounded-full">Development</span>
<span class="text-xs bg-orange-50 text-orange-600 px-2 py-0.5 rounded-full">Frontend</span>
</div>
<h3 class="font-bold text-gray-900 @lg:text-lg">Modern CSS Techniques</h3>
<p class="text-sm text-gray-600 mt-1 @lg:mt-2 line-clamp-2 @lg:line-clamp-3">
Explore modern CSS features including container queries, cascade layers,
and the latest layout techniques for responsive design.
</p>
</div>
<button class="hidden @lg:inline-flex mt-3 text-sm font-medium text-orange-600 hover:text-orange-700">
Read more →
</button>
</div>
</div>
</div>
</div>
</div>
"Media query dựa trên viewport width, phù hợp cho page-level layout (sidebar, header, grid columns). Container query dựa trên width của phần tử cha, phù hợp cho component tái sử dụng — cùng một card component nhưng render khác nhau khi nằm trong sidebar hẹp vs main content rộng. Tailwind v4 hỗ trợ cả hai."
@container-size (v4.3 NEW)
<!-- Định nghĩa container với custom size -->
<div class="@container-size-md">
<!-- Children query dựa trên size này -->
<div class="@md:grid-cols-2">...</div>
</div>
4. Flexbox
Container properties (cha)
| Class | CSS |
|---|---|
flex / inline-flex | display: flex / display: inline-flex |
flex-row / flex-row-reverse | flex-direction: row / row-reverse |
flex-col / flex-col-reverse | flex-direction: column / column-reverse |
flex-wrap / flex-wrap-reverse / flex-nowrap | flex-wrap |
flex-1 / flex-auto / flex-initial / flex-none | flex shorthand |
grow / grow-0 | flex-grow: 1 / flex-grow: 0 |
shrink / shrink-0 | flex-shrink: 1 / flex-shrink: 0 |
basis-* (0..96, auto, full, fractions) | flex-basis |
Justify & Align
| Class | CSS |
|---|---|
justify-normal, justify-start, justify-end, justify-center, justify-between, justify-around, justify-evenly, justify-stretch | justify-content |
justify-items-* | justify-items |
justify-self-* | justify-self |
content-normal, content-start, content-center, content-end, content-between, content-around, content-evenly, content-baseline, content-stretch | align-content |
items-start, items-end, items-center, items-baseline, items-stretch | align-items |
self-auto, self-start, self-end, self-center, self-stretch, self-baseline | align-self |
Order & Gap
| Class | CSS |
|---|---|
order-* (1..12, first, last, none) | order |
gap-* (0..96, px, fractions) | gap |
gap-x-*, gap-y-* | row-gap, column-gap |
Bài tập 7: Centered card (cả ngang và dọc)
Yêu cầu: Canh giữa một card cả chiều ngang và chiều dọc trong viewport.
<div class="min-h-screen flex items-center justify-center bg-gray-100 p-6">
<div class="bg-white rounded-2xl shadow-xl p-8 max-w-md w-full text-center">
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg class="w-8 h-8 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M5 13l4 4L19 7"/>
</svg>
</div>
<h2 class="text-2xl font-bold text-gray-900 mb-2">Thành công!</h2>
<p class="text-gray-600 mb-6">Tài khoản của bạn đã được tạo. Vui lòng kiểm tra email để xác nhận.</p>
<button class="w-full bg-blue-600 text-white py-2.5 rounded-lg hover:bg-blue-700 transition-colors font-medium">
Đi đến Dashboard
</button>
</div>
</div>
flex items-center justify-center trên container + min-h-screen để có full viewport height.Bài tập 8: Holy Grail layout với flexbox
Yêu cầu: Layout kinh điển: header + 3 cột (nav trái, main giữa, aside phải) + footer. Cột giữa co giãn, 2 cột bên fixed width.
<div class="min-h-screen flex flex-col">
<!-- Header -->
<header class="bg-gray-900 text-white px-6 py-4 flex items-center justify-between">
<h1 class="text-xl font-bold">Holy Grail</h1>
<nav class="flex gap-4 text-sm">
<a href="#" class="hover:text-gray-300">Home</a>
<a href="#" class="hover:text-gray-300">About</a>
</nav>
</header>
<!-- Body: 3 cột -->
<div class="flex flex-1">
<!-- Left nav -->
<nav class="w-64 bg-gray-100 p-6 flex-shrink-0">
<h3 class="font-bold mb-4">Navigation</h3>
<ul class="space-y-2">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</nav>
<!-- Main content — flex-1 chiếm hết chỗ còn lại -->
<main class="flex-1 p-6 min-w-0">
<h2 class="text-2xl font-bold mb-4">Main Content</h2>
<p class="text-gray-600">Nội dung chính ở đây. Cột này co giãn theo không gian còn lại.</p>
</main>
<!-- Right aside -->
<aside class="w-72 bg-gray-50 p-6 flex-shrink-0">
<h3 class="font-bold mb-4">Sidebar</h3>
<p class="text-sm text-gray-600">Thông tin phụ.</p>
</aside>
</div>
<!-- Footer -->
<footer class="bg-gray-900 text-gray-400 px-6 py-4 text-center text-sm">
© 2026 Holy Grail Layout. Built with Tailwind CSS v4.
</footer>
</div>
flex flex-col min-h-screen, thân flex flex-1, main content flex-1, side columns w-{value} flex-shrink-0. min-w-0 trên main để tránh overflow.Bài tập 9: Responsive card grid với flex-wrap
Yêu cầu: Grid card dùng flexbox. Card tự xuống dòng khi không đủ chỗ. Mỗi card có min-width, không bóp nhỏ quá.
<div class="flex flex-wrap gap-6 p-6">
<!-- Card 1 -->
<div class="flex-1 min-w-[280px] max-w-sm bg-white rounded-xl shadow-md overflow-hidden">
<div class="h-40 bg-gradient-to-br from-emerald-400 to-teal-500"></div>
<div class="p-4">
<h3 class="font-bold">Card 1</h3>
<p class="text-gray-600 text-sm">Flex item với min-width 280px.</p>
</div>
</div>
<!-- Card 2 -->
<div class="flex-1 min-w-[280px] max-w-sm bg-white rounded-xl shadow-md overflow-hidden">
<div class="h-40 bg-gradient-to-br from-rose-400 to-pink-500"></div>
<div class="p-4">
<h3 class="font-bold">Card 2</h3>
<p class="text-gray-600 text-sm">Tự wrap khi không đủ chỗ.</p>
</div>
</div>
<!-- Card 3 -->
<div class="flex-1 min-w-[280px] max-w-sm bg-white rounded-xl shadow-md overflow-hidden">
<div class="h-40 bg-gradient-to-br from-cyan-400 to-blue-500"></div>
<div class="p-4">
<h3 class="font-bold">Card 3</h3>
<p class="text-gray-600 text-sm">Không cần media query.</p>
</div>
</div>
<!-- Card 4 -->
<div class="flex-1 min-w-[280px] max-w-sm bg-white rounded-xl shadow-md overflow-hidden">
<div class="h-40 bg-gradient-to-br from-violet-400 to-purple-500"></div>
<div class="p-4">
<h3 class="font-bold">Card 4</h3>
<p class="text-gray-600 text-sm">Tự động responsive.</p>
</div>
</div>
<!-- Card 5 -->
<div class="flex-1 min-w-[280px] max-w-sm bg-white rounded-xl shadow-md overflow-hidden">
<div class="h-40 bg-gradient-to-br from-amber-400 to-orange-500"></div>
<div class="p-4">
<h3 class="font-bold">Card 5</h3>
<p class="text-gray-600 text-sm">Flex-wrap + min-width = grid không cần breakpoint.</p>
</div>
</div>
</div>
flex-1 min-w-[280px] — không cần media query, card tự động responsive. Mỗi card rộng ít nhất 280px, co giãn, tự xuống dòng.Bài tập 10: Navigation với logo trái, links phải, dùng justify-between
Yêu cầu: Navbar: logo bên trái, nhóm link bên phải, căn đều 2 đầu.
<nav class="flex items-center justify-between px-8 py-4 bg-white border-b">
<!-- Logo area — bên trái -->
<div class="flex items-center gap-3">
<div class="w-8 h-8 bg-blue-600 rounded-lg"></div>
<span class="font-bold text-lg">Company</span>
</div>
<!-- Links — bên phải, grouped -->
<div class="flex items-center gap-6">
<a href="#" class="text-gray-600 hover:text-gray-900 text-sm font-medium">Products</a>
<a href="#" class="text-gray-600 hover:text-gray-900 text-sm font-medium">Pricing</a>
<a href="#" class="text-gray-600 hover:text-gray-900 text-sm font-medium">Docs</a>
<button class="bg-gray-900 text-white px-4 py-2 rounded-lg text-sm font-medium hover:bg-gray-800">
Sign In
</button>
</div>
</nav>
flex items-center justify-between — logo trái, nav phải. Đây là navbar pattern bạn sẽ viết hàng trăm lần.5. Grid
Grid container
| Class | CSS |
|---|---|
grid / inline-grid | display: grid |
grid-cols-* (1..12, none, subgrid) | grid-template-columns |
grid-rows-* (1..6, none, subgrid) | grid-template-rows |
grid-flow-row / grid-flow-col / grid-flow-dense / grid-flow-row-dense / grid-flow-col-dense | grid-auto-flow |
auto-cols-auto / auto-cols-min / auto-cols-max / auto-cols-fr | grid-auto-columns |
auto-rows-auto / auto-rows-min / auto-rows-max / auto-rows-fr | grid-auto-rows |
Grid item (span)
| Class | CSS |
|---|---|
col-span-* (1..12, full) | grid-column: span N |
col-start-* / col-end-* (1..13, auto) | grid-column-start / end |
row-span-* (1..6, full) | grid-row: span N |
row-start-* / row-end-* (1..7, auto) | grid-row-start / end |
Grid alignment
| Class | CSS |
|---|---|
justify-items-start / end / center / stretch | justify-items |
justify-self-auto / start / end / center / stretch | justify-self |
place-content-* | shorthand align-content + justify-content |
place-items-* | shorthand align-items + justify-items |
place-self-* | shorthand align-self + justify-self |
Ví dụ cơ bản
<!-- Grid 3 cột đều -->
<div class="grid grid-cols-3 gap-4">
<div class="bg-blue-200 p-4">1</div>
<div class="bg-blue-200 p-4">2</div>
<div class="bg-blue-200 p-4">3</div>
</div>
<!-- Span columns -->
<div class="grid grid-cols-4 gap-4">
<div class="col-span-2 bg-green-200 p-4">Span 2</div>
<div class="bg-green-200 p-4">1</div>
<div class="bg-green-200 p-4">1</div>
</div>
<!-- Grid flow dense — fill holes -->
<div class="grid grid-cols-3 grid-flow-dense gap-4">
<div class="col-span-2 bg-purple-200 p-4">Span 2</div>
<div class="bg-purple-200 p-4">3</div>
<div class="bg-purple-200 p-4">4</div>
<div class="bg-purple-200 p-4">5</div>
</div>
<!-- Subgrid (dùng với cha grid) -->
<div class="grid grid-cols-3 gap-4">
<div class="grid grid-cols-subgrid col-span-3 gap-4">
<div class="bg-yellow-200 p-4">Sub 1</div>
<div class="bg-yellow-200 p-4">Sub 2</div>
<div class="bg-yellow-200 p-4">Sub 3</div>
</div>
</div>
Bài tập 11: 12-column grid system
Yêu cầu: Tạo layout 12 cột, các phần tử span với độ rộng khác nhau.
<div class="p-6 space-y-6">
<h2 class="text-xl font-bold mb-4">12-Column Grid System</h2>
<!-- Row 1: 3 cột đều nhau (4+4+4) -->
<div class="grid grid-cols-12 gap-4">
<div class="col-span-4 bg-blue-100 rounded-lg p-4 text-center font-medium text-blue-700">
4 cols
</div>
<div class="col-span-4 bg-blue-100 rounded-lg p-4 text-center font-medium text-blue-700">
4 cols
</div>
<div class="col-span-4 bg-blue-100 rounded-lg p-4 text-center font-medium text-blue-700">
4 cols
</div>
</div>
<!-- Row 2: 8+4 -->
<div class="grid grid-cols-12 gap-4">
<div class="col-span-8 bg-green-100 rounded-lg p-4 text-center font-medium text-green-700">
8 cols — main content
</div>
<div class="col-span-4 bg-green-50 rounded-lg p-4 text-center font-medium text-green-600">
4 cols — sidebar
</div>
</div>
<!-- Row 3: 3+6+3 -->
<div class="grid grid-cols-12 gap-4">
<div class="col-span-3 bg-purple-100 rounded-lg p-4 text-center font-medium text-purple-700">
3 cols
</div>
<div class="col-span-6 bg-purple-100 rounded-lg p-4 text-center font-medium text-purple-700">
6 cols
</div>
<div class="col-span-3 bg-purple-100 rounded-lg p-4 text-center font-medium text-purple-700">
3 cols
</div>
</div>
<!-- Row 4: 2+2+2+2+2+2 -->
<div class="grid grid-cols-12 gap-4">
<div class="col-span-2 bg-orange-100 rounded-lg p-4 text-center font-medium text-orange-700 text-sm">2</div>
<div class="col-span-2 bg-orange-100 rounded-lg p-4 text-center font-medium text-orange-700 text-sm">2</div>
<div class="col-span-2 bg-orange-100 rounded-lg p-4 text-center font-medium text-orange-700 text-sm">2</div>
<div class="col-span-2 bg-orange-100 rounded-lg p-4 text-center font-medium text-orange-700 text-sm">2</div>
<div class="col-span-2 bg-orange-100 rounded-lg p-4 text-center font-medium text-orange-700 text-sm">2</div>
<div class="col-span-2 bg-orange-100 rounded-lg p-4 text-center font-medium text-orange-700 text-sm">2</div>
</div>
</div>
Bài tập 12: Responsive gallery — 1 col mobile, 2 cols tablet, 3 cols desktop
Yêu cầu: Gallery ảnh responsive dùng grid, thay đổi số cột theo breakpoint.
<div class="p-6">
<h2 class="text-xl font-bold mb-4">Responsive Image Gallery</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Item 1 -->
<div class="group relative aspect-square rounded-xl overflow-hidden bg-gray-200">
<div class="absolute inset-0 bg-gradient-to-br from-indigo-400 to-blue-500
flex items-center justify-center text-white text-4xl font-bold">
1
</div>
<div class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100
transition-opacity flex items-center justify-center">
<span class="text-white font-medium">View Image</span>
</div>
</div>
<!-- Item 2 -->
<div class="group relative aspect-square rounded-xl overflow-hidden bg-gray-200">
<div class="absolute inset-0 bg-gradient-to-br from-rose-400 to-pink-500
flex items-center justify-center text-white text-4xl font-bold">
2
</div>
<div class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100
transition-opacity flex items-center justify-center">
<span class="text-white font-medium">View Image</span>
</div>
</div>
<!-- Item 3 -->
<div class="group relative aspect-square rounded-xl overflow-hidden bg-gray-200">
<div class="absolute inset-0 bg-gradient-to-br from-emerald-400 to-teal-500
flex items-center justify-center text-white text-4xl font-bold">
3
</div>
<div class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100
transition-opacity flex items-center justify-center">
<span class="text-white font-medium">View Image</span>
</div>
</div>
<!-- Item 4 -->
<div class="group relative aspect-square rounded-xl overflow-hidden bg-gray-200">
<div class="absolute inset-0 bg-gradient-to-br from-amber-400 to-orange-500
flex items-center justify-center text-white text-4xl font-bold">
4
</div>
<div class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100
transition-opacity flex items-center justify-center">
<span class="text-white font-medium">View Image</span>
</div>
</div>
<!-- Item 5 -->
<div class="group relative aspect-square rounded-xl overflow-hidden bg-gray-200">
<div class="absolute inset-0 bg-gradient-to-br from-violet-400 to-purple-500
flex items-center justify-center text-white text-4xl font-bold">
5
</div>
<div class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100
transition-opacity flex items-center justify-center">
<span class="text-white font-medium">View Image</span>
</div>
</div>
<!-- Item 6 -->
<div class="group relative aspect-square rounded-xl overflow-hidden bg-gray-200">
<div class="absolute inset-0 bg-gradient-to-br from-cyan-400 to-sky-500
flex items-center justify-center text-white text-4xl font-bold">
6
</div>
<div class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100
transition-opacity flex items-center justify-center">
<span class="text-white font-medium">View Image</span>
</div>
</div>
</div>
</div>
grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 — bắt đầu từ 1 cột (mobile), tăng dần. Ghi nhớ: trong Tailwind, breakpoint là min-width — class không prefix = mobile, sm: = >= 640px, lg: = >= 1024px.Bài tập 13: Dashboard layout với sidebar + header + main + widgets
Yêu cầu: Dashboard admin: sidebar trái cố định, header top, main content với grid widgets.
<div class="min-h-screen flex">
<!-- Sidebar — cố định bên trái -->
<aside class="w-64 bg-gray-900 text-white flex-shrink-0 hidden lg:block">
<div class="p-6">
<h2 class="text-lg font-bold mb-8">Admin Panel</h2>
<nav class="space-y-2">
<a href="#" class="flex items-center gap-3 px-3 py-2 rounded-lg bg-gray-800 text-white">
<span class="w-5 h-5 bg-blue-400 rounded"></span> Dashboard
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 transition-colors">
<span class="w-5 h-5 bg-gray-600 rounded"></span> Users
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 transition-colors">
<span class="w-5 h-5 bg-gray-600 rounded"></span> Products
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 transition-colors">
<span class="w-5 h-5 bg-gray-600 rounded"></span> Settings
</a>
</nav>
</div>
</aside>
<!-- Main area -->
<div class="flex-1 min-w-0 bg-gray-50">
<!-- Header -->
<header class="bg-white border-b px-6 py-4 flex items-center justify-between">
<h1 class="text-xl font-bold text-gray-900">Dashboard</h1>
<div class="flex items-center gap-4">
<span class="text-sm text-gray-600">Admin User</span>
<div class="w-8 h-8 bg-gray-300 rounded-full"></div>
</div>
</header>
<!-- Content grid -->
<main class="p-6">
<!-- Stats cards -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
<div class="bg-white rounded-xl p-5 shadow-sm">
<p class="text-sm text-gray-500 mb-1">Total Users</p>
<p class="text-2xl font-bold text-gray-900">12,543</p>
<p class="text-xs text-green-600 mt-1">+12.5% from last month</p>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm">
<p class="text-sm text-gray-500 mb-1">Revenue</p>
<p class="text-2xl font-bold text-gray-900">$45,200</p>
<p class="text-xs text-green-600 mt-1">+8.2% from last month</p>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm">
<p class="text-sm text-gray-500 mb-1">Active Now</p>
<p class="text-2xl font-bold text-gray-900">342</p>
<p class="text-xs text-red-600 mt-1">-3.1% from last hour</p>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm">
<p class="text-sm text-gray-500 mb-1">Conversion</p>
<p class="text-2xl font-bold text-gray-900">3.24%</p>
<p class="text-xs text-green-600 mt-1">+0.4% from last week</p>
</div>
</div>
<!-- Charts & tables area -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
<!-- Main chart — span 2 -->
<div class="lg:col-span-2 bg-white rounded-xl p-5 shadow-sm">
<h3 class="font-bold text-gray-900 mb-4">Revenue Overview</h3>
<div class="h-64 bg-gray-100 rounded flex items-center justify-center text-gray-400">
Chart Area (span 2 columns)
</div>
</div>
<!-- Side widget -->
<div class="bg-white rounded-xl p-5 shadow-sm">
<h3 class="font-bold text-gray-900 mb-4">Recent Activity</h3>
<div class="space-y-3">
<div class="flex gap-3 text-sm">
<div class="w-2 h-2 bg-blue-500 rounded-full mt-1.5 flex-shrink-0"></div>
<p class="text-gray-600">New user registered</p>
</div>
<div class="flex gap-3 text-sm">
<div class="w-2 h-2 bg-green-500 rounded-full mt-1.5 flex-shrink-0"></div>
<p class="text-gray-600">Order #1234 completed</p>
</div>
<div class="flex gap-3 text-sm">
<div class="w-2 h-2 bg-orange-500 rounded-full mt-1.5 flex-shrink-0"></div>
<p class="text-gray-600">Payment pending</p>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 responsive. Charts dùng lg:col-span-2 cho element chiếm 2/3 grid.6. Spacing
Padding
| Class | CSS |
|---|---|
p-* (0..96, px) | padding 4 phía |
px-*, py-* | padding-left + right, padding-top + bottom |
pt-*, pr-*, pb-*, pl-* | padding-top / right / bottom / left |
Margin
| Class | CSS |
|---|---|
m-* (0..96, px, auto) | margin 4 phía |
mx-*, my-* | margin-left + right, top + bottom |
mt-*, mr-*, mb-*, ml-* | margin-top / right / bottom / left |
Logical Properties (v4.2 NEW)
Hỗ trợ layout đa ngôn ngữ (LTR/RTL) — thay vì physical directions:
| Class | CSS | Ghi chú |
|---|---|---|
pbs-*, mbs-* | padding-block-start, margin-block-start | "Top" logic |
pbe-*, mbe-* | padding-block-end, margin-block-end | "Bottom" logic |
pis-*, mis-* | padding-inline-start, margin-inline-start | "Left" logic (start of text direction) |
pie-*, mie-* | padding-inline-end, margin-inline-end | "Right" logic (end of text direction) |
inline-* | Logical inline margin/padding | Shorthand |
block-* | Logical block margin/padding | Shorthand |
<!-- Logical properties: tự động đúng cho mọi ngôn ngữ -->
<div dir="ltr" class="bg-gray-100 p-4 rounded mb-4">
<p class="mis-4 text-gray-700">LTR: mis (margin-inline-start) = margin left</p>
</div>
<div dir="rtl" class="bg-gray-100 p-4 rounded">
<p class="mis-4 text-gray-700">RTL: mis (margin-inline-start) = margin right</p>
</div>
Space Between
| Class | CSS |
|---|---|
space-x-* (> 0) | margin-left cho mỗi child trừ child đầu |
space-y-* (> 0) | margin-top cho mỗi child trừ child đầu |
space-x-reverse, space-y-reverse | Đảo chiều space |
<!-- Dùng space-y cho vertical rhythm -->
<div class="space-y-4">
<p class="bg-blue-100 p-3 rounded">Paragraph 1</p>
<p class="bg-blue-100 p-3 rounded">Paragraph 2</p>
<p class="bg-blue-100 p-3 rounded">Paragraph 3</p>
</div>
<!-- Dùng gap thay thế (khuyến nghị dùng flex/grid) -->
<div class="flex gap-4">
<button class="bg-gray-200 px-4 py-2 rounded">Button 1</button>
<button class="bg-gray-200 px-4 py-2 rounded">Button 2</button>
</div>
Negative Margins & Auto Margins
<!-- Auto margin: đẩy element về phía đối diện -->
<div class="flex bg-gray-200 p-2 rounded">
<span>Left</span>
<span class="ml-auto bg-blue-200 px-2 rounded">Right (ml-auto)</span>
</div>
<!-- Negative margin: kéo element ra ngoài container -->
<div class="bg-gray-100 p-8">
<div class="bg-blue-500 text-white p-4 -mx-4 rounded">
Full-width inside padded container (-mx-4)
</div>
</div>
space-y-* vs gap-*:space-y-* thêm margin-top cho child (chỉ hoạt động khi children là block/inline). gap-* dùng với flex/grid container. Khuyến nghị: luôn dùng gap cho flex/grid, space-y-* chỉ khi children không phải flex/grid item.Bài tập 14: Spacing system cho blog article (consistent vertical rhythm)
Yêu cầu: Bài viết blog với khoảng cách dọc nhất quán giữa các phần tử: heading, paragraph, image, blockquote, list.
<article class="max-w-2xl mx-auto px-6 py-12 space-y-8">
<!-- Title section -->
<header class="space-y-3">
<div class="flex gap-2">
<span class="text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded-full">Technology</span>
<span class="text-xs bg-purple-50 text-purple-600 px-2 py-1 rounded-full">CSS</span>
</div>
<h1 class="text-3xl font-bold text-gray-900 leading-tight">
Building Consistent Spacing Systems with Tailwind CSS
</h1>
<div class="flex items-center gap-3 text-sm text-gray-500">
<div class="w-8 h-8 bg-gray-300 rounded-full"></div>
<span>John Doe</span>
<span>·</span>
<span>July 8, 2026</span>
</div>
</header>
<!-- Intro paragraph -->
<p class="text-lg text-gray-700 leading-relaxed">
A well-designed spacing system is the invisible foundation of every great UI.
In this article, we'll explore how Tailwind CSS v4 helps you maintain consistent
vertical rhythm across your entire layout.
</p>
<!-- Image placeholder -->
<figure class="space-y-2">
<div class="aspect-video bg-gradient-to-br from-slate-400 to-slate-600 rounded-xl flex items-center justify-center text-white text-lg">
Featured Image
</div>
<figcaption class="text-sm text-gray-500 text-center italic">
Figure 1: Consistent spacing makes content more readable.
</figcaption>
</figure>
<!-- Section heading + paragraph -->
<section class="space-y-4">
<h2 class="text-2xl font-bold text-gray-900">Why Spacing Matters</h2>
<p class="text-gray-700 leading-relaxed">
Vertical rhythm creates a predictable reading experience. When headings,
paragraphs, and images all follow the same spacing scale, users can scan
content faster and focus on what matters.
</p>
<p class="text-gray-700 leading-relaxed">
Tailwind's spacing scale (based on 4px increments) ensures every element
aligns to the same baseline grid, eliminating uneven gaps.
</p>
</section>
<!-- Blockquote -->
<blockquote class="border-l-4 border-blue-500 pl-4 py-2 bg-blue-50 rounded-r-lg">
<p class="text-gray-700 italic">
"Design is not just what it looks like and feels like. Design is how it works."
</p>
<footer class="text-sm text-gray-500 mt-2">— Steve Jobs</footer>
</blockquote>
<!-- Bullet list -->
<section class="space-y-3">
<h3 class="text-xl font-bold text-gray-900">Key Principles</h3>
<ul class="space-y-2 list-disc list-inside text-gray-700">
<li>Use multiples of 4px (Tailwind's default scale)</li>
<li>Maintain consistent spacing between same-level elements</li>
<li>Increase spacing before new sections</li>
<li>Keep line-height proportional to font-size</li>
</ul>
</section>
<!-- Conclusion -->
<hr class="border-gray-200">
<p class="text-gray-700 leading-relaxed">
A consistent spacing system is one of the easiest ways to make your designs
look polished and professional. Tailwind CSS v4 makes it effortless.
</p>
</article>
space-y-8 trên container chính (khoảng cách lớn giữa section), space-y-4 cho nội dung trong section (paragraphs, heading nhỏ), space-y-2 cho list/detail. Cấp bậc spacing phản ánh cấp bậc nội dung.Bài tập 15: Card với internal spacing chuẩn (padding + gap)
Yêu cầu: Card sản phẩm có ảnh, tiêu đề, mô tả, giá, và nút. Internal spacing rõ ràng và nhất quán.
<div class="max-w-sm mx-auto bg-white rounded-2xl shadow-lg overflow-hidden">
<!-- Image -->
<div class="aspect-video bg-gradient-to-br from-blue-400 to-indigo-600 relative">
<span class="absolute top-3 left-3 bg-white/90 text-xs font-bold px-2 py-1 rounded-full backdrop-blur-sm">
New Arrival
</span>
</div>
<!-- Content — padding + flex column with gap -->
<div class="p-5 flex flex-col gap-4">
<!-- Title + category -->
<div>
<p class="text-xs font-medium text-indigo-600 uppercase tracking-wide mb-1">Electronics</p>
<h3 class="text-lg font-bold text-gray-900">Wireless Headphones Pro</h3>
</div>
<!-- Description -->
<p class="text-sm text-gray-600 leading-relaxed">
Premium noise-canceling wireless headphones with 30-hour battery life
and spatial audio support.
</p>
<!-- Features (dùng gap thay vì space-y) -->
<div class="flex gap-3">
<span class="text-xs bg-gray-100 text-gray-700 px-2 py-1 rounded-full">ANC</span>
<span class="text-xs bg-gray-100 text-gray-700 px-2 py-1 rounded-full">30h Battery</span>
<span class="text-xs bg-gray-100 text-gray-700 px-2 py-1 rounded-full">Bluetooth 5.3</span>
</div>
<!-- Price + CTA -->
<div class="flex items-center justify-between pt-2 border-t border-gray-100">
<div>
<span class="text-2xl font-bold text-gray-900">$299</span>
<span class="text-sm text-gray-400 line-through ml-2">$399</span>
</div>
<button class="bg-indigo-600 text-white px-4 py-2 rounded-lg text-sm font-medium
hover:bg-indigo-700 transition-colors">
Add to Cart
</button>
</div>
</div>
</div>
p-5 cho padding đều, bên trong flex flex-col gap-4 cho khoảng cách giữa các phần. pt-2 border-t cho separator giữa mô tả và giá — phân tách visual rõ ràng.7. Sizing
Width & Height
| Class | CSS | Ghi chú |
|---|---|---|
w-* (0..96, auto, full, screen, min, max, fit, fractions) | width | |
h-* (0..96, auto, full, screen, min, max, fit, fractions) | height | |
min-w-*, max-w-* | min-width, max-width | |
min-h-*, max-h-* | min-height, max-height | |
size-* | width + height cùng lúc |
Viewport Units
| Class | CSS | Ghi chú |
|---|---|---|
w-screen, h-screen | width: 100vw, height: 100vh | |
min-h-screen | min-height: 100vh | Full height tối thiểu |
h-dvh | height: 100dvh | Dynamic viewport height |
h-svh | height: 100svh | Small viewport height |
h-lvh | height: 100lvh | Large viewport height |
dvh = dynamic viewport height — tự điều chỉnh khi mobile browser bar show/hide. svh = small (bar visible), lvh = large (bar hidden). Dùng dvh cho full-screen layout mobile để tránh bị che bởi browser UI.Logical Sizing (v4.2 NEW)
| Class | CSS |
|---|---|
inline-size-*, block-size-* | inline-size, block-size |
min-inline-size-*, min-block-size-* | min-inline-size, min-block-size |
max-inline-size-*, max-block-size-* | max-inline-size, max-block-size |
Bài tập 16: Full-screen hero section với min-h-screen
Yêu cầu: Hero section full màn hình, nội dung căn giữa, có background gradient, CTA button.
<section class="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900 relative overflow-hidden">
<!-- Decorative background elements -->
<div class="absolute top-20 left-20 w-72 h-72 bg-purple-500/20 rounded-full blur-3xl"></div>
<div class="absolute bottom-20 right-20 w-96 h-96 bg-blue-500/10 rounded-full blur-3xl"></div>
<!-- Content -->
<div class="relative z-10 max-w-3xl mx-auto px-6 text-center">
<span class="inline-block text-sm font-medium text-purple-300 bg-white/10 px-3 py-1 rounded-full mb-6 backdrop-blur-sm">
Tailwind CSS v4 — Now with Oxide Engine
</span>
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold text-white leading-tight mb-6">
Build Faster with
<span class="bg-gradient-to-r from-purple-400 to-pink-400 bg-clip-text text-transparent">
Utility-First CSS
</span>
</h1>
<p class="text-lg text-gray-300 max-w-xl mx-auto mb-8 leading-relaxed">
Tailwind CSS v4 is rebuilt from the ground up with the Oxide Engine in Rust,
delivering 5x faster builds and an all-new CSS-first configuration.
</p>
<div class="flex flex-col sm:flex-row items-center justify-center gap-4">
<button class="w-full sm:w-auto bg-white text-slate-900 px-8 py-3 rounded-xl font-semibold hover:bg-gray-100 transition-colors">
Get Started Free
</button>
<button class="w-full sm:w-auto bg-white/10 text-white px-8 py-3 rounded-xl font-semibold hover:bg-white/20 transition-colors backdrop-blur-sm">
View Docs
</button>
</div>
</div>
<!-- Scroll indicator -->
<div class="absolute bottom-8 left-1/2 -translate-x-1/2 animate-bounce">
<div class="w-6 h-10 border-2 border-white/30 rounded-full flex items-start justify-center p-1.5">
<div class="w-1.5 h-1.5 bg-white/60 rounded-full"></div>
</div>
</div>
</section>
min-h-screen flex items-center justify-center — đảm bảo luôn full viewport. Background gradient + blur decorative circles tạo chiều sâu. max-w-3xl mx-auto giới hạn text width cho readability.Bài tập 17: Image giữ aspect ratio + max-width
Yêu cầu: Container ảnh responsive — ảnh không bị méo, không tràn container, giữ đúng tỉ lệ.
<div class="max-w-2xl mx-auto p-6 space-y-8">
<h2 class="text-xl font-bold">Responsive Image Patterns</h2>
<!-- Pattern 1: Fixed aspect ratio với object-fit -->
<div>
<h3 class="font-medium mb-2">Fixed Aspect Ratio (16:9)</h3>
<div class="aspect-video bg-gray-200 rounded-xl overflow-hidden">
<div class="w-full h-full bg-gradient-to-br from-blue-400 to-purple-500
flex items-center justify-center text-white text-2xl font-bold">
16:9 Image
</div>
</div>
</div>
<!-- Pattern 2: Square (1:1) -->
<div>
<h3 class="font-medium mb-2">Square (1:1)</h3>
<div class="grid grid-cols-3 gap-4">
<div class="aspect-square bg-gray-200 rounded-lg overflow-hidden">
<div class="w-full h-full bg-gradient-to-br from-emerald-400 to-teal-500
flex items-center justify-center text-white font-bold">1:1</div>
</div>
<div class="aspect-square bg-gray-200 rounded-lg overflow-hidden">
<div class="w-full h-full bg-gradient-to-br from-rose-400 to-pink-500
flex items-center justify-center text-white font-bold">1:1</div>
</div>
<div class="aspect-square bg-gray-200 rounded-lg overflow-hidden">
<div class="w-full h-full bg-gradient-to-br from-amber-400 to-orange-500
flex items-center justify-center text-white font-bold">1:1</div>
</div>
</div>
</div>
<!-- Pattern 3: 4:3 aspect ratio -->
<div>
<h3 class="font-medium mb-2">4:3 Aspect Ratio</h3>
<div class="aspect-[4/3] max-w-md bg-gray-200 rounded-xl overflow-hidden">
<div class="w-full h-full bg-gradient-to-br from-indigo-400 to-cyan-500
flex items-center justify-center text-white font-bold text-lg">
4:3
</div>
</div>
</div>
<!-- Pattern 4: Full width, auto height, max-width constraint -->
<div>
<h3 class="font-medium mb-2">Full Width with Max Constraint</h3>
<div class="w-full max-w-lg bg-gray-200 rounded-xl overflow-hidden">
<div class="aspect-video bg-gradient-to-br from-violet-400 to-fuchsia-500
flex items-center justify-center text-white font-bold">
w-full + max-w-lg
</div>
</div>
</div>
</div>
aspect-video= 16:9,aspect-square= 1:1,aspect-[4/3]= custom ratio.w-full max-w-lg= responsive full width nhưng không vượt quá max-width.object-cover+object-centercho ảnh thật (thẻ<img>) để crop thay vì méo.
8. Overflow
| Class | CSS |
|---|---|
overflow-auto | overflow: auto — scrollbar khi cần |
overflow-hidden | overflow: hidden — cắt nội dung |
overflow-clip | overflow: clip — giống hidden nhưng không tạo scroll container |
overflow-visible | overflow: visible |
overflow-scroll | overflow: scroll — luôn có scrollbar |
overflow-x-*, overflow-y-* | Overflow theo trục |
overscroll-auto, overscroll-contain, overscroll-none | overscroll-behavior |
Bài tập 18: Scrollable sidebar với fixed height
Yêu cầu: Sidebar có chiều cao cố định, nội dung bên trong cuộn được.
<div class="flex min-h-screen bg-gray-100">
<!-- Scrollable sidebar -->
<aside class="w-64 bg-white border-r flex flex-col">
<!-- Header sidebar — fixed -->
<div class="p-4 border-b">
<h2 class="font-bold text-gray-900">Channels</h2>
</div>
<!-- Scrollable content -->
<nav class="flex-1 overflow-y-auto p-4 space-y-1">
<!-- 20 channel items — scroll sẽ xuất hiện -->
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg bg-indigo-50 text-indigo-700 font-medium text-sm">
<span class="text-lg">#</span> general
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> random
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> announcements
</a>
<!-- Thêm nhiều items để tạo scroll -->
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> design
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> frontend
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> backend
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> devops
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> help
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> jobs
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> projects
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> resources
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> events
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> feedback
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> mentoring
</a>
<a href="#" class="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 hover:bg-gray-50 font-medium text-sm">
<span class="text-lg">#</span> open-source
</a>
</nav>
<!-- Footer sidebar — fixed -->
<div class="p-4 border-t">
<div class="flex items-center gap-2">
<div class="w-8 h-8 bg-indigo-500 rounded-full"></div>
<span class="text-sm font-medium">User Name</span>
</div>
</div>
</aside>
<!-- Main content -->
<main class="flex-1 p-6">
<h1 class="text-2xl font-bold">Main Content Area</h1>
</main>
</div>
flex flex-col với header (fixed), nav giữa flex-1 overflow-y-auto, footer (fixed). flex-1 làm nav chiếm hết chiều cao còn lại, overflow-y-auto chỉ hiện scrollbar khi nội dung vượt quá.9. Scrollbar Styling (v4.3 NEW)
Tailwind CSS v4.3 thêm built-in scrollbar utilities — không cần plugin riêng nữa.
| Class | CSS | Ghi chú |
|---|---|---|
scrollbar-auto | Scrollbar mặc định của OS | |
scrollbar-thin | Scrollbar mỏng hơn | |
scrollbar-none | Ẩn scrollbar nhưng vẫn scroll được | Cực kỳ hữu ích |
scrollbar-thumb-* | Màu của thumb (phần kéo) | scrollbar-thumb-gray-300 |
scrollbar-track-* | Màu của track (rãnh) | scrollbar-track-gray-100 |
scrollbar-gutter-stable | Dành chỗ cho scrollbar ngay cả khi không scroll | Tránh layout shift |
<!-- Scrollbar mỏng với màu tùy chỉnh -->
<div class="h-48 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-400 scrollbar-track-gray-100 p-4 bg-white rounded-lg">
<p class="text-gray-700">Nội dung cuộn với scrollbar được style...</p>
<!-- nhiều content -->
</div>
<!-- Ẩn scrollbar nhưng vẫn scroll -->
<div class="h-48 overflow-y-auto scrollbar-none p-4 bg-white rounded-lg">
<p class="text-gray-700">Scrollbar bị ẩn nhưng vẫn scroll được bằng touch/swipe/wheel...</p>
</div>
<!-- scrollbar-gutter: tránh layout shift -->
<div class="h-48 overflow-y-auto scrollbar-gutter-stable p-4 bg-white rounded-lg">
<p>Dành chỗ cho scrollbar ngay cả khi chưa đủ nội dung để scroll → không bị giật layout.</p>
</div>
Bài tập 19: Custom scrollbar cho chat message list
Yêu cầu: Khung chat với danh sách tin nhắn có scrollbar tùy chỉnh — mỏng, màu phù hợp theme, gutter stable.
<div class="max-w-md mx-auto bg-white rounded-2xl shadow-lg overflow-hidden flex flex-col" style="height: 500px;">
<!-- Chat header -->
<div class="px-5 py-4 border-b flex items-center gap-3">
<div class="w-10 h-10 bg-gradient-to-br from-blue-400 to-indigo-500 rounded-full flex items-center justify-center text-white font-bold">
A
</div>
<div>
<h3 class="font-semibold text-gray-900">Alice Nguyen</h3>
<p class="text-xs text-green-500">Online</p>
</div>
</div>
<!-- Message list — scrollable với custom scrollbar -->
<div class="flex-1 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-300
scrollbar-track-transparent scrollbar-gutter-stable
hover:scrollbar-thumb-gray-400 transition-colors
px-5 py-4 space-y-4">
<!-- Received message -->
<div class="flex gap-3">
<div class="w-8 h-8 bg-gray-300 rounded-full flex-shrink-0 mt-1"></div>
<div class="bg-gray-100 rounded-2xl rounded-tl-sm px-4 py-2.5 max-w-[75%]">
<p class="text-sm text-gray-800">Chào bạn! Khóa học Tailwind CSS v4 thế nào rồi?</p>
<span class="text-xs text-gray-400 mt-1 block">10:30 AM</span>
</div>
</div>
<!-- Sent message -->
<div class="flex gap-3 justify-end">
<div class="bg-blue-600 text-white rounded-2xl rounded-tr-sm px-4 py-2.5 max-w-[75%]">
<p class="text-sm">Rất hay! Đang học phần Layout & Spacing. Container queries mới cực kỳ hữu ích.</p>
<span class="text-xs text-blue-200 mt-1 block">10:31 AM</span>
</div>
<div class="w-8 h-8 bg-blue-500 rounded-full flex-shrink-0 mt-1"></div>
</div>
<!-- Received message 2 -->
<div class="flex gap-3">
<div class="w-8 h-8 bg-gray-300 rounded-full flex-shrink-0 mt-1"></div>
<div class="bg-gray-100 rounded-2xl rounded-tl-sm px-4 py-2.5 max-w-[75%]">
<p class="text-sm text-gray-800">Tuyệt! Phần scrollbar mới trong v4.3 cũng rất đáng học. Để mình gửi link docs cho.</p>
<span class="text-xs text-gray-400 mt-1 block">10:32 AM</span>
</div>
</div>
<!-- Sent message 2 -->
<div class="flex gap-3 justify-end">
<div class="bg-blue-600 text-white rounded-2xl rounded-tr-sm px-4 py-2.5 max-w-[75%]">
<p class="text-sm">Cảm ơn bạn! Để mình xem thử.</p>
<span class="text-xs text-blue-200 mt-1 block">10:33 AM</span>
</div>
<div class="w-8 h-8 bg-blue-500 rounded-full flex-shrink-0 mt-1"></div>
</div>
<!-- Tin nhắn dài tạo scroll -->
<div class="flex justify-center">
<span class="text-xs text-gray-400 bg-gray-50 px-3 py-1 rounded-full">Hôm nay</span>
</div>
<!-- Received message 3 -->
<div class="flex gap-3">
<div class="w-8 h-8 bg-gray-300 rounded-full flex-shrink-0 mt-1"></div>
<div class="bg-gray-100 rounded-2xl rounded-tl-sm px-4 py-2.5 max-w-[75%]">
<p class="text-sm text-gray-800">À, bài tập trong tài liệu — nhớ làm hết nhé! Mỗi bài đều có pattern thực tế áp dụng được ngay.</p>
<span class="text-xs text-gray-400 mt-1 block">10:35 AM</span>
</div>
</div>
<!-- Sent message 3 -->
<div class="flex gap-3 justify-end">
<div class="bg-blue-600 text-white rounded-2xl rounded-tr-sm px-4 py-2.5 max-w-[75%]">
<p class="text-sm">Yes sir! Đang làm đến bài tập 19 luôn nè.</p>
<span class="text-xs text-blue-200 mt-1 block">10:36 AM</span>
</div>
<div class="w-8 h-8 bg-blue-500 rounded-full flex-shrink-0 mt-1"></div>
</div>
<!-- Received message 4 -->
<div class="flex gap-3">
<div class="w-8 h-8 bg-gray-300 rounded-full flex-shrink-0 mt-1"></div>
<div class="bg-gray-100 rounded-2xl rounded-tl-sm px-4 py-2.5 max-w-[75%]">
<p class="text-sm text-gray-800">Good job! Học xong phần này là master layout Tailwind rồi. Tiếp theo là Typography & Colors nhé!</p>
<span class="text-xs text-gray-400 mt-1 block">10:37 AM</span>
</div>
</div>
</div>
<!-- Input area -->
<div class="px-5 py-4 border-t flex gap-3">
<input type="text" placeholder="Nhập tin nhắn..."
class="flex-1 bg-gray-100 rounded-full px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-colors">
<button class="bg-blue-600 text-white w-10 h-10 rounded-full flex items-center justify-center hover:bg-blue-700 transition-colors flex-shrink-0">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</button>
</div>
</div>
scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-transparent — scrollbar trong suốt hòa vào nền, chỉ thấy thumb. hover:scrollbar-thumb-gray-400 làm thumb đậm hơn khi hover để dễ nhìn. scrollbar-gutter-stable tránh layout shift khi scrollbar xuất hiện.Tổng kết
Bạn đã học qua 9 nhóm utility cho layout và spacing trong Tailwind CSS v4, kèm 19 bài tập thực hành:
- Display (Bài tập 1-2): Navigation bar, sidebar toggle
- Position (Bài tập 3-5): Fixed header, sticky sidebar, absolute badge
- Container Queries (Bài tập 6): Card responsive theo width của chính nó
- Flexbox (Bài tập 7-10): Centered card, Holy Grail, flex-wrap grid, navbar
- Grid (Bài tập 11-13): 12-column system, responsive gallery, dashboard
- Spacing (Bài tập 14-15): Blog vertical rhythm, card internal spacing
- Sizing (Bài tập 16-17): Hero section, responsive images
- Overflow (Bài tập 18): Scrollable sidebar
- Scrollbar (Bài tập 19): Chat message list custom scrollbar
"Tôi kết hợp flexbox cho page-level layout (sidebar + main content), grid cho content-area layout (stats cards, charts), container queries cho component tái sử dụng (card thay đổi trong các ngữ cảnh khác nhau). Mobile-first responsive: bắt đầu với mobile layout, thêm
sm:,md:,lg:để enhance khi màn hình lớn hơn. Pattern hay dùng:flex min-h-screencho app shell,grid-cols-1 sm:grid-cols-2 lg:grid-cols-4cho card grid,sticky top-24cho sidebar trong blog."
Tailwind CSS
Học Tailwind CSS v4.3 (2026) — Oxide Engine, CSS-first config, OKLCH colors, container queries, 3D transforms. Từ cơ bản đến practical.
2. Typography & Colors
Tailwind CSS v4 — font, text, color (OKLCH), background, gradient, border, outline. Bài tập thiết kế typography system và color palette.