flex-wrap: một dòng, hay bao nhiêu dòng cũng được
Mặc định, một flex container giữ mọi item trên một dòng (flex-wrap: nowrap) và co chúng lại cho vừa. flex-wrap: wrap thì cho chúng giữ kích thước và chuyển xuống dòng tiếp theo:
Mỗi item cần 100px, năm item trong một hộp rộng 340px. Năm item và bốn khoảng gap 8px cần 532px, nên khi không xuống dòng, mỗi item bị ép còn khoảng 62px, vì mặc định flex item sẽ co lại. Với wrap, chúng giữ nguyên 100px: ba item vừa trên dòng đầu và hai item còn lại chuyển xuống dòng thứ hai.
Các giá trị của flex-wrap
| Giá trị | Điều gì xảy ra |
|---|---|
nowrap (mặc định) | Một dòng. Các item co lại, và tràn ra khỏi container khi không co thêm được nữa |
wrap | Các item không vừa sẽ bắt đầu một dòng mới bên dưới |
wrap-reverse | Tương tự, nhưng các dòng mới xếp chồng lên trên: dòng đầu tiên nằm ở dưới cùng |
Xem các item xuống dòng
Kéo thanh trượt để thay đổi chiều rộng của container. Phần hiển thị đếm số dòng và cho biết mỗi dòng có bao nhiêu item:
Ở 400px, bốn item 90px và ba khoảng gap 8px (384px) vừa trên một dòng, nên bạn có 4 + 2. Kéo về phía 620px thì cả sáu item vừa trên một dòng; kéo về phía 120px thì mỗi item chiếm riêng một dòng.
flex-direction: hàng hay cột
flex-direction đặt hướng chạy của các item, đó chính là trục chính:
| Giá trị | Các item chạy | Item đầu tiên |
|---|---|---|
row (mặc định) | cạnh nhau, theo hướng viết | ở đầu dòng |
row-reverse | cạnh nhau, đảo ngược | ở cuối dòng |
column | xếp chồng, từ trên xuống dưới | ở trên cùng |
column-reverse | xếp chồng, từ dưới lên trên | ở dưới cùng |
Trong hai hộp row, các item giãn ra hết chiều cao của hộp, vì align-items: stretch tác động theo chiều ngang của hàng. Trong các hộp column, chúng lại giãn ra hết chiều rộng, cũng vì lý do đó. Các trục đã xoay, và mọi thuộc tính căn chỉnh xoay theo (trang justify-content trình bày chi tiết điều này).
flex-flow: cả hai trong một dòng
flex-flow là cách viết tắt cho flex-direction rồi đến flex-wrap:
.cards { flex-flow: row wrap; } /* flex-direction: row; flex-wrap: wrap; */
.stack { flex-flow: column nowrap; } /* flex-direction: column; flex-wrap: nowrap; */
Thẻ responsive với wrap, không cần media query
Cho mỗi item một kích thước ban đầu bằng flex: 1 1 180px và cho hàng xuống dòng. Mỗi item giãn ra lấp đầy dòng của nó, và khi một dòng không còn chỗ cho thêm một item 180px, item tiếp theo sẽ xuống dòng:
Trong khung xem trước rộng khoảng 800px, ba thẻ vừa trên dòng đầu (mỗi thẻ khoảng 253px) và hai thẻ cuối chia nhau dòng thứ hai, nơi mỗi thẻ giãn ra khoảng 386px. Flexbox hoạt động như vậy: mỗi dòng tự chia khoảng trống của mình, nên các thẻ trên một dòng cuối ngắn sẽ rộng hơn các thẻ phía trên. Nếu bạn muốn thẻ cuối giữ cùng chiều rộng với các thẻ khác, hãy dùng grid với repeat(auto-fill, minmax(180px, 1fr)) (xem trang grid).
align-content: giãn cách giữa các dòng
Khi container xuống dòng và cao hơn tổng các dòng, align-content quyết định các dòng nằm ở đâu. Nó nhận cùng các giá trị như justify-content, cộng thêm stretch:
Trong hộp đầu tiên, cả hai dòng nằm ở trên cùng. Trong hộp thứ hai, dòng đầu ở trên cùng còn dòng thứ hai ở dưới cùng, toàn bộ chiều cao dư nằm giữa chúng.
Thứ tự đảo ngược và khả năng tiếp cận
row-reverse, column-reverse và wrap-reverse chỉ thay đổi vị trí vẽ các item. Trình đọc màn hình và phím Tab vẫn đi theo thứ tự trong HTML, nên người dùng bàn phím sẽ duyệt các item theo hướng ngược với những gì họ thấy. Chỉ đảo ngược để tạo hiệu ứng hiển thị; khi thứ tự mang ý nghĩa, hãy đổi nó trong HTML.
Lỗi thường gặp
- Các item co lại thay vì xuống dòng. Item có
flex: 1bắt đầu từflex-basisbằng 0 và bị ép vào một dòng. Hãy cho chúng một basis thật, ví dụflex: 1 1 200px. - Đặt
flex-wraptrên các item. Nó thuộc về flex container. - Dùng
align-itemsđể giãn cách các dòng đã xuống. Thuộc tính đó căn các item trong mỗi dòng; còn các dòng thì di chuyển bằngalign-content. - Item cuối đứng một mình bị kéo giãn cả hàng. Đó là
flex-growtrên một dòng chỉ có một item. Hãy dùng grid nếu mọi thẻ phải cùng chiều rộng. - Mong
flex-direction: columnlấp đầy một chiều cao. Một container dạng cột chỉ cao bằng nội dung của nó trừ khi bạn đặtheight, nênjustify-contentkhông có chỗ để hoạt động.
Câu hỏi thường gặp
flex-wrap: wrap làm gì?
Nó cho phép các flex item chuyển xuống dòng mới khi không vừa trên một hàng. Với giá trị mặc định nowrap, các item ở lại trên một dòng và co lại, hoặc tràn ra khỏi container nếu không co thêm được nữa.
Vì sao flex-wrap không hoạt động?
Việc xuống dòng chỉ xảy ra khi tổng kích thước ban đầu của các item lớn hơn container. Item có flex: 1 bắt đầu từ flex-basis bằng 0, nên không bao giờ xuống dòng; hãy cho chúng một kích thước ban đầu thật (flex: 1 1 200px hoặc width: 200px). Cũng kiểm tra xem flex-wrap có nằm trên flex container hay không, chứ không phải trên các item.
flex-direction row và column khác nhau thế nào?
row (mặc định) đặt các item cạnh nhau theo hướng viết, còn column xếp chúng từ trên xuống dưới. Trục chính xoay theo, nên trong một cột justify-content hoạt động theo chiều dọc còn align-items theo chiều ngang.
flex-flow là gì?
Cách viết tắt gộp flex-direction và flex-wrap trong một khai báo: flex-flow: row wrap; giống hệt flex-direction: row; flex-wrap: wrap;.
align-items và align-content khác nhau thế nào?
align-items đặt vị trí các item bên trong dòng của chúng. align-content đặt vị trí của chính các dòng bên trong container, nên nó chỉ có tác dụng khi container có flex-wrap: wrap và cao hơn tổng các dòng.