Learn CSS Grid Layout in-depth: defining explicit grids with grid-template, the
fr unit, repeat() and minmax(), the responsive auto-fit /
auto-fill pattern, line-based placement with span, and named template areas.
This lesson is currently only available in Vietnamese. Please switch the language toggle in the menu to Vietnamese to read the full guide and take the interactive quiz.
Ở Bài 2, chúng ta đã làm chủ Flexbox — công cụ dàn trang một chiều (theo một trục: hàng hoặc cột). Nhưng khi cần một bố cục thực sự hai chiều — vừa kiểm soát hàng vừa kiểm soát cột cùng lúc, ví dụ layout cả trang web — thì CSS Grid mới là công cụ sinh ra cho việc đó.
CSS Grid Layout là hệ thống bố cục mạnh nhất mà CSS từng có: bạn vẽ ra một mạng lưới các đường (grid lines) tạo thành hàng và cột, rồi đặt từng phần tử con vào các ô (cell) hoặc vùng (area) tùy ý — kể cả cho chúng đè lên nhau hay nhảy cóc qua nhiều ô.
1. Grid Container & Grid Items — tư duy hai chiều
Mọi thứ bắt đầu khi bạn khai báo display: grid (hoặc inline-grid) trên phần
tử cha — nó trở thành Grid Container, và mọi con trực tiếp của nó tự động trở thành
Grid Items. Khác biệt cốt lõi so với Flexbox:
- Flexbox dàn trang theo nội dung (content-first), một chiều mỗi lúc.
- Grid dàn trang theo bố cục (layout-first), hai chiều cùng lúc: bạn định nghĩa cấu trúc lưới trước, rồi xếp nội dung vào.
Grid dùng hệ thống đường lưới (grid lines) được đánh số bắt đầu từ 1. Một lưới có
N cột sẽ có N + 1 đường dọc; tương tự với hàng. Mọi cách đặt vị trí về sau
đều dựa trên các đường này.
2. Định nghĩa lưới tường minh: grid-template & đơn vị fr
Hai thuộc tính trung tâm đặt trên container là grid-template-columns và
grid-template-rows. Chúng liệt kê kích thước của từng rãnh (track):
.container {
display: grid;
/* 3 cột: 200px cố định | phần còn lại | 100px cố định */
grid-template-columns: 200px 1fr 100px;
/* 2 hàng, mỗi hàng cao tối thiểu theo nội dung */
grid-template-rows: auto auto;
gap: 16px; /* khoảng cách giữa các rãnh */
}
Ngôi sao của Grid là đơn vị fr (fraction — phần phân số của không gian còn trống). Sau
khi trừ đi các rãnh có kích thước cố định và khoảng gap, không gian còn lại được chia cho
các rãnh fr theo tỷ lệ:
$$\text{Free Space} = \text{Container Size} - \sum \text{fixed tracks} - \sum \text{gaps}$$ Một rãnh
có hệ số fr nhận được phần không gian: $$\text{Track Size}_i = \text{Free Space} \times
\frac{\text{fr}_i}{\sum \text{fr}}$$
Ví dụ grid-template-columns: 1fr 2fr 1fr chia không gian trống thành 4 phần: cột giữa
rộng gấp đôi hai cột bên (2/4 so với 1/4).
% tính theo toàn bộ kích thước container và không tự trừ đi
gap, nên repeat(3, 33.33%) kèm gap sẽ bị tràn. Còn
fr chia không gian còn lại sau khi đã trừ gap, nên
repeat(3, 1fr) luôn vừa khít. Hãy ưu tiên fr cho lưới co giãn.
Khi có nhiều rãnh lặp lại, dùng hàm repeat() cho gọn:
grid-template-columns: repeat(12, 1fr) tạo ngay một lưới 12 cột kinh điển.
3. Lưới linh hoạt: minmax(), auto-fit & auto-fill
Sức mạnh responsive thật sự của Grid đến từ bộ ba repeat() + auto-fit/auto-fill
+ minmax(). Mẫu dưới đây tạo lưới thẻ tự động xuống dòng mà
không cần một media query nào:
.cards {
display: grid;
/* Mỗi thẻ rộng tối thiểu 220px, tối đa 1fr.
Số cột tự động tính theo bề rộng container. */
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
}
minmax(220px, 1fr) nói: mỗi rãnh không bao giờ nhỏ hơn 220px nhưng có thể giãn tới
1fr. Khi container hẹp lại, số cột vừa được tự giảm; khi rộng ra, số cột tự tăng.
auto-fill
giữ lại các rãnh rỗng ở cuối (các thẻ co về kích thước min, để chừa chỗ trống), còn
auto-fit thu gọn các rãnh rỗng về 0 (các thẻ giãn ra lấp đầy hàng).
Nếu một hàng chỉ có 2 thẻ mà bạn muốn chúng giãn full chiều ngang → dùng auto-fit. Muốn
giữ kích thước cố định và để khoảng trống → dùng auto-fill.
4. Sân chơi tương tác: Grid Sandbox
Hãy tự điều chỉnh số cột, khoảng cách và cách căn lề bên dưới, rồi chọn một ô để cho nó nhảy cóc qua nhiều cột/hàng (span) và xem lưới tự sắp xếp lại trong thời gian thực:
Container Controls
Item Configurator
<div class="container">
<div class="item item-1">Item 1</div>
<div class="item item-2">Item 2</div>
<div class="item item-3">Item 3</div>
<div class="item item-4">Item 4</div>
<div class="item item-5">Item 5</div>
<div class="item item-6">Item 6</div>
</div>
5. Đặt vị trí item theo đường lưới: grid-column & grid-row
Mặc định Grid tự xếp item lần lượt vào từng ô (auto-placement). Nhưng bạn có thể chỉ định chính xác
một item bắt đầu và kết thúc ở đường lưới nào bằng grid-column và grid-row:
.hero {
/* Bắt đầu ở đường cột 1, kết thúc ở đường cột 3 → chiếm 2 cột */
grid-column: 1 / 3;
/* Tương đương cách viết bằng span: */
/* grid-column: 1 / span 2; */
grid-row: 1 / 2;
}
.sidebar {
grid-column: 3 / 4; /* cột cuối */
grid-row: 1 / 3; /* kéo dài qua 2 hàng */
}
Cú pháp start / end nhận số đường lưới; số âm đếm ngược từ cạnh cuối (-1 là
đường cuối cùng), nên grid-column: 1 / -1 nghĩa là "chiếm trọn chiều ngang lưới" — rất
hay dùng cho header.
grid-auto-rows / grid-auto-columns quyết định, và hướng dòng chảy do
grid-auto-flow: row | column | dense điều khiển. Giá trị dense cho phép
Grid "lấp lỗ hổng" bằng cách kéo item nhỏ phía sau lên ô trống phía trước — tiện cho gallery nhưng
có thể làm sai thứ tự đọc (ảnh hưởng accessibility).
6. Bố cục bằng tên vùng: grid-template-areas
Cách trực quan nhất để dựng layout cả trang là vẽ nó bằng chữ. grid-template-areas cho
phép đặt tên cho từng vùng rồi "vẽ" sơ đồ bố cục như một bức tranh ASCII:
.layout {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
gap: 12px;
}
.layout > header { grid-area: header; }
.layout > nav { grid-area: sidebar; }
.layout > main { grid-area: main; }
.layout > footer { grid-area: footer; }
grid-template-areas, bạn có thể sắp xếp lại toàn
bộ trang cho mobile chỉ bằng cách viết lại sơ đồ vùng trong một media query (ví dụ dồn
sidebar xuống dưới main) — không cần đụng tới HTML hay đổi thứ tự thẻ.
Grid và Flexbox không loại trừ nhau — thực tế bạn thường dùng Grid cho bố cục tổng thể của trang và Flexbox để căn chỉnh nội dung bên trong từng ô. Toán ma trận đằng sau các phép sắp đặt không gian này còn được khai thác sâu hơn ở series WebGL — Toán học & Hệ tọa độ.
Trắc nghiệm ôn tập
Câu 1: Với grid-template-columns: 1fr 2fr 1fr và không có rãnh cố định nào khác, cột
giữa chiếm bao nhiêu phần không gian trống?
Trắc nghiệm ôn tập
Câu 2: Bạn muốn các thẻ giãn ra lấp đầy hết chiều ngang khi một hàng còn dư chỗ. Nên dùng từ khóa
nào trong repeat()?
Trắc nghiệm ôn tập
Câu 3: grid-column: 1 / -1 có ý nghĩa gì?