Podcast CSS – 010: Flexbox
Một mẫu thiết kế có thể phức tạp trong thiết kế thích ứng là thanh bên nằm cùng dòng với một số nội dung. Nơi có không gian khung nhìn, mẫu này hoạt động rất hiệu quả, nhưng ở nơi không gian được nén lại, bố cục cứng nhắc đó có thể trở thành vấn đề.
Mô hình bố cục hộp linh hoạt (flexbox) là một mô hình bố cục được thiết kế cho nội dung một chiều. Hiệu quả cao khi lấy nhiều đồ vật có kích thước khác nhau, và trả về bố cục phù hợp nhất cho các mục đó.
Đây là mô hình bố cục lý tưởng cho mẫu thanh bên này. Hộp linh hoạt không chỉ giúp bố trí thanh bên và nội dung cùng dòng, nhưng khi không còn đủ dung lượng, thanh bên sẽ ngắt trên một dòng mới. Thay vì đặt các kích thước cố định để trình duyệt tuân theo, với Flexbox, bạn có thể đưa ra các ranh giới linh hoạt để gợi ý cách hiển thị nội dung.
Bạn có thể làm gì với bố cục linh hoạt?
Bố cục của Flex có những tính năng sau, bạn sẽ có thể khám phá nội dung đó trong hướng dẫn này.
- Chúng có thể hiển thị theo hàng hoặc cột.
- Chúng tuân theo chế độ viết của tài liệu.
- Theo mặc định, biểu trưng này là một dòng nhưng có thể cần gói lên nhiều dòng.
- Bạn có thể sắp xếp lại các mục trong bố cục một cách trực quan, khỏi thứ tự của chúng trong DOM.
- Không gian có thể được phân bổ bên trong các mục, để chúng lớn hơn và nhỏ hơn theo không gian có sẵn trong bố mẹ.
- Bạn có thể phân bổ không gian xung quanh các mục và các đường linh hoạt trong một bố cục bao bọc, bằng cách sử dụng thuộc tính Căn chỉnh hộp.
- Các mục có thể được căn chỉnh trên trục chéo.
Trục chính và trục chữ thập
Chìa khoá để tìm hiểu về flexbox là cần nắm được khái niệm về một trục chính và một trục chéo.
Trục chính là trục do thuộc tính flex-direction
đặt.
Nếu đó là row
, trục chính của bạn nằm dọc theo hàng,
nếu là column
, trục chính của bạn sẽ nằm dọc theo cột.
Các mục linh hoạt di chuyển như một nhóm trên trục chính. Hãy nhớ rằng: chúng ta có rất nhiều thứ và đang cố gắng bố cục tốt nhất cho các thành phần đó trong một nhóm.
Trục chéo chạy theo hướng khác với trục chính,
vì vậy, nếu flex-direction
là row
, trục chéo sẽ chạy dọc theo cột.
Bạn có thể thực hiện hai việc trên trục chéo.
Bạn có thể di chuyển các mục riêng lẻ hoặc theo nhóm để các mục này khớp với nhau và linh hoạt
vùng chứa. Ngoài ra, nếu bạn đã gói các đường linh hoạt,
bạn có thể coi những dòng đó là một nhóm để kiểm soát cách chỉ định không gian cho những dòng đó.
Bạn sẽ thấy cách tất cả điều này hoạt động trong thực tế trong suốt hướng dẫn này,
hiện tại, xin lưu ý rằng trục chính sẽ theo sau flex-direction
.
Tạo vùng chứa linh hoạt
Hãy xem cách hoạt động của flexbox bằng cách lấy một nhóm các mục có kích thước khác nhau và dùng flexbox để xếp chúng.
<div class="container" id="container">
<div>One</div>
<div>Item two</div>
<div>The item we will refer to as three</div>
</div>
Để sử dụng Flexbox, bạn cần khai báo rằng bạn muốn sử dụng ngữ cảnh định dạng linh hoạt và không thông thường
bố cục khối và bố cục cùng dòng.
Bạn có thể thực hiện việc này bằng cách thay đổi giá trị của thuộc tính display
thành flex
.
.container {
display: flex;
}
Như bạn đã tìm hiểu trong hướng dẫn bố cục, tuỳ chọn này sẽ cung cấp cho bạn một hộp cấp khối, với thành phần con linh hoạt cho mục. Các mục linh hoạt ngay lập tức bắt đầu cho thấy một số hành vi của hộp linh hoạt, sử dụng giá trị ban đầu của chúng.
Các giá trị ban đầu có nghĩa là:
- Các mục sẽ hiển thị theo hàng.
- Chúng không xuống dòng tự động.
- Chúng không lớn lên để lấp đầy vùng chứa.
- Các tham số này xếp hàng ở đầu vùng chứa.
Kiểm soát hướng của mục
Mặc dù bạn chưa thêm thuộc tính flex-direction
,
các mục được hiển thị dưới dạng hàng vì giá trị ban đầu của flex-direction
là row
.
Nếu muốn thêm một hàng, bạn không cần thêm tài sản.
Để thay đổi hướng, hãy thêm thuộc tính và một trong 4 giá trị:
row
: các mục được bố trí theo hàng.row-reverse:
các mục được bố trí dưới dạng hàng từ cuối vùng chứa linh hoạt.column
: các mục được bố trí dưới dạng cột.column-reverse
: các mục được bố trí dưới dạng cột từ cuối vùng chứa linh hoạt.
Bạn có thể thử tất cả các giá trị bằng cách sử dụng nhóm mục trong bản minh hoạ bên dưới.
Đảo ngược luồng mục và khả năng hỗ trợ tiếp cận
Bạn nên thận trọng khi sử dụng bất kỳ tài sản nào có thể sắp xếp lại giao diện trực quan
khác với cách sắp xếp thứ tự
trong tài liệu HTML,
vì có thể tác động tiêu cực đến khả năng tiếp cận.
Giá trị row-reverse
và column-reverse
là một ví dụ điển hình cho trường hợp này.
Việc sắp xếp lại chỉ xảy ra đối với thứ tự hình ảnh chứ không phải thứ tự logic.
Bạn cần hiểu rõ điều này vì thứ tự logic là thứ tự mà trình đọc màn hình sẽ đọc
nội dung,
và bất kỳ ai điều hướng bằng bàn phím sẽ theo sau.
Bạn có thể xem trong video sau đây cách bố cục hàng đảo ngược, việc di chuyển giữa các đường liên kết bị ngắt kết nối vì việc điều hướng bằng bàn phím đi theo DOM chứ không phải hình ảnh màn hình.
Bất cứ thao tác nào có thể thay đổi thứ tự các mục trong hộp linh hoạt hoặc lưới đều có thể gây ra sự cố này. Do đó, bất kỳ việc sắp xếp lại nào cũng phải bao gồm việc kiểm tra kỹ lưỡng để đảm bảo rằng việc đó không làm cho trang web của bạn khó sử dụng đối với một số người.
Để biết thêm thông tin, hãy xem:
Chế độ và hướng viết
Theo mặc định, các mục Flex được bố trí dưới dạng hàng. Một hàng chạy theo hướng câu lệnh trong chế độ viết và hướng kịch bản. Điều này có nghĩa là nếu bạn làm việc bằng tiếng Ả Rập, có hướng tập lệnh từ phải sang trái (rtl), các mục sẽ thẳng hàng ở bên phải. Thứ tự phím tab cũng sẽ bắt đầu ở bên phải vì đây là cách đọc câu trong tiếng Ả Rập.
Nếu bạn đang dùng chế độ viết dọc,
giống như một số kiểu chữ tiếng Nhật, thì một hàng sẽ chạy theo chiều dọc, từ trên xuống dưới.
Hãy thử thay đổi flex-direction
trong bản minh hoạ đang sử dụng chế độ viết dọc.
Do đó, theo mặc định, các mục linh hoạt hoạt động sẽ được liên kết với chế độ viết của tài liệu. Hầu hết các hướng dẫn được viết bằng tiếng Anh hoặc một ngôn ngữ ngang khác, từ trái sang phải. Điều này sẽ giúp bạn dễ dàng giả định rằng các mục linh hoạt xếp thẳng ở bên trái và chạy theo chiều ngang.
Với trục chính và trục chéo cùng với chế độ viết cần xem xét, mà chúng ta nói về bắt đầu và kết thúc chứ không phải là trên, dưới, bên trái và bên phải trong flexbox có thể dễ hiểu hơn. Mỗi trục có điểm bắt đầu và kết thúc. Điểm bắt đầu của trục chính được gọi là khởi đầu chính. Vì vậy, các mục linh hoạt của chúng ta sẽ được sắp xếp từ đầu đến cuối. Điểm cuối của trục đó là phần đầu. Điểm bắt đầu của trục chéo là bắt đầu chéo và kết thúc kết thúc.
Đóng gói các mục linh hoạt
Giá trị ban đầu của thuộc tính flex-wrap
là nowrap
.
Điều này có nghĩa là nếu không có đủ dung lượng trong vùng chứa thì các mục sẽ bị tràn.
Các mục được hiển thị bằng giá trị ban đầu sẽ thu nhỏ nhất có thể,
giảm xuống kích thước min-content
trước khi tràn.
Để gói các mục, hãy thêm flex-wrap: wrap
vào vùng chứa linh hoạt.
.container {
display: flex;
flex-wrap: wrap;
}
Khi một vùng chứa linh hoạt bao bọc, nó sẽ tạo ra nhiều đường linh hoạt. Về mặt phân bổ theo không gian, mỗi dòng hoạt động như một vùng chứa linh hoạt mới. Do đó, nếu bạn đang gói hàng, không thể lấy mục nào đó ở hàng 2 để thẳng hàng với mục ở trên hàng 1. Điều này nghĩa là flexbox có một chiều. Bạn có thể kiểm soát việc căn chỉnh theo một trục, một hàng hoặc một cột, không thể thực hiện cùng nhau như trong lưới.
Viết tắt Flex-flow
Bạn có thể đặt thuộc tính flex-direction
và flex-wrap
bằng cách sử dụng cách viết tắt flex-flow
.
Ví dụ: để đặt flex-direction
thành column
và cho phép các mục gói:
.container {
display: flex;
flex-flow: column wrap;
}
Kiểm soát không gian bên trong các mục linh hoạt
Giả sử vùng chứa của chúng ta có nhiều không gian hơn mức cần thiết để hiển thị các mục,
các mục hiển thị ngay từ đầu và không tăng lên để lấp đầy chỗ trống.
Kích thước nội dung của các video đó không còn tăng lên nữa.
Điều này là do giá trị ban đầu của thuộc tính flex-
là:
flex-grow: 0
: các mục không tăng trưởng.flex-shrink: 1
: các mục có thể thu nhỏ hơnflex-basis
.flex-basis: auto
: các mục có kích thước cơ sở làauto
.
Giá trị này có thể được biểu thị bằng giá trị từ khoá là flex: initial
.
Thuộc tính viết tắt flex
,
hoặc các giá trị dài của flex-grow
, flex-shrink
và flex-basis
được áp dụng cho phần tử con của
vùng chứa linh hoạt.
Để các mục tăng lên,
còn các mục lớn có nhiều không gian hơn các mục nhỏ thì sử dụng flex:auto
.
Bạn có thể thử cách này bằng bản minh hoạ ở trên.
Thao tác này sẽ đặt các thuộc tính thành:
flex-grow: 1
: các mục có thể lớn hơnflex-basis
.flex-shrink: 1
: các mục có thể thu nhỏ hơnflex-basis
.flex-basis: auto
: các mục có kích thước cơ sở làauto
.
Việc sử dụng flex: auto
có nghĩa là các mục sẽ có các kích thước khác nhau,
vì không gian được chia sẻ giữa các mục được chia sẻ sau khi mỗi mục được bố trí dưới dạng
kích thước nội dung tối đa.
Vì vậy, một mục lớn sẽ có nhiều không gian hơn.
Để buộc tất cả các mục có kích thước nhất quán và bỏ qua thay đổi về kích thước nội dung
flex:auto
thành flex: 1
trong bản minh hoạ.
Thao tác này sẽ giải nén thành:
flex-grow: 1
: các mục có thể lớn hơnflex-basis
.flex-shrink: 1
: các mục có thể thu nhỏ hơnflex-basis
.flex-basis: 0
: các mục có kích thước cơ sở là0
.
Việc sử dụng flex: 1
cho biết rằng tất cả các mục đều có kích thước bằng 0,
do đó tất cả không gian trong vùng chứa linh hoạt đều có sẵn để phân phối.
Vì tất cả các mục đều có hệ số flex-grow
là 1
, nên tất cả các mục đều phát triển như nhau và không gian được chia sẻ như nhau.
Cho phép mặt hàng tăng trưởng ở nhiều tốc độ
Bạn không cần phải cung cấp cho tất cả các mục hệ số flex-grow
là 1
.
Bạn có thể cung cấp nhiều hệ số flex-grow
cho các mục linh hoạt.
Trong bản minh hoạ bên dưới mục đầu tiên có flex: 1
, flex: 2
thứ hai và flex: 3
thứ ba.
Khi các mục này phát triển từ 0
, không gian có sẵn trong vùng chứa linh hoạt sẽ được chia sẻ thành 6.
Một phần được gán cho mục đầu tiên,
hai phần đến phần thứ hai,
vào phần thứ ba.
Bạn có thể làm tương tự với flex-basis
của auto
, mặc dù bạn sẽ cần chỉ định ba thuộc tính
giá trị.
Giá trị đầu tiên là flex-grow
,
flex-shrink
thứ hai,
và flex-basis
thứ ba.
.item1 {
flex: 1 1 auto;
}
.item2 {
flex: 2 1 auto;
}
Đây là một trường hợp sử dụng ít phổ biến hơn làm lý do để sử dụng flex-basis
của auto
là cho phép trình duyệt xác định sự phân phối theo không gian.
Tuy nhiên, nếu bạn muốn làm cho mục tăng thêm một chút so với cách thuật toán quyết định, thì mục đó có thể
hữu ích.
Sắp xếp lại các mục linh hoạt
Bạn có thể sắp xếp lại các mục trong vùng chứa linh hoạt bằng thuộc tính order
.
Tài sản này cho phép sắp xếp các mặt hàng theo các nhóm thứ tự.
Các mục được bố trí theo hướng do flex-direction
chỉ định,
giá trị thấp nhất đầu tiên.
Nếu nhiều mặt hàng có cùng giá trị, thì mặt hàng đó sẽ được hiển thị cùng với các mặt hàng khác cũng có giá trị đó.
Ví dụ bên dưới minh hoạ thứ tự này.
Kiểm tra kiến thức
Kiểm tra kiến thức về flexbox
Mặc định flex-direction
là
row
column
Theo mặc định, một vùng chứa linh hoạt sẽ bao bọc các phần tử con.
flex-wrap: wrap
với display: flex
để gói phần tử conMột mục con linh hoạt có vẻ bị thu nhỏ, thuộc tính linh hoạt nào giúp giảm thiểu điều này?
flex-grow
flex-shrink
flex-basis
Tổng quan về căn chỉnh hộp linh hoạt
Flexbox có một tập hợp các thuộc tính để căn chỉnh các mục và phân phối không gian giữa các mục. Các thuộc tính này rất hữu ích nên giờ đây đã được chuyển vào quy cách riêng, bạn cũng sẽ gặp chúng trong Bố cục lưới. Tại đây, bạn có thể tìm hiểu cách hoạt động của các thành phần này khi sử dụng Flexbox.
Có thể đặt một tập hợp các tài sản thành hai nhóm. Thuộc tính cho việc phân phối không gian và thuộc tính cho việc căn chỉnh. Các thuộc tính phân phối không gian là:
justify-content
: phân phối không gian trên trục chính.align-content
: phân phối không gian trên trục chéo.place-content
: viết tắt để đặt cả hai thuộc tính ở trên.
Các thuộc tính dùng để căn chỉnh trong hộp linh hoạt:
align-self
: căn chỉnh một mục trên trục chéo.align-items
: căn chỉnh tất cả mục thành một nhóm trên trục chéo.
Nếu bạn đang làm việc trên trục chính, thì các thuộc tính sẽ bắt đầu bằng justify-
.
Trên trục chéo, chúng bắt đầu bằng align-
.
Phân bổ không gian trên trục chính
Với HTML được sử dụng trước đó, các mục linh hoạt được bố trí dưới dạng hàng, có khoảng trống trên trục chính.
Các mục không đủ lớn để lấp đầy hoàn toàn vùng chứa linh hoạt.
Các mục được xếp hàng ở đầu vùng chứa linh hoạt vì giá trị ban đầu của justify-content
là flex-start
.
Các mục được sắp xếp ở đầu và mọi khoảng trống thừa sẽ nằm ở cuối.
Thêm thuộc tính justify-content
vào vùng chứa linh hoạt,
hãy gán giá trị flex-end
cho nó
và các mặt hàng được xếp thành hàng ở cuối thùng chứa và không gian trống được đặt ở đầu thùng.
.container {
display: flex;
justify-content: flex-end;
}
Bạn cũng có thể phân phối không gian giữa các mục bằng justify-content: space-between
.
Hãy thử một số giá trị trong bản minh hoạ, và xem MDN để biết toàn bộ các giá trị có thể có.
Thông qua flex-direction: column
Nếu bạn đã thay đổi flex-direction
thành column
thì justify-content
sẽ hoạt động trên
cột.
Để có không gian dự phòng trong vùng chứa khi làm việc dưới dạng cột, bạn cần cung cấp cho vùng chứa của mình
height
hoặc block-size
.
Nếu không, bạn sẽ không còn không gian để phân phối ứng dụng.
Hãy thử các giá trị khác nhau, lần này với bố cục cột hộp linh hoạt.
Phân bổ không gian giữa các đường linh hoạt
Với vùng chứa linh hoạt được bao bọc, bạn có thể có khoảng trống để phân phối trên trục chéo.
Trong trường hợp này, bạn có thể sử dụng thuộc tính align-content
có cùng giá trị với justify-content
.
Không giống như justify-content
(được căn chỉnh các mục với flex-start
theo mặc định),
giá trị ban đầu của align-content
là stretch
.
Thêm thuộc tính align-content
vào vùng chứa linh hoạt để thay đổi hành vi mặc định đó.
.container {
align-content: center;
}
Hãy thử tính năng này trong bản minh hoạ.
Ví dụ này có các dòng bao bọc của các mục linh hoạt,
và vùng chứa có block-size
để chúng ta có không gian dự phòng.
Viết tắt place-content
Để đặt cả justify-content
và align-content
, bạn có thể dùng place-content
với một
hoặc hai giá trị.
Một giá trị sẽ được sử dụng cho cả hai trục,
nếu bạn chỉ định cả URL đầu tiên sẽ dùng cho align-content
và mã thứ hai cho justify-content
.
.container {
place-content: space-between;
/* sets both to space-between */
}
.container {
place-content: center flex-end;
/* wrapped lines on the cross axis are centered,
on the main axis items are aligned to the end of the flex container */
}
Căn chỉnh các mục trên trục chéo
Trên trục chéo, bạn cũng có thể căn chỉnh các mục của mình trong đường linh hoạt bằng cách sử dụng align-items
và align-self
.
Không gian có sẵn cho việc căn chỉnh này sẽ phụ thuộc vào chiều cao của vùng chứa linh hoạt,
hoặc đường cong trong trường hợp một tập hợp các mục được gói.
Giá trị ban đầu của align-self
là stretch
,
đó là lý do tại sao các mục linh hoạt trong một hàng kéo dài đến chiều cao của mục cao nhất theo mặc định.
Để thay đổi giá trị này, hãy thêm thuộc tính align-self
vào bất kỳ mục linh hoạt nào của bạn.
.container {
display: flex;
}
.item1 {
align-self: flex-start;
}
Sử dụng bất kỳ giá trị nào sau đây để căn chỉnh mục:
flex-start
flex-end
center
stretch
baseline
Xem danh sách đầy đủ các giá trị trên MDN.
Bản minh hoạ tiếp theo có một dòng mục linh hoạt với flex-direction: row
.
Mục cuối cùng xác định chiều cao của vùng chứa linh hoạt.
Mục đầu tiên có thuộc tính align-self
với giá trị là flex-start
.
Hãy thử thay đổi giá trị trên thuộc tính đó để xem giá trị này di chuyển như thế nào trong không gian trên trục chéo.
Thuộc tính align-self
được áp dụng cho từng mục.
Bạn có thể áp dụng thuộc tính align-items
cho vùng chứa linh hoạt
để đặt tất cả tài sản align-self
riêng lẻ thành một nhóm.
.container {
display: flex;
align-items: flex-start;
}
Trong bản minh hoạ tiếp theo, hãy thử thay đổi giá trị của align-items
để căn chỉnh tất cả các mục trên chữ thập
Trục dưới dạng một nhóm.
Tại sao không có lời tự chứng minh trong hộp linh hoạt?
Các mục linh hoạt hoạt động như một nhóm trên trục chính. Vì vậy, không có khái niệm về việc tách một mục riêng lẻ ra khỏi nhóm đó.
Trong bố cục lưới, các thuộc tính justify-self
và justify-items
hoạt động trên trục cùng dòng
để căn chỉnh các mục trên trục đó trong khu vực lưới của chúng.
Do cách bố cục linh hoạt xem các mục là một nhóm,
các thuộc tính này không được triển khai trong ngữ cảnh linh hoạt.
Cần phải biết rằng flexbox hoạt động rất tốt với lề tự động.
Nếu bạn muốn tách một mục khỏi nhóm,
hoặc tách nhóm thành hai nhóm, bạn có thể áp dụng lề để thực hiện việc này.
Trong ví dụ bên dưới, mục cuối cùng có lề trái là auto
.
Lề tự động sẽ hấp thụ mọi không gian theo hướng được áp dụng.
Tức là thao tác này sẽ đẩy mục sang bên phải, dẫn đến việc chia nhóm.
Cách căn giữa một mục theo chiều dọc và chiều ngang
Bạn có thể dùng thuộc tính căn chỉnh để căn giữa một mục bên trong một hộp khác.
Thuộc tính justify-content
căn chỉnh mục trên trục chính,
chính là hàng. Thuộc tính align-items
trên trục chéo.
.container {
width: 400px;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
}
Kiểm tra kiến thức
Kiểm tra kiến thức về flexbox
.container { display: flex; direction: ltr; }
Để căn chỉnh theo chiều dọc với Flexbox, hãy sử dụng
.container { display: flex; direction: ltr; }
Để căn chỉnh theo chiều ngang với hộp linh hoạt, hãy sử dụng
.container { display: flex; direction: ltr; }
Theo mặc định, các mục linh hoạt sẽ được căn chỉnh theo stretch
. Nếu bạn muốn xem nội dung
kích thước dùng cho các mặt hàng con, bạn sẽ sử dụng kiểu nào sau đây?
justify-content: flex-start
align-content: start
content
căn chỉnh các đường linh hoạt, chứ không căn chỉnh mục con.height: auto
align-items: flex-start
Tài nguyên
- Bố cục hộp linh hoạt MDN CSS bao gồm một loạt hướng dẫn chi tiết kèm theo ví dụ.
- Hướng dẫn các thủ thuật CSS dành cho Flexbox
- Điều gì xảy ra khi bạn tạo vùng chứa Flexbox
- Mọi điều bạn cần biết về cách căn chỉnh trong hộp linh hoạt
- Hộp linh hoạt đó lớn đến mức nào?
- Trường hợp sử dụng cho hộp linh hoạt
- Kiểm tra và gỡ lỗi bố cục CSS Flexbox trong Công cụ của Chrome cho nhà phát triển