Aligning items in a flex container

Một trong những lý do flexbox rất hữu ích là nó cho phép căn chỉnh đúng cách, bao gồm cung cấp phương pháp nhanh để căn giữa các phần tử theo chiều dọc. Trong hướng dẫn này, chúng ta sẽ xem xét kỹ lưỡng cách các thuộc tính alignment và justification hoạt động trong flexbox.

Sử dụng alignment trong flexbox

Flexbox cung cấp một số thuộc tính để kiểm soát alignment và khoảng cách, với align-itemsjustify-content là căn bản để căn giữa các phần tử. Để căn giữa một phần tử, chúng ta sử dụng thuộc tính align-items để căn chỉnh phần tử trên cross axis, trong trường hợp này là block axis chạy theo chiều dọc. Chúng ta sử dụng justify-content để căn chỉnh phần tử trên main axis, trong trường hợp này là inline axis chạy theo chiều ngang.

Cross axis là trục dọc và main axis là trục ngang.

Thay đổi kích thước container hoặc phần tử lồng nhau trong ví dụ mã bên dưới. Phần tử lồng nhau luôn ở giữa.

html
<div class="box">
  <div></div>
</div>
css
.box {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px dotted rgb(96 139 168);
}

.box div {
  width: 100px;
  height: 100px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
}

Các thuộc tính kiểm soát alignment trong flexbox

Các thuộc tính chúng ta sẽ xem xét trong hướng dẫn này như sau.

  • justify-content: Kiểm soát alignment của tất cả các phần tử trên main axis.
  • align-items: Kiểm soát alignment của tất cả các phần tử trên cross axis.
  • align-self: Kiểm soát alignment của từng flex item riêng lẻ trên cross axis.
  • align-content: Kiểm soát không gian giữa các flex line trên cross axis.
  • gap, column-gaprow-gap: Được dùng để tạo khoảng cách hoặc rãnh giữa các flex item.

Chúng ta cũng sẽ khám phá cách auto margin có thể được dùng để căn chỉnh trong flexbox.

Căn chỉnh các phần tử trên cross axis

Thuộc tính align-items, được đặt trên flex container, và thuộc tính align-self, được đặt trên flex item, kiểm soát alignment của flex item trên cross axis. Cross axis chạy dọc theo các cột nếu flex-directionrow và dọc theo các hàng nếu flex-directioncolumn.

Trong ví dụ flex cơ bản này, chúng ta đang sử dụng cross-axis alignment. Khi chúng ta thêm display: flex vào container, các phần tử con trở thành flex item được sắp xếp theo hàng. Theo mặc định, tất cả chúng sẽ kéo dài để khớp với chiều cao của phần tử cao nhất, vì phần tử đó xác định chiều cao của các phần tử trên cross axis. Nếu flex container có chiều cao được đặt, các phần tử sẽ kéo dài đến chiều cao đó, bất kể lượng nội dung trong mỗi phần tử.

Ba phần tử, một phần tử có thêm văn bản khiến nó cao hơn các phần tử còn lại.

Ba phần tử được kéo dài đến 200 pixel chiều cao

Lý do các phần tử có cùng chiều cao là vì giá trị ban đầu của align-items, thuộc tính kiểm soát alignment trên cross axis, được đặt thành stretch.

Chúng ta có thể sử dụng các giá trị khác để kiểm soát cách các phần tử căn chỉnh:

  • align-items: stretch
  • align-items: flex-start
  • align-items: flex-end
  • align-items: start
  • align-items: end
  • align-items: center
  • align-items: baseline
  • align-items: first baseline
  • align-items: last baseline

Trong ví dụ bên dưới, giá trị của align-itemsstretch. Hãy thử các giá trị khác và xem cách các phần tử căn chỉnh so với nhau trong flex container.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three <br />has <br />extra <br />text</div>
</div>
css
.box {
  border: 2px dotted rgb(96 139 168);
  display: flex;
  align-items: stretch;
}

.box div {
  width: 100px;
  background-color: rgb(96 139 168 / 0.2);
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
}

Căn chỉnh một phần tử với align-self

Thuộc tính align-items đặt thuộc tính align-self cho tất cả flex item như một nhóm. Điều này có nghĩa là bạn có thể khai báo tường minh thuộc tính align-self để nhắm đến một phần tử cụ thể. Thuộc tính align-self chấp nhận tất cả các giá trị giống như align-items, cộng thêm giá trị auto, giá trị này đặt lại giá trị về giá trị được định nghĩa trên flex container.

Trong ví dụ live tiếp theo, flex container có align-items: flex-start, có nghĩa là các phần tử đều được căn chỉnh về đầu của cross axis. Sử dụng bộ chọn first-child, phần tử đầu tiên được đặt thành align-self: stretch. Một phần tử khác với class selectedalign-self: center được đặt. Thay đổi giá trị của align-items hoặc thay đổi các giá trị của align-self trên từng phần tử riêng lẻ để xem cách này hoạt động.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div class="selected">Three</div>
  <div>Four</div>
</div>
css
.box {
  border: 2px dotted rgb(96 139 168);
  display: flex;
  align-items: flex-start;
  height: 200px;
}
.box div {
  background-color: rgb(96 139 168 / 0.2);
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  padding: 20px;
}
.box > *:first-child {
  align-self: stretch;
}
.box .selected {
  align-self: center;
}

Thay đổi main axis

Cho đến nay, chúng ta đã xem xét hành vi alignment khi flex-direction mặc định là row trong khi làm việc với ngôn ngữ viết từ trên xuống dưới, với main axis ngang và cross axis dọc.

Ba phần tử, phần tử đầu tiên căn chỉnh với flex-start, phần tử thứ hai với center, phần tử thứ ba với flex-end. Căn chỉnh trên trục dọc.

Giữ nguyên chế độ viết, khi flex-direction được thay đổi thành column, các thuộc tính align-itemsalign-self sẽ căn chỉnh các phần tử sang trái và phải thay vì trên và dưới; những thuộc tính này vẫn đang căn chỉnh các phần tử dọc theo cross axis, nhưng cross axis giờ đây là ngang!

Ba phần tử, phần tử đầu tiên căn chỉnh với flex-start, phần tử thứ hai với center, phần tử thứ ba với flex-end. Căn chỉnh trên trục ngang.

Bạn có thể thử điều này trong ví dụ bên dưới, có flex container với flex-direction: column nhưng về cơ bản giống với ví dụ trước.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div class="selected">Three</div>
  <div>Four</div>
</div>
css
.box {
  border: 2px dotted rgb(96 139 168);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 200px;
}
.box div {
  background-color: rgb(96 139 168 / 0.2);
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  padding: 20px;
}
.box > *:first-child {
  align-self: stretch;
}
.box .selected {
  align-self: center;
}

Căn chỉnh nội dung trên cross axis với thuộc tính align-content

Cho đến nay, chúng ta đã tập trung vào việc căn chỉnh các phần tử hoặc từng phần tử riêng lẻ trong vùng được xác định bởi flex container chứa một dòng flex item duy nhất. Khi flex item được phép bao quanh nhiều dòng, thuộc tính align-content có thể được dùng để kiểm soát việc phân bổ không gian giữa các dòng, còn được gọi là packing flex lines.

Để align-content có hiệu lực, kích thước chiều cross axis (chiều cao trong trường hợp này) của flex container phải lớn hơn cần thiết để hiển thị các phần tử. Sau đó nó hoạt động trên tất cả các phần tử như một tập hợp. Các giá trị align-content xác định điều gì xảy ra với không gian sẵn có còn lại và alignment của toàn bộ tập hợp các phần tử trong đó.

Thuộc tính align-content nhận các giá trị sau:

  • align-content: flex-start
  • align-content: flex-end
  • align-content: start
  • align-content: end
  • align-content: center
  • align-content: space-between
  • align-content: space-around
  • align-content: space-evenly
  • align-content: stretch
  • align-content: normal (hoạt động như stretch)
  • align-content: baseline
  • align-content: first baseline
  • align-content: last baseline

Trong ví dụ live bên dưới, flex container có chiều cao 400 pixels, lớn hơn cần thiết để hiển thị các phần tử. Giá trị của align-contentspace-between, có nghĩa là không gian sẵn có được chia đều giữa các flex line, được đặt ngang với đầu và cuối của container trên cross axis.

Hãy thử các giá trị khác để xem thuộc tính align-content hoạt động như thế nào.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
</div>
css
.box {
  width: 450px;
  border: 2px dotted rgb(96 139 168);
  display: flex;
  flex-wrap: wrap;
  height: 300px;
  align-content: space-between;
}

.box > * {
  padding: 20px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
  flex: 1 1 100px;
}

.box div {
  background-color: rgb(96 139 168 / 0.2);
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  padding: 20px;
}

Một lần nữa chúng ta có thể chuyển flex-direction thành column để xem thuộc tính này hoạt động như thế nào khi chúng ta làm việc theo cột. Như trước, chúng ta cần đủ không gian trong cross axis để có không gian trống sau khi hiển thị tất cả các phần tử.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
</div>
css
.box {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  width: 400px;
  height: 300px;
  align-content: space-between;
  border: 2px dotted rgb(96 139 168);
}

.box > * {
  padding: 20px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
  flex: 1 1 100px;
}

.box div {
  background-color: rgb(96 139 168 / 0.2);
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  padding: 20px;
}

Căn chỉnh nội dung trên main axis

Bây giờ chúng ta đã thấy cách alignment hoạt động trên cross axis, chúng ta có thể xem xét main axis. Ở đây chúng ta chỉ có một thuộc tính — justify-content. Điều này là vì chúng ta chỉ xử lý các phần tử như một nhóm trên main axis. Với justify-content chúng ta kiểm soát điều gì xảy ra với không gian sẵn có, nếu có nhiều không gian hơn cần thiết để hiển thị các phần tử.

Trong ví dụ ban đầu với display: flex trên container, các phần tử hiển thị theo hàng và tất cả xếp hàng ở đầu container. Điều này là do giá trị ban đầu của justify-contentnormal, hoạt động như start. Bất kỳ không gian sẵn có nào đều được đặt ở cuối các phần tử.

Ba phần tử, mỗi phần tử rộng 100 pixel trong container 500 pixel. Không gian sẵn có ở cuối các phần tử.

Các giá trị baseline không liên quan trong chiều này. Ngoài ra, thuộc tính justify-content chấp nhận các giá trị tương tự như align-content.

  • justify-content: flex-start
  • justify-content: flex-end
  • justify-content: start
  • justify-content: end
  • justify-content: left
  • justify-content: right
  • justify-content: center
  • justify-content: space-between
  • justify-content: space-around
  • justify-content: space-evenly
  • justify-content: stretch (hoạt động như start)
  • justify-content: normal (hoạt động như stretch, hoạt động như start)

Trong ví dụ bên dưới, giá trị của justify-contentspace-between. Không gian sẵn có sau khi hiển thị các phần tử được phân bổ giữa các phần tử. Phần tử bên trái và bên phải nằm ngang với đầu và cuối.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
</div>
css
.box {
  display: flex;
  justify-content: space-between;
  border: 2px dotted rgb(96 139 168);
}

.box > * {
  padding: 20px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
}

Nếu main axis nằm theo hướng block vì flex-direction được đặt thành column, thì justify-content sẽ phân bổ không gian giữa các phần tử theo chiều đó miễn là có không gian trong flex container để phân bổ.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
</div>
css
.box {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 300px;
  border: 2px dotted rgb(96 139 168);
}

.box > * {
  padding: 20px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
}

Alignment và writing modes

Hãy nhớ rằng với tất cả các phương pháp alignment này, các giá trị startend nhận biết writing mode. Nếu giá trị của justify-contentstart và writing mode là trái sang phải, như tiếng Anh, các phần tử sẽ căn chỉnh bắt đầu từ cạnh trái của container.

Ba phần tử xếp hàng bên trái

Tuy nhiên nếu writing mode là phải sang trái như tiếng Ả Rập, các phần tử sẽ xếp hàng bắt đầu từ cạnh phải của container.

Ba phần tử xếp hàng từ bên phải

Ví dụ live bên dưới có thuộc tính direction được đặt thành rtl để buộc luồng từ phải sang trái cho các phần tử. Bạn có thể xóa điều này, hoặc thay đổi các giá trị của justify-content để xem flexbox hoạt động như thế nào khi đầu của inline direction ở bên phải.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
</div>
css
.box {
  direction: rtl;
  display: flex;
  justify-content: flex-end;
  border: 2px dotted rgb(96 139 168);
}

.box > * {
  padding: 20px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
}

Alignment và flex-direction

Hướng start của dòng cũng sẽ thay đổi nếu bạn thay đổi thuộc tính flex-direction — ví dụ, sử dụng row-reverse thay vì row.

Trong ví dụ tiếp theo này, flex-direction: row-reversejustify-content: flex-end xác định hướng và vị trí của các phần tử trong flex container. Trong ngôn ngữ trái sang phải, các phần tử xếp hàng ở bên trái. Hãy thử thay đổi flex-direction: row-reverse thành flex-direction: row. Bạn sẽ thấy rằng các phần tử giờ đây di chuyển sang phía bên phải, và thứ tự hiển thị của các phần tử bị đảo ngược.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
</div>
css
.box {
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  border: 2px dotted rgb(96 139 168);
}

.box > * {
  padding: 20px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
}

Mặc dù tất cả điều này có vẻ hơi khó hiểu, quy tắc cần nhớ là trừ khi bạn làm gì đó để thay đổi, flex item tự sắp xếp theo hướng mà các từ được đặt trong ngôn ngữ của tài liệu dọc theo inline, row axis. startflex-start sẽ là nơi câu văn bản bắt đầu.

Sơ đồ cho thấy start ở bên trái và end ở bên phải.

Bạn có thể chuyển chúng để hiển thị theo hướng block cho ngôn ngữ của tài liệu bằng cách chọn flex-direction: column. Sau đó, startflex-start sẽ là nơi đoạn văn đầu tiên của bạn bắt đầu.

Sơ đồ cho thấy start ở trên cùng và end ở dưới cùng.

Nếu bạn thay đổi flex-direction thành một trong các giá trị reverse, chúng sẽ tự sắp xếp từ end axis và theo thứ tự ngược lại với cách các từ được viết trong ngôn ngữ của tài liệu. Sau đó, startflex-start sẽ thay đổi thành end của trục đó — vì vậy đến vị trí mà các dòng của bạn sẽ bao quanh nếu làm việc theo hàng, hoặc ở cuối đoạn văn cuối cùng của bạn theo hướng block.

Sơ đồ cho thấy start ở bên phải và end ở bên trái.

Sơ đồ cho thấy end ở trên cùng và start ở dưới cùng

Sử dụng auto margin để căn chỉnh trên main axis

Chúng ta không có thuộc tính justify-items hoặc justify-self sẵn dùng trên main axis vì các phần tử được coi là một nhóm trên trục đó. Tuy nhiên, có thể thực hiện một số alignment riêng lẻ để tách biệt một phần tử hoặc một nhóm phần tử khỏi các phần tử khác bằng cách sử dụng auto margin cùng với flexbox.

Một mẫu phổ biến là thanh điều hướng trong đó một số mục chính được căn chỉnh về bên phải, với nhóm chính ở bên trái. Bạn có thể nghĩ rằng đây nên là trường hợp sử dụng cho thuộc tính justify-self. Tuy nhiên, hãy xem xét hình ảnh bên dưới. Như một ví dụ, lấy hình ảnh sau với ba phần tử ở một phía và hai phần tử ở phía kia. Nếu justify-self hoạt động trên flex item và được đặt trên phần tử d, nó cũng sẽ thay đổi alignment của phần tử e theo sau, có thể hoặc không theo ý muốn.

Năm phần tử, trong hai nhóm. Ba ở bên trái và hai ở bên phải.

Thay vào đó, phần tử d có thể được đẩy sang bằng cách sử dụng CSS margins.

Trong ví dụ live này, phần tử 4 được tách khỏi ba phần tử đầu tiên bằng cách đặt margin-left thành auto, tiêu thụ tất cả không gian có thể theo trục của nó. Đây là cách căn giữa một block với margin auto trái và phải hoạt động. Mỗi phía cố gắng chiếm nhiều không gian nhất có thể, và vì vậy block được đẩy vào giữa.

Trong ví dụ live này, các flex item được sắp xếp theo hàng với các giá trị flex cơ bản, và class push, được đặt trên phần tử thứ tư, áp dụng margin-left: auto cho phần tử đó. Hãy thử xóa class trên phần tử thứ tư hoặc thêm class vào một phần tử khác để xem cách hoạt động.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div class="push">Four</div>
  <div>Five</div>
</div>
css
.box {
  display: flex;
  border: 2px dotted rgb(96 139 168);
}

.box > * {
  padding: 20px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
}
.push {
  margin-left: auto;
}

Tạo khoảng cách giữa các phần tử

Để tạo khoảng cách giữa các flex item, sử dụng các thuộc tính gap, column-gaprow-gap. Thuộc tính column-gap tạo khoảng cách giữa các phần tử trong một hàng. Thuộc tính row-gap tạo khoảng cách giữa các flex line khi bạn có flex-wrap được đặt thành wrap.

Thuộc tính gap là shorthand đặt cả row-gapcolumn-gap. Khoảng cách giữa các flex item hoặc flex line phụ thuộc vào hướng. Nếu thuộc tính flex-direction tạo các hàng, giá trị đầu tiên xác định khoảng cách giữa các flex line, và giá trị thứ hai xác định khoảng cách giữa các phần tử trong mỗi dòng. Với cột (khi flex-direction được đặt thành column hoặc column-reverse), giá trị đầu tiên xác định khoảng cách giữa các flex item, và giá trị thứ hai xác định khoảng cách giữa các flex line.

html
<div class="box">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
</div>
css
.box {
  display: flex;
  flex-wrap: wrap;
  row-gap: 10px;
  column-gap: 2em;
  border: 2px dotted rgb(96 139 168);
}

.box > * {
  flex: 1;
  padding: 20px;
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
}

Xem thêm