"Grid hay flexbox?" có câu trả lời ngắn: grid khi bạn sắp xếp theo hàng và cột, flexbox khi bạn xếp các thứ theo một hướng và kích thước của chúng nên do nội dung quyết định. Câu trả lời dài dễ thấy qua bố cục thật hơn là qua quy tắc. Dưới đây là ba bố cục, mỗi cái kèm CSS mà công cụ tạo CSS grid và flexbox viết ra và phép tính trình duyệt thực hiện, để bạn đoán được kết quả trước khi mở DevTools.
Bố cục 1: khung trang với vùng grid
Đầu trang, cột điều hướng, nội dung chính, thanh bên và chân trang. Đây là bố cục hai chiều (đầu trang trải qua mọi cột, các cột bên chiếm một hàng), nên là việc của grid:
.grid {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
gap: 16px;
}
.header { grid-area: header; }
/* ...mỗi vùng một quy tắc */`main` rộng bao nhiêu? fr chia phần còn lại sau các cột cố định và khoảng cách. Trong khung 1.000 px: 1.000 − 200 − 200 − 2 × 16 = 568 px. Trong khung 800 px là 368 px. Các vùng là một bức tranh bố cục đọc được ngay trong CSS, và chuyển thanh bên sang trái chỉ là sửa một chuỗi, không phải sửa HTML.
Trên điện thoại, bạn khai báo lại mẫu trong media query với một cột và các vùng xếp chồng: "header" "main" "nav" "aside" "footer". HTML luôn giữ thứ tự đọc hợp lý, điều quan trọng với người dùng bàn phím và trình đọc màn hình.
Trong Tailwind v4, khung đó là grid grid-cols-[200px_1fr_200px] grid-rows-[auto_1fr_auto] [grid-template-areas:'header_header_header'_'nav_main_aside'_'footer_footer_footer'] gap-4, cho thấy vì sao khung trang thường rõ ràng hơn khi viết CSS thuần.
Bố cục 2: lưới thẻ không cần media query
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
}Trình duyệt xếp được bao nhiêu cột 220 px thì xếp, rồi kéo giãn chúng đều nhau. Số cột là floor((rộng + gap) / (220 + gap)):
| Độ rộng khung | Số cột | Mỗi thẻ |
|---|---|---|
| 1.000 px | floor(1.016 / 236) = 4 | (1.000 − 3 × 16) / 4 = 238 px |
| 700 px | floor(716 / 236) = 3 | (700 − 2 × 16) / 3 ≈ 222,7 px |
| 600 px | floor(616 / 236) = 2 | (600 − 16) / 2 = 292 px |
| 360 px | 1 | 360 px |
Không cần điểm ngắt, và mọi thẻ trong một hàng rộng bằng nhau, điều flexbox với flex-wrap không bảo đảm được: ở đó hàng cuối có hai thẻ sẽ giãn rộng hơn các hàng trên, trừ khi bạn cố định basis và bỏ việc kéo giãn. auto-fit và auto-fill chỉ khác nhau khi số thẻ ít hơn số cột: auto-fit để hai thẻ lấp đầy hàng rộng, auto-fill giữ các cột trống để thẻ vẫn đúng cỡ.
Bố cục 3: thanh công cụ với flexbox
Logo, ô tìm kiếm chiếm phần còn lại, và hai nút. Một hướng, và nút nên rộng vừa nhãn của nó: flexbox.
.toolbar {
display: flex;
align-items: center;
gap: 8px;
}
.search {
flex: 1;
}Phép tính: trong thanh rộng 600 px với logo 100 px và hai nút 80 px, ba khoảng 8 px để lại 600 − 100 − 80 − 80 − 24 = 316 px cho ô tìm kiếm. Dịch nhãn nút sang tiếng Đức, nút dài ra và ô tìm kiếm co lại tương ứng. Kích thước theo nội dung chính là việc flexbox làm tốt.
Hai giá trị flex làm phần lớn công việc, và chúng không giống nhau:
- `flex: 1` là
1 1 0%: các phần tử bắt đầu từ 0 và chia đều không gian. Hai phần tử có nội dung 100 px và 200 px trong hàng 600 px thành 300 px và 300 px. - `flex: auto` là
1 1 auto: các phần tử bắt đầu từ nội dung và chỉ chia phần dư. Hai phần tử đó thành 250 px và 350 px (mỗi cái nhận một nửa của 300 px dư).
flex: 0 0 160px (công cụ viết dạng ba số) là cột cố định 160 px không giãn không co: thanh bên kinh điển cạnh vùng chính flex: 1.
Kết hợp cả hai
Phần lớn trang thật dùng cả hai: grid cho trang và lưới thẻ, flexbox bên trong mỗi thẻ để đẩy nút "Xem thêm" xuống đáy (flex-direction: column cho thẻ, margin-top: auto cho nút), và flexbox cho thanh công cụ. Grid trả lời "hộp này đặt ở đâu?", flexbox trả lời "các hộp này chia một hàng thế nào?".
Các lỗi thường gặp
- Vùng không phải hình chữ nhật.
mainhình chữ L, hoặc một tên dùng ở hai chỗ tách rời, làm cả khai báogrid-template-areasvô hiệu và trình duyệt lặng lẽ bỏ qua. Công cụ không xuất ra và chỉ tên vùng gây lỗi. - `1fr` bị tràn.
1frnghĩa làminmax(auto, 1fr): một URL dài hay bảng rộng bên trong khiến cột không co lại được. Dùngminmax(0, 1fr)hoặcmin-width: 0cho phần tử. - Cùng lỗi đó trong flexbox. Phần tử flex mặc định
min-width: auto, nên chữ dài đẩy hàng rộng hơn màn hình. Thêmmin-width: 0cho phần tử cần co. - Đổi thứ tự nội dung bằng mắt.
ordervàrow-reversedời hộp trên màn hình nhưng không đổi thứ tự phím Tab. Giữ HTML theo thứ tự đọc. - Dùng khoảng cách hai lần. Khi đã có
gaptrên khung, hãy bỏ margin cũ của các phần tử, nếu không khoảng cách ở mép bị gấp đôi.
Thử ngay
Mở công cụ tạo CSS grid và flexbox, chọn mẫu "Lưới thẻ co giãn" và kéo góc khung xem trước: số cột giảm từ bốn xuống một đúng ở các độ rộng trong bảng trên. Sau đó chuyển sang Flexbox và so flex: 1 với flex: auto trên các phần tử có chữ dài ngắn khác nhau. Khi bố cục xong, tạo chiều sâu cho thẻ bằng công cụ tạo box shadow.