Bài viết được sự cho phép của tác giả Lưu Bình An
Một trong những cách đơn giản nhất để tạo masonry layout là dùng flexbox, tất cả những gì cần làm là set flex-flow: column wrap
và height: giá-trị-độ-cao-nào-đó
, là bạn có kiểu layout nổi tiếng của pinterest.
/* hiển thị theo dạng column, rớt dòng khi cần thiết */
.container {
display: flex;
flex-flow: column wrap;
align-content: space-between;
/* fixed height, cao hơn độ cao của item cao nhất */
height: 960px;
}
Cách này bị một vấn đề, thứ tự các item chúng ta sẽ là như thế này
Đây không phải là kết quả chúng ta mong muốn, nó phải xếp các item từ trái qua phải mới hợp gu
Nếu chuyển giá trị flex-direction: row
, thứ tự sẽ đúng như mong muốn, tuy nhiên nó lại bị khoảng trống khi các item có độ cao không đồng nhất, như thế này
Sử dụng kết hợp với 2 thuộc tính :nth-child()
và order
để giải quyết vấn đề này
Column 1 | Column 2 | Column 3 | |
---|---|---|---|
Row 1 | 1 | 2 | 3 |
Row 2 | 4 | 5 | 6 |
Row 3 | 7 | 8 | 9 |
Row 4 | 10 | 11 | 12 |
Chúng ta có 3 cột, chúng ta sẽ xếp các item theo từng cột, nhưng order nó theo hàng
/* sắp xếp lại theo từng dòng */
.item:nth-child(3n+1) { order: 1; }
// set order = 1 cho các item 1, 4, 7, 10,...
.item:nth-child(3n+2) { order: 2; }
// set order = 1 cho các item 2, 5, 8, 11,...
.item:nth-child(3n) { order: 3; }
// set order = 1 cho các item 3, 6, 9, 12,...
Với các item có cùng giá trị order như 1, 4, 7, 10
trình duyệt sẽ render theo thứ tự xuất hiện của html, một cách ngắn gọn với đoạn css trên chúng ta đã xếp các item lại theo thứ tự là 1,4,7,10,2,5,8,11,3,6,9,12
Còn một trường hợp có thể xảy ra là item có độ cao ko fill
hết chỗ trống trong cột, khi ấy nó sẽ dồn item đó về cột phía trước
Để xử trí vụ này, đây là một cái trick khá vi diệu, chúng ta sẽ chèn 2 element before
và after
có giá trị order: 2
để các item sẽ theo thứ tự 1, 4, 7, 10, <break>, 2, 5, 8, 11, <break>, 3, 6, 9, 12
/* bắt buộc chèn vào cột mới */
.container::before,
.container::after {
content: “”;
flex-basis: 100%;
width: 0;
order: 2;
}
Đường màu xám là 2 element before
và after
Toàn bộ source
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
...
</div>
/* hiển thị theo dạng column, rớt dòng khi cần thiết */
.container {
display: flex;
flex-flow: column wrap;
align-content: space-between;
/* fixed height, cao hơn độ cao của item cao nhất */
height: 600px;
}
.item {
width: 32%;
margin-bottom: 2%;
}
/* sắp xếp lại theo từng dòng */
.item:nth-child(3n+1) { order: 1; }
// set order = 1 cho các item 1, 4, 7, 10,...
.item:nth-child(3n+2) { order: 2; }
// set order = 1 cho các item 2, 5, 8, 11,...
.item:nth-child(3n) { order: 3; }
// set order = 1 cho các item 3, 6, 9, 12,...
/* bắt buộc chèn vào cột mới */
.container::before,
.container::after {
content: "";
flex-basis: 100%;
width: 0;
order: 2;
}
Bài viết gốc được đăng tải tại Vui Lập Trình
Có thể bạn quan tâm:
- Sử dụng ellipsis text với flexbox
- Làm chủ CSS Flexbox trong 5 phút
- View Hierarchy, Optimize Layout và Custom View (Phần 1)!
Xem thêm các việc làm Developer hấp dẫn tại TopDev