Trước đây, lập trình viên phải dùng float hoặc position để tạo bố cục trang web — rất phức tạp và dễ gây lỗi. May mắn, Flexbox đã giải quyết vấn đề này.
Flexbox (Flexible Box Layout) là một cách dễ dàng, mạnh mẽ để sắp xếp các phần tử theo một chiều (ngang hoặc dọc). Nó giúp bạn tạo các bố cục đẹp mắt, responsive, và dễ bảo trì. Bài này sẽ dạy bạn tất cả những gì cần biết về Flexbox.
Flexbox là gì?
Flexbox là một mô hình bố cục CSS dùng để sắp xếp các phần tử con (items) bên trong một container theo một hoặc hai chiều.
- 🏘️ Flex Container: Phần tử cha (có
display: flex;) - 📦 Flex Items: Phần tử con (những cái được sắp xếp)
<!-- HTML -->
<div class="container"> <!-- Flex Container -->
<div class="item">Item 1</div> <!-- Flex Item -->
<div class="item">Item 2</div> <!-- Flex Item -->
<div class="item">Item 3</div> <!-- Flex Item -->
</div>/* CSS */
.container {
display: flex; /* Bật Flexbox */
background-color: #f0f0f0;
padding: 20px;
}Bước 1: Tạo Flex Container – display: flex
Để sử dụng Flexbox, bạn chỉ cần thêm display: flex; vào phần tử cha.
.container {
display: flex; /* Bật Flexbox */
}
/* Hoặc inline-flex (không chiếm toàn bộ chiều rộng) */
.container {
display: inline-flex;
}Trước và sau khi dùng Flexbox
<!-- HTML (giống nhau) -->
<div class="container">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>/* ❌ Không Flexbox: Items xếp dọc (default) */
.container {
/* Không có display: flex */
}
.item {
width: 100px;
height: 100px;
margin: 10px;
background-color: blue;
}
/* Kết quả: Items xếp dọc, khó kiểm soát */
/* ✅ Flexbox: Items xếp ngang, dễ kiểm soát */
.container {
display: flex; /* Bật Flexbox */
gap: 10px; /* Khoảng cách giữa items */
}
.item {
width: 100px;
height: 100px;
background-color: blue;
}
/* Kết quả: Items xếp ngang, dễ sắp xếp */Flex-direction – Hướng sắp xếp
flex-direction xác định hướng sắp xếp items: ngang (row) hoặc dọc (column).
| Giá trị | Mô tả | Ví dụ |
|---|---|---|
row (mặc định) | Items xếp ngang từ trái sang phải | flex-direction: row; |
row-reverse | Items xếp ngang từ phải sang trái | flex-direction: row-reverse; |
column | Items xếp dọc từ trên xuống dưới | flex-direction: column; |
column-reverse | Items xếp dọc từ dưới lên trên | flex-direction: column-reverse; |
/* Xếp ngang (mặc định) */
.row-layout {
display: flex;
flex-direction: row;
}
/* Xếp dọc */
.column-layout {
display: flex;
flex-direction: column;
}
/* Xếp ngang ngược */
.row-reverse-layout {
display: flex;
flex-direction: row-reverse;
}Justify-content – Sắp xếp theo chiều chính
justify-content sắp xếp items theo chiều chính (ngang nếu flex-direction: row, dọc nếu flex-direction: column).
| Giá trị | Mô tả | Ví dụ |
|---|---|---|
flex-start (mặc định) | Items sát đầu | justify-content: flex-start; |
flex-end | Items sát cuối | justify-content: flex-end; |
center | Items giữa chính giữa | justify-content: center; |
space-between | Items cách đều, không có khoảng đầu-cuối | justify-content: space-between; |
space-around | Items cách đều, có khoảng đầu-cuối (bằng nửa) | justify-content: space-around; |
space-evenly | Items cách đều, khoảng cách bằng nhau | justify-content: space-evenly; |
.flex-start {
display: flex;
justify-content: flex-start;
/* Items: |x x x | */
}
.flex-end {
display: flex;
justify-content: flex-end;
/* Items: | x x x| */
}
.center {
display: flex;
justify-content: center;
/* Items: | x x x | */
}
.space-between {
display: flex;
justify-content: space-between;
/* Items: |x x x| */
}
.space-around {
display: flex;
justify-content: space-around;
/* Items: | x x x | */
}
.space-evenly {
display: flex;
justify-content: space-evenly;
/* Items: | x x x | */
}Align-items – Sắp xếp theo chiều ngang dọc
align-items sắp xếp items theo chiều vuông góc với chiều chính (dọc nếu flex-direction: row, ngang nếu flex-direction: column).
| Giá trị | Mô tả | Ví dụ |
|---|---|---|
stretch (mặc định) | Items kéo giãn để lấp đầy container | align-items: stretch; |
flex-start | Items sát phía trên | align-items: flex-start; |
flex-end | Items sát phía dưới | align-items: flex-end; |
center | Items giữa chính giữa | align-items: center; |
baseline | Items canh theo baseline (chữ) | align-items: baseline; |
.stretch {
display: flex;
height: 300px;
align-items: stretch;
/* Items kéo giãn cao 300px */
}
.flex-start {
display: flex;
height: 300px;
align-items: flex-start;
/* Items sát trên */
}
.center {
display: flex;
height: 300px;
align-items: center;
/* Items giữa chính giữa (dọc) */
}
.flex-end {
display: flex;
height: 300px;
align-items: flex-end;
/* Items sát dưới */
}Gap – Khoảng cách giữa items
gap tạo khoảng cách giữa các items (dễ hơn dùng margin).
.container {
display: flex;
gap: 20px; /* Khoảng cách 20px giữa mỗi item */
}
/* Hoặc riêng từng hướng */
.container {
display: flex;
row-gap: 20px; /* Khoảng cách theo hàng */
column-gap: 30px; /* Khoảng cách theo cột */
}Flex-wrap – Chuyển dòng
flex-wrap xác định có nên chuyển dòng khi items quá rộng hay không.
| Giá trị | Mô tả |
|---|---|
nowrap (mặc định) | Items không chuyển dòng, kéo nhỏ lại nếu cần |
wrap | Items chuyển dòng khi quá rộng |
wrap-reverse | Items chuyển dòng ngược (từ dưới lên trên) |
/* Không chuyển dòng (items kéo nhỏ) */
.no-wrap {
display: flex;
flex-wrap: nowrap;
}
/* Chuyển dòng (items không kéo nhỏ) */
.wrap {
display: flex;
flex-wrap: wrap;
/* Item quá rộng → dòng mới */
}
/* Shorthand: flex-flow */
.container {
display: flex;
flex-flow: row wrap;
/* Tương đương: flex-direction: row; flex-wrap: wrap; */
}Flex items – Thuộc tính cho phần tử con
Ngoài các thuộc tính của container, flex items có thể có các thuộc tính riêng.
Flex – Tỷ lệ phân chia
flex xác định tỷ lệ chiếm dụng không gian của item so với các item khác.
.container {
display: flex;
}
.item1 {
flex: 1; /* Chiếm 1/3 chiều rộng */
}
.item2 {
flex: 1; /* Chiếm 1/3 chiều rộng */
}
.item3 {
flex: 1; /* Chiếm 1/3 chiều rộng */
}
/* Hoặc tỷ lệ khác nhau */
.item1 {
flex: 2; /* Chiếm 2/4 (50%) */
}
.item2 {
flex: 1; /* Chiếm 1/4 (25%) */
}
.item3 {
flex: 1; /* Chiếm 1/4 (25%) */
}Align-self – Sắp xếp riêng của item
align-self cho phép sắp xếp riêng của từng item, ghi đè align-items của container.
.container {
display: flex;
height: 300px;
align-items: center; /* Tất cả items giữa chính giữa */
}
.item3 {
align-self: flex-end; /* Item này sát dưới */
}Ví dụ hoàn chỉnh – Tạo navigation bar và layout
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flexbox Demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Header với navigation -->
<header class="navbar">
<div class="logo">Logo</div>
<nav class="nav-links">
<a href="#">Trang chủ</a>
<a href="#">Dịch vụ</a>
<a href="#">Về chúng tôi</a>
<a href="#">Liên hệ</a>
</nav>
<button class="btn-login">Đăng nhập</button>
</header>
<!-- Hero section -->
<section class="hero">
<h1>Chào mừng bạn đến với Flexbox!</h1>
<p>Tạo bố cục linh hoạt và responsive dễ dàng</p>
</section>
<!-- Main content -->
<main>
<!-- Feature cards -->
<section class="features">
<div class="feature-card">
<h3>Dễ sử dụng</h3>
<p>Flexbox rất dễ học và sử dụng</p>
</div>
<div class="feature-card">
<h3>Responsive</h3>
<p>Tự động điều chỉnh theo màn hình</p>
</div>
<div class="feature-card">
<h3>Mạnh mẽ</h3>
<p>Có thể tạo bất kỳ bố cục nào</p>
</div>
</section>
<!-- Products grid -->
<section class="products">
<h2>Sản phẩm nổi bật</h2>
<div class="product-list">
<div class="product-item">
<img src="product1.jpg" alt="Sản phẩm 1">
<h4>Sản phẩm 1</h4>
<p>Giá: 100,000đ</p>
</div>
<div class="product-item">
<img src="product2.jpg" alt="Sản phẩm 2">
<h4>Sản phẩm 2</h4>
<p>Giá: 200,000đ</p>
</div>
<div class="product-item">
<img src="product3.jpg" alt="Sản phẩm 3">
<h4>Sản phẩm 3</h4>
<p>Giá: 150,000đ</p>
</div>
<div class="product-item">
<img src="product4.jpg" alt="Sản phẩm 4">
<h4>Sản phẩm 4</h4>
<p>Giá: 180,000đ</p>
</div>
</div>
</section>
</main>
<!-- Footer -->
<footer class="footer">
<p>© 2024 Flexbox Demo. Tất cả quyền được bảo lưu.</p>
</footer>
</body>
</html>/* FILE: styles.css */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
}
/* Navbar */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 20px;
background-color: #2c3e50;
color: white;
padding: 15px 30px;
position: sticky;
top: 0;
}
.logo {
font-size: 24px;
font-weight: bold;
}
.nav-links {
display: flex;
gap: 30px;
flex: 1; /* Chiếm không gian còn lại */
}
.nav-links a {
color: white;
text-decoration: none;
font-weight: 500;
transition: color 0.3s;
}
.nav-links a:hover {
color: #3498db;
}
.btn-login {
padding: 8px 20px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
}
/* Hero section */
.hero {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 400px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
text-align: center;
gap: 20px;
}
.hero h1 {
font-size: 48px;
}
.hero p {
font-size: 20px;
opacity: 0.9;
}
/* Feature cards */
.features {
display: flex;
justify-content: space-around;
gap: 20px;
max-width: 1200px;
margin: 60px auto;
padding: 0 20px;
}
.feature-card {
flex: 1;
background-color: #f9f9f9;
padding: 30px;
border-radius: 8px;
text-align: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s;
}
.feature-card:hover {
transform: translateY(-5px);
}
.feature-card h3 {
color: #2c3e50;
margin-bottom: 15px;
}
/* Products section */
.products {
max-width: 1200px;
margin: 60px auto;
padding: 0 20px;
}
.products h2 {
text-align: center;
margin-bottom: 40px;
font-size: 32px;
color: #2c3e50;
}
/* Product list (grid-like with Flexbox) */
.product-list {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
}
.product-item {
flex: 0 1 calc(25% - 15px); /* 4 items per row */
background-color: white;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
text-align: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s;
}
.product-item:hover {
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.product-item img {
width: 100%;
height: 200px;
object-fit: cover;
}
.product-item h4 {
padding: 15px;
color: #2c3e50;
margin-bottom: 10px;
}
.product-item p {
padding: 0 15px 15px;
color: #e74c3c;
font-weight: bold;
font-size: 18px;
}
/* Footer */
.footer {
display: flex;
justify-content: center;
align-items: center;
background-color: #2c3e50;
color: white;
padding: 30px;
text-align: center;
margin-top: 60px;
}
/* Responsive */
@media (max-width: 768px) {
.navbar {
flex-wrap: wrap;
flex-direction: column;
gap: 10px;
}
.nav-links {
flex-direction: column;
width: 100%;
gap: 10px;
}
.features {
flex-direction: column;
}
.product-item {
flex: 0 1 calc(50% - 10px); /* 2 items per row */
}
.hero h1 {
font-size: 32px;
}
}
@media (max-width: 480px) {
.product-item {
flex: 0 1 100%; /* 1 item per row */
}
.hero {
height: 250px;
}
.hero h1 {
font-size: 24px;
}
}Tóm tắt các thuộc tính Flexbox quan trọng
| Thuộc tính | Áp dụng cho | Chức năng |
|---|---|---|
display: flex | Container | Bật Flexbox |
flex-direction | Container | Hướng sắp xếp (row, column…) |
justify-content | Container | Sắp xếp theo chiều chính |
align-items | Container | Sắp xếp theo chiều vuông góc |
gap | Container | Khoảng cách giữa items |
flex-wrap | Container | Có chuyển dòng hay không |
flex | Item | Tỷ lệ phân chia không gian |
align-self | Item | Sắp xếp riêng của item |
Tóm tắt
- ✅ Flexbox: Bố cục 1 chiều linh hoạt, dễ sử dụng
- ✅ Flex Container: Phần tử cha có
display: flex; - ✅ Flex Items: Phần tử con được sắp xếp
- ✅ flex-direction: row, column, row-reverse, column-reverse
- ✅ justify-content: Sắp xếp theo chiều chính
- ✅ align-items: Sắp xếp theo chiều vuông góc
- ✅ gap: Khoảng cách giữa items
- ✅ flex-wrap: Cho phép chuyển dòng
- ✅ flex: Tỷ lệ chiếm không gian của item
- ✅ align-self: Sắp xếp riêng của từng item
🎯 Bài tập thực hành
Bài tập 1: Tạo navigation bar với Flexbox:
- Header chứa: logo (trái), menu links (giữa), button (phải)
- Dùng Flexbox với justify-content: space-between
- Menu links: display flex, gap 20px
- Responsive: trên mobile, chuyển dòng
Bài tập 2: Tạo grid sản phẩm 3 cột với Flexbox:
- Container: display flex, flex-wrap: wrap, gap 20px, justify-content: space-between
- Items: flex: 0 1 calc(33.333% – 14px) (3 items per row)
- Responsive: 2 cột trên tablet (calc(50% – 10px)), 1 cột trên mobile
- Mỗi item có ảnh, tiêu đề, giá, nút mua
Bài tập 3: Tạo footer với 4 cột Flexbox:
- 4 cột: Công ty, Sản phẩm, Hỗ trợ, Liên hệ
- Mỗi cột: flex: 1, gap: 20px, justify-content: space-evenly
- Responsive: 2 cột trên tablet, 1 cột trên mobile
- Header của mỗi cột: fontweight bold, margin-bottom 15px
Chúc bạn thành công! 🚀