Bài 8: Flexbox – Bố cục linh hoạt 1 chiều

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ảiflex-direction: row;
row-reverseItems xếp ngang từ phải sang tráiflex-direction: row-reverse;
columnItems xếp dọc từ trên xuống dướiflex-direction: column;
column-reverseItems xếp dọc từ dưới lên trênflex-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 đầujustify-content: flex-start;
flex-endItems sát cuốijustify-content: flex-end;
centerItems giữa chính giữajustify-content: center;
space-betweenItems cách đều, không có khoảng đầu-cuốijustify-content: space-between;
space-aroundItems cách đều, có khoảng đầu-cuối (bằng nửa)justify-content: space-around;
space-evenlyItems cách đều, khoảng cách bằng nhaujustify-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 containeralign-items: stretch;
flex-startItems sát phía trênalign-items: flex-start;
flex-endItems sát phía dướialign-items: flex-end;
centerItems giữa chính giữaalign-items: center;
baselineItems 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
wrapItems chuyển dòng khi quá rộng
wrap-reverseItems 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 choChức năng
display: flexContainerBật Flexbox
flex-directionContainerHướng sắp xếp (row, column…)
justify-contentContainerSắp xếp theo chiều chính
align-itemsContainerSắp xếp theo chiều vuông góc
gapContainerKhoảng cách giữa items
flex-wrapContainerCó chuyển dòng hay không
flexItemTỷ lệ phân chia không gian
align-selfItemSắ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! 🚀

Để lại bình luận

Email của bạn sẽ không được hiển thị.