Bài 9.3: So sánh Flexbox và CSS Grid

Bài 9.3: So sánh Flexbox và CSS Grid
Chào mừng trở lại với series blog của chúng ta! Trong thế giới phát triển web hiện đại, việc tạo ra các layout linh hoạt và responsive là điều thiết yếu. Để làm được điều này một cách hiệu quả, CSS cung cấp cho chúng ta hai công cụ layout cực kỳ mạnh mẽ: Flexbox và CSS Grid.
Mặc dù cả hai đều giúp chúng ta sắp xếp các phần tử trên trang, chúng lại có những mục đích và cách hoạt động rất khác nhau. Việc hiểu rõ sự khác biệt này là chìa khóa để bạn có thể chọn đúng công cụ cho đúng công việc, giúp code sạch hơn, dễ bảo trì hơn và responsive tốt hơn.
Trong bài viết này, chúng ta sẽ cùng mổ xẻ Flexbox và CSS Grid, so sánh chúng trên nhiều khía cạnh để bạn có cái nhìn toàn diện nhất.
Flexbox: Bố cục một chiều (One-Dimensional Layout)
Flexbox, hay Flexible Box Module, được thiết kế để giúp chúng ta sắp xếp, căn chỉnh và phân phối không gian giữa các phần tử trong một container dọc theo một chiều duy nhất (hoặc là một hàng hoặc là một cột).
Hãy hình dung Flexbox như việc sắp xếp các món đồ trên một kệ sách dài (hàng) hoặc xếp chồng các hộp lên nhau (cột). Bạn có thể dễ dàng căn giữa chúng, dồn chúng về một phía, hay làm cho chúng giãn ra để lấp đầy không gian còn trống.
Flexbox cực kỳ tuyệt vời cho các thành phần UI (User Interface) nhỏ đến trung bình, chẳng hạn như:
- Thanh điều hướng (navigation bar).
- Các phần tử trong form (nhãn, input, button).
- Header hoặc footer của card.
- Phân phối không gian giữa các nút bấm.
- Căn giữa một phần tử con duy nhất trong container mẹ.
Các khái niệm cốt lõi trong Flexbox xoay quanh hai trục: trục chính (main axis) và trục phụ (cross axis). Trục chính được xác định bởi thuộc tính flex-direction
(mặc định là row
- hàng), còn trục phụ vuông góc với trục chính.
Để sử dụng Flexbox, bạn chỉ cần đặt thuộc tính display: flex
cho container chứa các phần tử bạn muốn sắp xếp (gọi là flex container). Các phần tử con trực tiếp bên trong container đó sẽ trở thành flex items.
Ví dụ đơn giản về Flexbox: Căn giữa một div con bên trong div mẹ.
<div class="flex-container">
<div class="flex-item">Tôi được căn giữa!</div>
</div>
.flex-container {
display: flex; /* Biến container này thành flex container */
justify-content: center; /* Căn chỉnh flex items theo trục chính (ngang) */
align-items: center; /* Căn chỉnh flex items theo trục phụ (dọc) */
height: 200px; /* Cần một chiều cao để thấy căn giữa dọc */
border: 1px solid #ccc;
font-size: 1.2em;
}
.flex-item {
padding: 30px;
background-color: #ffcc80; /* Màu nền đẹp mắt */
color: #333;
border-radius: 8px; /* Bo góc nhẹ nhàng */
box-shadow: 2px 2px 5px rgba(0,0,0,0.2); /* Thêm đổ bóng */
}
Giải thích:
.flex-container
được đặtdisplay: flex
để kích hoạt chế độ Flexbox.justify-content: center
sẽ đưa.flex-item
về giữa theo trục chính (mặc định là hàng ngang).align-items: center
sẽ đưa.flex-item
về giữa theo trục phụ (trục dọc trong trường hợp này).- Chúng ta thêm
height
cho container để có không gian choalign-items
hoạt động hiệu quả theo chiều dọc.
CSS Grid: Bố cục hai chiều (Two-Dimensional Layout)
Ngược lại với Flexbox, CSS Grid được thiết kế để xử lý bố cục hai chiều (cả hàng và cột) cùng một lúc. Hãy nghĩ về Grid như một tờ giấy kẻ ô ly hoặc một bảng tính. Bạn có thể định nghĩa các đường kẻ (grid lines) để tạo ra các ô (grid cells), và sau đó đặt các phần tử vào bất kỳ ô hoặc khu vực nào bạn muốn trên lưới đó.
Grid là công cụ hoàn hảo để xây dựng các bố cục tổng thể của trang web (maco-layout), chẳng hạn như:
- Cấu trúc trang với header, sidebar, main content, footer.
- Dashboard với nhiều widget được sắp xếp theo một lưới phức tạp.
- Các layout tạp chí hoặc báo chí với nhiều cột và hàng có kích thước khác nhau.
- Tạo ra các hệ thống lưới responsive mạnh mẽ mà không cần sử dụng float hay positioning phức tạp.
Để sử dụng Grid, bạn đặt thuộc tính display: grid
cho container chứa các phần tử (gọi là grid container). Các phần tử con trực tiếp sẽ trở thành grid items. Sự khác biệt lớn nhất là bạn sẽ định nghĩa cấu trúc lưới (số lượng cột, hàng, kích thước của chúng) trực tiếp trên grid container bằng các thuộc tính như grid-template-columns
và grid-template-rows
.
Ví dụ đơn giản về CSS Grid: Tạo một layout lưới 2 cột, 2 hàng.
<div class="grid-container">
<div class="grid-item">Ô 1</div>
<div class="grid-item">Ô 2</div>
<div class="grid-item">Ô 3</div>
<div class="grid-item">Ô 4</div>
</div>
.grid-container {
display: grid; /* Biến container này thành grid container */
grid-template-columns: 1fr 1fr; /* Định nghĩa 2 cột, mỗi cột chiếm 1 phần bằng nhau (fr unit) */
grid-template-rows: auto auto; /* Định nghĩa 2 hàng, chiều cao tự động dựa trên nội dung */
gap: 15px; /* Tạo khoảng cách giữa các ô lưới (hàng và cột) */
border: 1px solid #ccc;
padding: 15px;
font-size: 1.2em;
}
.grid-item {
background-color: #80dfff; /* Màu nền đẹp mắt */
color: #333;
padding: 20px;
text-align: center;
border-radius: 8px; /* Bo góc nhẹ nhàng */
box-shadow: 2px 2px 5px rgba(0,0,0,0.2); /* Thêm đổ bóng */
}
Giải thích:
.grid-container
được đặtdisplay: grid
để kích hoạt chế độ Grid.grid-template-columns: 1fr 1fr
định nghĩa lưới có 2 cột. Đơn vịfr
(fraction) là đơn vị mới trong Grid, thể hiện một phần không gian còn trống.1fr 1fr
nghĩa là hai cột sẽ chia đều không gian có sẵn.grid-template-rows: auto auto
định nghĩa lưới có 2 hàng.auto
nghĩa là chiều cao của hàng sẽ tự động điều chỉnh theo nội dung bên trong ô cao nhất của hàng đó.gap: 15px
tạo khoảng cách 15px giữa tất cả các ô lưới (cả chiều ngang và dọc).
So sánh trực tiếp: Flexbox vs CSS Grid
Bây giờ, hãy đặt chúng cạnh nhau để xem những điểm khác biệt quan trọng nhất:
Sự khác biệt cốt lõi: Một chiều (1D) vs Hai chiều (2D)
- Flexbox: Chỉ hoạt động hiệu quả trên một trục tại một thời điểm (hàng hoặc cột). Tuyệt vời cho việc sắp xếp các phần tử con bên trong một container theo một hướng.
- CSS Grid: Hoạt động trên cả hai trục (hàng và cột) cùng lúc. Cho phép bạn định nghĩa cấu trúc lưới tổng thể và đặt các phần tử vào các vị trí cụ thể trên lưới đó.
Cách tiếp cận: Content-first (Flexbox) vs Layout-first (Grid)
- Flexbox: Thường được coi là "content-first". Nó dựa vào kích thước và số lượng của các flex items để quyết định cách phân phối không gian. Bạn có thể cho phép các item co lại hoặc giãn ra để phù hợp.
- CSS Grid: Thường được coi là "layout-first". Bạn định nghĩa cấu trúc lưới (số cột, số hàng, kích thước) trước khi đặt các grid items vào đó. Điều này cho phép bạn kiểm soát chính xác vị trí và kích thước của các khu vực trên trang bất kể nội dung bên trong chúng là gì.
Khả năng căn chỉnh và phân phối không gian:
- Flexbox: Có các thuộc tính mạnh mẽ (
justify-content
,align-items
,align-self
,gap
) để căn chỉnh và phân phối không gian giữa các items dọc theo trục chính và trục phụ. - CSS Grid: Cũng có các thuộc tính tương tự (
justify-items
,align-items
,justify-content
,align-content
,gap
) nhưng chúng áp dụng cho việc căn chỉnh các items bên trong ô lưới hoặc căn chỉnh toàn bộ lưới bên trong container. Grid cung cấp khả năng kiểm soát vị trí các items chi tiết hơn dựa trên các đường kẻ lưới (grid-column-start
,grid-column-end
,grid-row-start
,grid-row-end
hoặc shorthandgrid-column
,grid-row
,grid-area
).
- Flexbox: Có các thuộc tính mạnh mẽ (
Xử lý khoảng cách:
- Cả hai đều hỗ trợ thuộc tính
gap
(hoặc tiền nhiệmgrid-gap
,column-gap
,row-gap
) để tạo khoảng cách giữa các items/ô. Điều này đơn giản hơn nhiều so với việc sử dụngmargin
trên các items và phải xử lý khoảng cách ở viền ngoài.
- Cả hai đều hỗ trợ thuộc tính
Tính linh hoạt và Responsive:
- Cả hai đều rất tốt cho responsive design.
- Flexbox: Dễ dàng làm cho các item "cuốn chiếu" (
flex-wrap
) xuống hàng/cột mới khi không còn đủ không gian. - CSS Grid: Cho phép bạn định nghĩa lại toàn bộ cấu trúc lưới (số cột, số hàng, vị trí items) chỉ bằng cách thay đổi các thuộc tính trên container hoặc items trong media queries. Điều này cực kỳ mạnh mẽ cho các thay đổi layout lớn giữa các breakpoint. Đơn vị
fr
và hàmrepeat()
,minmax()
trong Grid giúp tạo ra các lưới linh hoạt theo kích thước màn hình một cách dễ dàng.
Độ phức tạp cú pháp:
- Flexbox: Cú pháp tương đối trực quan khi mới bắt đầu, tập trung vào cách các item tương tác trong container.
- CSS Grid: Có thể hơi phức tạp hơn lúc đầu do phải làm quen với việc định nghĩa lưới, các đơn vị mới (
fr
), các khái niệm về đường kẻ lưới (grid lines), và việc đặt items vào các khu vực cụ thể (grid-area
). Tuy nhiên, khi đã quen, nó trở nên cực kỳ mạnh mẽ cho các layout phức tạp.
Khi nào sử dụng loại nào?
Vậy, khi nào thì bạn nên dùng Flexbox, và khi nào nên dùng Grid? Tin tốt là bạn không cần phải chọn một và loại bỏ cái kia! Trên thực tế, chúng thường được sử dụng kết hợp với nhau trong cùng một dự án, thậm chí là lồng ghép vào nhau.
Hãy dùng Flexbox khi:
- Bạn cần sắp xếp các phần tử theo một hàng hoặc một cột.
- Bạn muốn phân phối không gian giữa các items dọc theo một trục.
- Bạn cần căn giữa một item hoặc một nhóm item trong container.
- Bạn đang làm việc với các component UI nhỏ (thanh điều hướng, footer card, form group).
- Bạn muốn các item tự động "cuốn chiếu" xuống hàng mới khi không gian hẹp lại.
Hãy dùng CSS Grid khi:
- Bạn cần định nghĩa cấu trúc layout tổng thể của trang (layout chính).
- Bạn cần sắp xếp các phần tử theo cả hàng và cột cùng lúc.
- Bạn muốn kiểm soát chính xác vị trí của từng phần tử trên lưới (ví dụ: một sidebar cố định ở bên trái, nội dung chính chiếm phần còn lại).
- Bạn đang xây dựng các bố cục phức tạp (dashboard, layout tạp chí).
- Bạn muốn dễ dàng thay đổi cấu trúc layout lớn ở các kích thước màn hình khác nhau.
Sức mạnh thật sự nằm ở sự kết hợp!
Bạn có thể sử dụng CSS Grid để tạo ra cấu trúc layout chính của trang, ví dụ: định nghĩa các khu vực header, main content, sidebar, footer. Sau đó, bên trong khu vực main content
hoặc sidebar
(là một grid item), bạn có thể sử dụng Flexbox để sắp xếp các phần tử con bên trong nó theo một chiều (ví dụ: các card sản phẩm trong khu vực main content được sắp xếp theo hàng bằng Flexbox, hoặc các menu item trong sidebar được xếp theo cột bằng Flexbox).
Ví dụ về việc kết hợp Grid và Flexbox: Một bố cục Grid cơ bản, và một ô Grid sử dụng Flexbox để căn giữa nội dung bên trong nó.
<div class="container-ket-hop">
<header class="header">Header</header>
<aside class="sidebar">Sidebar</aside>
<main class="main">
<div class="flex-inside-grid">
<p>Nội dung được căn giữa bởi Flexbox, nằm trong ô Grid.</p>
</div>
</main>
<footer class="footer">Footer</footer>
</div>
.container-ket-hop {
display: grid; /* Bố cục chính dùng Grid */
grid-template-columns: 200px 1fr; /* Sidebar 200px, Main content chiếm phần còn lại */
grid-template-rows: auto 1fr auto; /* Header tự động, Main chiếm hết chiều cao còn lại, Footer tự động */
grid-template-areas:
"header header"
"sidebar main"
"footer footer"; /* Định nghĩa các khu vực bằng tên */
gap: 10px; /* Khoảng cách giữa các khu vực */
height: 400px; /* Chiều cao mẫu để minh hoạ */
border: 1px solid #ddd;
}
.header { grid-area: header; background-color: #f0f0f0; padding: 10px; text-align: center; }
.sidebar { grid-area: sidebar; background-color: #e0e0e0; padding: 10px; }
.main { grid-area: main; background-color: #d0d0d0; padding: 10px; }
.footer { grid-area: footer; background-color: #f0f0f0; padding: 10px; text-align: center; }
/* Sử dụng Flexbox bên trong một ô Grid (ở đây là .main) */
.flex-inside-grid {
display: flex; /* Container này là Flex container */
justify-content: center; /* Căn giữa nội dung theo chiều ngang */
align-items: center; /* Căn giữa nội dung theo chiều dọc */
height: 100%; /* Quan trọng để align-items center hoạt động hiệu quả trong ô grid */
border: 1px dashed blue;
font-size: 1.1em;
}
Giải thích:
.container-ket-hop
sử dụngdisplay: grid
vàgrid-template-areas
để định nghĩa cấu trúc layout chính của trang (header, sidebar, main, footer).- Mỗi class
.header
,.sidebar
,.main
,.footer
được đặt vào các khu vực tương ứng bằnggrid-area
. Chúng là các grid items. - Bên trong
.main
(một grid item), chúng ta có mộtdiv
khác là.flex-inside-grid
. Div này được đặtdisplay: flex
. justify-content: center
vàalign-items: center
trên.flex-inside-grid
sẽ căn giữa phần tử con bên trong nó (<p>
) theo cả chiều ngang và dọc.- Chúng ta dùng
height: 100%
trên.flex-inside-grid
để nó lấp đầy chiều cao của ô grid.main
, cho phépalign-items: center
căn giữa theo chiều dọc hiệu quả.
Ví dụ này cho thấy cách bạn có thể sử dụng Grid cho cấu trúc lớn và Flexbox cho việc sắp xếp các phần tử nhỏ hơn bên trong các khu vực của lưới.
Comments