CSS Flexible Box (Flexbox) đầy đủ nhất :)
Bài đăng này đã không được cập nhật trong 3 năm
Giới thiệu
Trước khi flex xuất hiện, để tạo bố cục cho một trang web ta thường sử dụng kiểu float hoặc table. Tuy nhiên, cả float và table đều có nhiều nhược điểm khiến việc sử dụng không đạt hiệu quả cao. Từ khi flex xuất hiện việc dàn layout trở nên đơn giản rất nhiều. Vậy flex có gì mạnh mẽ mà đến 99,9999% các trang web ngày nay đều sử dụng nó? Chúng ta cùng tìm hiểu đâu nào!
1. Flex Container - Parent Element
Để sử dụng mô hình Flexbox, trước hết ta cần định nghĩa một flex container với cú pháp display: flex
.
Ví dụ với đoạn code dưới ta sẽ được một layout với bố cục như sau:
HTML:
<div class="flex-container">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
CSS:
.flex-container {
display: flex;
background-color: DodgerBlue;
}
.flex-container > div {
background-color: #f1f1f1;
margin: 10px;
padding: 20px;
font-size: 30px;
}
Ở đây, flex container chính là vùng màu xanh với ba flex item.
Các thuộc tính của flex container là:
-
flex-direction: row*|row-reverse|column|column-reverse|initial|inherit;
Xác định hướng của các flex item trong flex container
- row: Giá trị mặc định. Các phần tử sẽ nằm theo chiều ngang (một hàng)
- column: Các phần tử sẽ nằm theo chiều ngang (một cột)
- row-reverse, column-reverse: thứ tự sắp xếp các sẽ đảo ngược so với row và column
-
flex-wrap: nowrap*|wrap|wrap-reverse|initial|inherit
Ý tưởng ban đầu của flexbox là đặt các mục linh hoạt theo một hàng duy nhất. Nhưng sẽ thế nào nếu chúng ta muốn có một bố cục với các mục xếp thành nhiều hàng? Thuộc tính flex-wrap được tạo ra để giúp chúng ta giải quyết điều này.
- nowrap: Giá trị mặc định. Các phần tử được hiển thị trên cùng một hàng, mặc định chúng sẽ tự động dãn hoặc thu hẹp để vừa với chiều rộng của khung lớn.
- wrap: Các phần tử có thể hiển thị nhiều hàng từ trái qua phải và từ trên xuống dưới nếu cần
- wrap-reverse: tương tự như wrap nhưng thứ tự sẽ đảo ngược lại
-
flex-flow: flex-direction flex-wrap|initial|inherit; Thuộc tính này là một dạng viết tắt (shorthand) cho hai thuộc tính flex-direction và flex-wrap.
-
justify-content: flex-start*|flex-end|center|space-between|space-around|space-evenly|initial|inherit;. thuộc tính căn chỉnh các mục của phần tử khi các phần tử không sử dụng hết không gian có sẵn trên "trục chính".
-
flex-start: Giá trị mặc định. Các phần tử sẽ bắt đầu được đặt ở đầu của flex container
-
flex-end: Ngược lại với flex-start, các phần tử sẽ được đặt sao cho phần tử cuối cùng ở cuối cùng của flex container
-
center: Các phần tử sẽ bắt đầu được đặt ở chính giữa của flex container
-
space-between: Giữa các phần tử sẽ có khoảng trống sao và khoảng trống đó sẽ bằng nhau
-
space-around: Các phần tử sẽ có khoảng trống ở đầu, ở giữa các phần tử, và ở sau nó. Như hình bên dưới ta thấy, khoảng cách giữa phần tử 1 và 2, 2 và 3 là bằng nhau và gấp đôi khoảng cách giữa 1 và đầu của flex container.
-
space-evenly: Các phần tử sẽ có khoảng không gian bằng nhau tức là khoảng cách đến flex container cũng như đến các phần tử khác sẽ bằng nhau.
-
-
align-items: stretch*|center|flex-start|flex-end|baseline|initial|inherit; Căn chỉnh theo chiều dọc các mục linh hoạt khi các mục không sử dụng tất cả không gian có sẵn trên trục vuông góc với trục chính
- stretch: Giá trị mặc định. Các phần tử được kéo căng để vừa với flex container. Chiều cao của các phần tử sẽ bằng chiều cao của flex container
- center: Các phần tử được đặt ở chính giữa flex container
- flex-start: Các phần tử được đặt ở đầu flex container
- flex-end: Các phần tử được đặt ở cuối flex container
- baseline: Các phần tử được đặt ở đường cơ sở (baseline) của flex container.
*Giải thích thêm một chút: Theo wikipedia, baseline là: "The line upon which most letters "sit" and below which descenders extend."
Vì vậy nếu các phần tử trong flex container có font-size bằng nhau thì khi sử dụng thuộc tính baseline ta sẽ được kết quả giống với khi sửa dụng flex-start
Các bạn có để ý rằng bên trên mình có dùng một từ là trục chính không? Vâng nó chính là chiều phân bố của các phần tử trong flex container hay chính là thuộc tính flex-direction. Vì vậy nếu flex container có
flex-direction: column
thì thuộc tínhjustify-content
lúc này sẽ giúp căn dọc và ngược lạialign-item
sẽ giúp chúng ta căn ngang -
align-content: stretch*|center|flex-start|flex-end|space-between|space-around|space-evenly|initial|inherit; Thuộc tính align-content thay đổi các hiển thị của thuộc tính flex-wrap. Nó tương tự như align-items, nhưng thay vì căn chỉnh các mục linh hoạt, nó căn chỉnh các đường linh hoạt. Flex container phải có nhiều dòng mục để thuộc tính này có bất kỳ tác dụng nào! Tức là ta phải sử dụng kèm thuộc tính
flex-wrap: wrap;
- stretch: Giá trị mặc định. Các dòng kéo dài để chiếm không gian còn lại
- center: Các dòng được "đóng gói" về phía trung tâm của flex container
- flex-start: Các dòng được "đóng gói" về phía đầu của flex container
- flex-end: Các dòng được "đóng gói" về phía cuối của flex container
- space-between:
- space-around:
- space-evenly:
Ta thấy rằng thuộc tính này khá giống với
justify-content
nhưng phân bố các phân tử theo chiều dọc.
2. Flex Items - Children Element
Các thuộc tính của flex items bao gồm:
-
order: number|initial|inherit; Chỉ định thứ tự của các mục linh hoạt bên trong cùng một flex container. Chú ý một số trình duyệt cần phải sử dụng tiếp đầu ngữ để có thể hoạt động ví dụ với Safari ta cần viết:
-webkit-order: 0
Ví dụ với đoạn code ta sẽ có kết quả như sau:
HTML:
<div id="main"> <div style="background-color:coral;" id="myRedDIV"></div> <div style="background-color:lightblue;" id="myBlueDIV"></div> <div style="background-color:lightgreen;" id="myGreenDIV"></div> <div style="background-color:pink;" id="myPinkDIV"></div> </div>
CSS:
div#myRedDIV {order: 2;} div#myBlueDIV {order: 4;} div#myGreenDIV {order: 3;} div#myPinkDIV {order: 1;}
-
flex-basis: number*|auto|initial|inherit; Xác định độ rộng ban đầu của các phần tử
- auto: Độ rộng của nó sẽ bằng chính độ rộng của content chính nó
- number: Đơn vị độ dài hoặc tỷ lệ phần trăm, chỉ định độ dài ban đầu của (các) phần tử ví dụ:
HTML:
<div id="main"> <div style="background-color:coral;">50px</div> <div style="background-color:lightblue;">100px</div> <div style="background-color:khaki;">50px</div> <div style="background-color:pink;">50px</div> <div style="background-color:lightgrey;">50px</div> </div>
CSS:
#main { width: 300px; height: 100px; border: 1px solid #c3c3c3; display: flex; } #main div { flex-basis: 50px; } #main div:nth-of-type(2) { flex-basis: 100px; }
Tuy nhiên trong một vài trường hợp độ rộng của các phần tử sẽ không bằng giá trị của thuộc tính
flex-basis
. Ví dụHTML:
<div id="main"> <div style="background-color:coral;">50px and more content....................</div> <div style="background-color:lightblue;">100px</div> <div style="background-color:khaki;">50px</div> <div style="background-color:pink;">50px</div> <div style="background-color:lightgrey;">50px</div> </div>
CSS:
#main { width: 300px; height: 100px; border: 1px solid #c3c3c3; display: flex; } #main div { flex-basis: 50px; } #main div:nth-of-type(2) { flex-basis: 100px; }
Ở ví dụ trên ta thấy độ rộng của content thẻ div màu cam lớn hơn 50px nên chiều rộng thẻ div đó sẽ lớn hơn giá trị flex-basis đã được gán. Lúc đó độ rộng của các phần tử khác cũng bị thay đổi chứ không còn bằng đúng giá trị flex-basis đã được gán nữa. Nhưng độ rộng của flex-container vẫn giữ nguyên là 300px. Suy ra, khi tổng chiều rộng của các phần tử con lớn hơn chiều rộng của flex container thì khi đó, các phần tử con sẽ được phân chia lại độ rộng theo một tỉ lệ nào đó. Tỉ lệ đó như nào mình sẽ giải thích trong flex-grow và flex-shrink
-
flex-grow: number|initial|inherit;
- number: Giá trị mặc định là 0. Sẽ chỉ định phần tử đó sẽ tăng bao nhiêu so với phần còn lại của các mục linh hoạt
Ví dụ:
HTML:
<div id="main"> <div style="background-color:coral;">50px</div> <div style="background-color:lightblue;">100px</div> <div style="background-color:khaki;">50px</div> <div style="background-color:pink;">50px</div> <div style="background-color:lightgrey;">50px</div> </div> <div id="main2"> <div style="background-color:coral;">50px</div> <div style="background-color:lightblue;">100px</div> <div style="background-color:khaki;">50px</div> <div style="background-color:pink;">50px</div> <div style="background-color:lightgrey;">50px</div> </div>
CSS:
#main, #main2 { width: 300px; height: 100px; border: 1px solid #c3c3c3; display: flex; } #main div { flex-grow: 0; flex-basis: 50px; } #main2 div { flex-grow: 0; flex-basis: 50px; } #main2 div:nth-of-type(2) { flex-grow: 1; }
Ta thấy ở main2, block màu xanh đã chiếm hết khoảng trống còn thừa của cha nó. Điều gì đã làm điều này xảy ra? Câu trả lời là do block đó có
flex-grow: 1
. Các block khác có giá trị flex-grow là 0 nên block màu xanh sẽ chiếm1 /(0 + 1 + 0 + 0 + 0) = 1
tức là sẽ chiếm toàn bộ khoảng trống còn thừa của element cha. -
flex-shrink: number|initial|inherit; ngược lại với flex-grow. Thuộc tính này này sẽ xác định các phần tử con sẽ bị cắt bớt đi như thế nào nếu độ rộng của element cha nhỏ hơn tổng độ rộng của element con. Giá trị mặc định của nó sẽ là 1. Công thức tính toán như sau
flexBasis * (1 + shrinkFactor / sumScaledShrinkFactors * remainingFreeSpace)
ví dụ:
HTML:
<div class="main"> <div style="background-color:coral;"></div> <div style="background-color:lightblue;"> main1</div> <div style="background-color:khaki;"></div> </div> <div class="main"> <div class="item1" style="background-color:coral;"></div> <div class="item2" style="background-color:lightblue;"> main2</div> <div class="item3" style="background-color:khaki;"></div> </div>
CSS:
.main { width: 300px; height: 100px; border: 1px solid #c3c3c3; display: flex; } .main div { flex-basis: 200px; text-align: center } .main .item1 { flex-basis: 200px; flex-shrink: 2; } .main .item2 { flex-basis: 300px; flex-shrink: 1; } .main .item3 { flex-basis: 400px; flex-shrink: 2; }
Ta bắt tay tính toán độ rộng của các phần tử con nào theo công thức ở trên nào:
- Element của main: 200 * ( 1 + 1 / ( 1 * 200 + 1 * 200 + 1 * 200) * ( 300 - 200 - 200 - 200)) = 100
- Element item3 của main2: 400 * ( 1 + 2 / (2200+ 300 +4002) * (300 - 200 - 300 - 400)) = 80
Kết quả tính toán hoàn toàn chính xác so với kết quả hiển thị thực tế
-
flex: là cách viết ngắn gọn của các thuộc tính flex-grow, flex-shrink, flex-basis: flex: flex-grow flex-shrink flex-basis|auto|initial|inherit;
-
align-self: Chỉ định căn chỉnh theo chiều vuông góc với trục chính cho một phần tử (ghi đè thuộc tính align-items của flex container). Các giá trị tương tự như align-item: auto*|stretch|center|flex-start|flex-end|baseline|initial|inherit;
Ví dụ:
HTML:
<div id="main"> <div style="background-color:coral;">RED</div> <div style="background-color:lightblue;" id="myBlueDiv">BLUE</div> <div style="background-color:lightgreen;">Green div with more content.</div> </div>
CSS:
#main { width: 220px; height: 300px; border: 1px solid black; display: flex; align-items: flex-start; } #main div { flex: 1; } #myBlueDiv { align-self: center; }
Kết
Bài viết đến đây cũng đã dài rồi. Hy vọng nhưng kiến thức mình chia sẽ có thể giúp bạn khi làm CSS. Nếu có góp ý gì xin hãy để lại ở phần bình luận bên dưới. Cảm ơn các bạn rất nhiều.
All rights reserved