Flexbox hay là Flexible Box được dùng để thay thế Floats trong việc thiết kế layout cho trang web. Khi mà float chỉ có khả năng dàn ngang boxes, flexbox sẽ cho chúng ta toàn quyền tùy chỉnh alignment, direction, order, và size của boxes.

Ở bài này chúng ta sẽ tìm hiểu flexbox thông qua những ví dụ, và sau khi hoàn thành chúng ta sẽ được một layout như sau:

Cài đặt

Bắt đầu bằng việc tạo ra file flexbox.html:

<!DOCTYPE html>
<html lang='en'>
  <head>
    <meta charset='UTF-8'/>
    <title>Some Web Page</title>
    <link rel='stylesheet' href='styles.css'/>
  </head>
  <body>
    <div class='menu-container'>
      <div class='menu'>
        <div class='date'>Aug 14, 2016</div>
        <div class='signup'>Sign Up</div>
        <div class='login'>Login</div>
      </div>
    </div>
  </body>
</html>

Sau đó tạo ra file styles.css:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.menu-container {
  color: #fff;
  background-color: #5995DA;  /* Blue */
  padding: 20px 0;
}

.menu {
  border: 1px solid #fff;  /* For debugging */
  width: 900px;
}

Cuối cùng tải các file ảnh, giải nén chúng và đặt trong folder images:

Tổng quan về Flexbox

Trong flexbox có hai khái niệm là flex containersflex items:

Flex containers

Bây giờ chúng ta sẽ thay đổi file styles.css bằng cách thêm thuộc tính display:

.menu-container {
  /* ... */
  display: flex;
}

Mục đích là để cho browser biết chúng ta đang sử dụng flex để xây dựng layout:

Aligning những phần tử flex

.menu-container {
  /* ... */
  display: flex;
  justify-content: center;    /* Add this */
}

Bằng việc định nghĩa justify-content: center chúng ta sẽ cho các items căn giữa theo chiều ngang, nó tương tự như định nghĩa margin: 0 auto vậy.

Các giá trị có thể có của justify-content là:

  • center
  • flex-start
  • flex-end
  • space-around
  • space-between

Phân phối lại các flex items

Chúng ta có thể left/right alignment với floats và căn giữa bằng auto-margins, nhưng flexbox còn có thể layout các items đều nhau trong containers nữa.

Thay đổi .menu trong styles.css:

.menu {
  border: 1px solid #fff;
  width: 900px;
  display: flex;
  justify-content: space-around;
}

Nào, hãy lần lượt thử các giá trị còn lại của justify-content để xem sự khác biệt.

Nhóm các flex items

Bằng cách thêm các thẻ <div> bao bọc những items muốn nhóm chúng ta sẽ đạt được mục đích.

Ví dụ chúng ta muốn có hai links Sign UpLogin gom thành một nhóm, ta tùy chỉnh lại <div class='menu'> như sau:

<div class='menu'>
  <div class='date'>Aug 14, 2016</div>
  <div class='links'>
    <div class='signup'>Sign Up</div>      <!-- This is nested now -->
    <div class='login'>Login</div>         <!-- This one too! -->
  </div>
</div>

Và kết quả sẽ như bên dưới, nhớ lại rằng class .signup.login mặc định sẽ display: block khi container chứa chúng không định nghĩa display: flex.

Thay đổi styles.css để display: flex cho .links :

.links {
  border: 1px solid #fff;  /* For debugging */
  display: flex;
  justify-content: flex-end;
}

.login {
  margin-left: 20px;
}

Tới giờ chúng ta dùng border cho việc debug, ta có thể gỡ chúng đi.

Căn chỉnh ngang-dọc các items

Có hai thuộc tính quan trọng trong flexbox là justify-contentalign-items để căn chỉnh các phần tử con.

Thay đổi flexbox.html:

<div class='header-container'>
  <div class='header'>
    <div class='subscribe'>Subscribe &#9662;</div>
    <div class='logo'><img src='images/awesome-logo.svg'/></div>
    <div class='social'><img src='images/social-icons.svg'/></div>
  </div>
</div>

Tiếp theo align .menu của chúng ta:

.header-container {
  color: #5995DA;
  background-color: #D6E9FE;
  display: flex;
  justify-content: center;
}

.header {
  width: 900px;
  height: 300px;
  display: flex;
  justify-content: space-between;
}

Hãy nhớ rằng justify-content để căn chỉnh theo chiều ngang, và align-items để căn chỉnh theo chiều dọc, thay đổi styles.css như dưới:

.header {
  /* ... */
  align-items: center;  /* Add this */
}

Tương tự justify-content, align-items cũng có những giá trị có thể có như sau, thử đi nào!

  • center
  • flex-start (top)
  • flex-end (bottom)
  • stretch
  • baseline

Thử giá trị align-items: stretch, ta thấy rằng không có sự thay đổi, tuy nhiên, tiếp tục thêm border cho các items để xem điều gì xảy ra.

.header {
  /* ... */
  align-items: stretch;    /* Change this */
}

.social,
.logo,
.subscribe {
  border: 1px solid #5995DA;
}

Wrapping các flex items

Khi số lượng các items nhiều làm tràn giao diện, flex-wrap sẽ thể hiện vai trò của nó.

Một lần nữa thay đổi flexbox.html :

<div class='photo-grid-container'>
  <div class='photo-grid'>
    <div class='photo-grid-item first-item'>
      <img src='images/one.svg'/>
    </div>
    <div class='photo-grid-item'>
      <img src='images/two.svg'/>
    </div>
    <div class='photo-grid-item'>
      <img src='images/three.svg'/>
    </div>
  </div>
</div>

Đối với styles.css :

.photo-grid-container {
  display: flex;
  justify-content: center;
}

.photo-grid {
  width: 900px;
  display: flex;
  justify-content: flex-start;
}

.photo-grid-item {
  border: 1px solid #fff;
  width: 300px;
  height: 300px;
}

Nó sẽ hiển thị tốt, tuy nhiên điều gì xảy ra khi số lượng items lớn hơn 3, thử thêm 2 items nữa xem sao:

<div class='photo-grid-item'>
  <img src='images/four.svg'/>
</div>
<div class='photo-grid-item last-item'>
  <img src='images/five.svg'/>
</div>

Mặc định, chúng sẽ bị tràn ra như thế này:

Sửa lại như thế này nha :

.photo-grid {
  /* ... */
  flex-wrap: wrap;
}

Okie, những items bị tràn đã đẩy xuống dưới, tiếp tục nghịch @@ :

.photo-grid {
  width: 900px;
  display: flex;
  justify-content: center;    /* Change this */
  flex-wrap: wrap;
}

Hai items dưới đã vào giữa :

Hướng của flex container

Mặc định flex-direction trong flex có giá trị là row, cho nên khi thêm display: flex cho container bao bọc chúng, ta thấy các items sẽ lập tức dàn hàng ngang, để chúng dàn hàng dọc thì ta thay đổi flex-direction: column .

.photo-grid {
  /* ... */
  flex-direction: column;
}

Kết quả như thế này, nó sẽ hữu ích trong trường hợp ta muốn responsive cho mobile.

Thuộc tính Alignment

Thay đổi flex-direction: column thì vai trò của justify-contentalign-items sẽ hoán đổi cho nhau.

Thử thay đổi như sau :

.photo-grid {
  /* ... */
  flex-direction: column;
  align-items: center;      /* Add this */
}

Thứ tự của flex container

Đến giờ thứ tự xuất hiện các items sẽ bình thường như thứ tự các thẻ trong file html, chúng ta cũng có thể thay đổi thứ tự này.

.photo-grid {
  width: 900px;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  flex-direction: row-reverse;  /* <--- Really freaking cool! */
  align-items: center;
}

Kết quả :

Thứ tự của flex item

Thứ tự thay đổi theo flex-direction sẽ áp dụng toàn bộ items, ta cũng có thể thứ tự riêng mỗi items nếu muốn.

Thay đổi styles.css :

.photo-grid {
  /* ... */
  flex-direction: row;  /* Update this */
  align-items: center;
}

.first-item {
  order: 1;
}

.last-item {
  order: -1;
}

Alignment cho flex item

Align riêng hai items ứng với class .social.subcribe để chúng nằm bên dưới.

.social,
.subscribe {
  align-self: flex-end;
  margin-bottom: 20px;
}

Kết quả :

Nhắc lại một số giá trị có thể dùng là :

  • center
  • flex-start (top)
  • flex-end (bottom)
  • stretch
  • baseline

Flexible items

Tất cả các ví dụ trên layout các items với kích thước mỗi item là cố định, bây giờ nếu muốn stretch chúng theo container :

Trước tiên, thêm vào file flexbox.html phần footer :

<div class='footer'>
  <div class='footer-item footer-one'></div>
  <div class='footer-item footer-two'></div>
  <div class='footer-item footer-three'></div>
</div>

Thay đổi styles.css :

.footer {
  display: flex;
  justify-content: space-between;
}

.footer-item {
  border: 1px solid #fff;
  background-color: #D6E9FE;
  height: 200px;
  flex: 1;
}

Trong đó, flex: 1 đảm bảo các items sẽ chiếm hết không gian container và kích thước của các items mặc định sẽ bằng nhau.

Ta có thể thay đổi flex cho một item con để thấy chúng có kích thước khác với các item còn lại, chẳng hạn với .footer-three :

.footer-three {
  flex: 2;
}

Thay đổi chiều rộng cho static item


.footer-one,
.footer-three {
  background-color: #5995DA;
  flex: initial;
  width: 300px;
}

Flex items và auto-margins

Thay đổi file .html :

<div class='menu-container'>
  <div class='menu'>
    <div class='date'>Aug 14, 2016</div>
    <div class='signup'>Sign Up</div>
    <div class='login'>Login</div>
  </div>
</div>

và file .css :

.signup {
  margin-left: auto;
}

Tóm lại

  • Dùng display: flex; để tạo ra một flex container.
  • Dùng justify-content để căn ngang các items.
  • Dùng align-items để căn dọc các items.
  • Dùng flex-direction nếu muốn các items theo hướng chiều dọc chứ không phải ngang.
  • Dùng row-reverse hoặc column-reverse để đảo ngược thứ tự mặc định.
  • Dùng order để tùy chỉnh thứ tự một item cụ thể.
  • Dùng align-self để căn dọc một item cụ thể.
  • Dùng flex để tạo ra một flexible boxes có thể stretch và shrink.

Tham khảo

https://internetingishard.com/html-and-css/flexbox/