Hộp linh hoạt

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 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 flex?

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.

  • Các giá trị này có thể hiển thị dưới dạng hàng hoặc cột.
  • Chúng tuân theo chế độ viết của tài liệu.
  • Theo mặc định, các dòng này là một dòng, nhưng có thể được yêu cầu ngắt thành nhiều dòng.
  • Bạn có thể sắp xếp lại các mục trong bố cục theo cách trực quan, khác với thứ tự của các mục đó trong DOM.
  • Không gian có thể được phân phối bên trong các mục, nhờ đó các mục này sẽ lớn hơn và nhỏ hơn theo không gian có sẵn trong mục 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éo

Để hiểu rõ flexbox, bạn cần nắm được khái niệm về trục chính và trục chéo. Trục chính là trục do thuộc tính flex-direction của bạn đặt. Nếu đó là row, trục chính của bạn sẽ nằm dọc theo hàng, còn nếu đó là column, trục chính của bạn sẽ nằm dọc theo cột.

Ba hộp cạnh nhau có một mũi tên chỉ từ trái sang phải. Mũi tên được gắn nhãn Trục chính

Các mục Flex di chuyển dưới dạng một nhóm trên trục chính. Hãy nhớ: chúng ta có một loạt các thành phần và đang cố gắng tìm bố cục tốt nhất cho các thành phần đó.

Trục chéo chạy theo hướng khác với trục chính, vì vậy, nếu flex-directionrow, trục chéo sẽ chạy dọc theo cột.

Ba hộp có chiều cao khác nhau, cạnh nhau có một mũi tên, chỉ từ trái sang phải. Mũi tên có nhãn Trục chính. Có một mũi tên khác chỉ từ trên xuống dưới. Trục này được gắn nhãn Trục chéo

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 đó căn chỉnh với nhau và với vùng chứa flex. 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 hoạt động của tất cả các thành phần này trong thực tế trong suốt hướng dẫn này. Hiện tại, bạn chỉ cần lưu ý rằng trục chính tuân theo flex-direction.

Tạo vùng chứa flex

Hãy xem cách flexbox hoạt động bằng cách lấy một nhóm các mục có kích thước khác nhau và sử dụng flexbox để bố trí các mục đó.

<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 flex chứ không phải khối thông thường và bố cục nội tuyến. 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 về bố cục, thao tác này sẽ cung cấp cho bạn một hộp cấp khối, với các mục con flex. Các mục flex ngay lập tức bắt đầu thể hiện một số hành vi của flexbox, sử dụng giá trị ban đầu.

Các giá trị ban đầu có nghĩa là:

  • Các mục sẽ hiển thị theo hàng.
  • Các thành phần này không gói.
  • Các thành phần này không phát triể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 các mục

Mặc dù bạn chưa thêm thuộc tính flex-direction, nhưng các mục sẽ hiển thị dưới dạng một hàng vì giá trị ban đầu của flex-directionrow. Nếu muốn thêm 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 sắp xếp thành một 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 sắp xếp 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 các mục trong bản minh hoạ bên dưới.

Đảo ngược luồng của các 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ỳ thuộc tính nào sắp xếp lại cách hiển thị hình ảnh khác với cách sắp xếp trong tài liệu HTML, vì điều này có thể ảnh hưởng tiêu cực đến khả năng hỗ trợ tiếp cận. Giá trị row-reversecolumn-reverse là ví dụ điển hình cho điều 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 dõi.

Bạn có thể xem trong video sau đây cách trong bố cục hàng đảo ngược, việc nhấn phím giữa các đường liên kết sẽ bị ngắt kết nối vì thao tác điều hướng bằng bàn phím tuân theo DOM chứ không phải màn hình hiển thị hình ả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ỳ lần sắp xếp lại nào cũng phải bao gồm việc kiểm thử kỹ lưỡng để đảm bảo rằng việc này sẽ không khiến một số người khó sử dụng trang web của bạn.

Để 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 một hàng. Hàng chạy theo hướng các câu chảy trong chế độ viết và hướng tập lệnh. Đ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 sử dụng chế độ viết dọc, như một số kiểu chữ Nhật Bản, 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ạ này đang sử dụng chế độ ghi 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 giúp bạn dễ dàng giả định rằng các mục flex sẽ xếp hà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ế độ ghi cần xem xét, việc chúng ta nói về bắt đầukết thúc thay vì trên, dưới, trái và phải trong flexbox có thể dễ hiểu hơn. Mỗi trục có một điểm bắt đầu và một điểm 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 flex ban đầu sẽ xếp hàng từ main-start. Điểm cuối của trục đó là main-end. Điểm bắt đầu của trục chéo là cross-start và điểm kết thúc là cross-end.

Biểu đồ có gắn nhãn của các thuật ngữ ở trên

Đóng gói các mục linh hoạt

Giá trị ban đầu của thuộc tính flex-wrapnowrap. Đ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.

Một vùng chứa flex có 9 mục bên trong, các mục đã thu nhỏ để một từ nằm trên một dòng nhưng không đủ chỗ để hiển thị các mục đó cạnh nhau, vì vậy các mục flex đã mở rộng ra bên ngoài hộp của vùng chứa.
Khi đạt đến kích thước nội dung tối thiểu, các mục flex sẽ bắt đầu tràn vùng chứa

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ề việc phân phối không gian, mỗi dòng hoạt động như một vùng chứa flex mới. Do đó, nếu bạn đang gói các hàng, thì không thể căn chỉnh nội dung trong hàng 2 với nội dung ở phía trên trong hàng 1. Điều này nghĩa là flexbox có một chiều. Bạn có thể kiểm soát căn chỉnh theo một trục, một hàng hoặc một cột, không phải cả hai cùng lúc như chúng ta có thể làm trong lưới.

Ký hiệu viết tắt flex-flow

Bạn có thể đặt thuộc tính flex-directionflex-wrap bằng cách sử dụng 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 flex

Giả sử vùng chứa của chúng ta có nhiều không gian hơn cần thiết để hiển thị các mục, các mục sẽ xếp hàng ở đầu và không tăng lên để lấp đầy không gian. Các thành phần này sẽ ngừng phát triển ở kích thước nội dung tối đ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ơn flex-basis.
  • flex-basis: auto: các mục có kích thước cơ sở là auto.

Bạn có thể biểu thị giá trị từ khoá này bằng flex: initial. Thuộc tính viết tắt flex hoặc các thuộc tính viết dài của flex-grow, flex-shrinkflex-basis được áp dụng cho các phần tử con của vùng chứa flex.

Để các mục phát triển, đồng thời cho phép các mục lớn có nhiều không gian hơn các mục nhỏ, hãy 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ơn flex-basis.
  • flex-shrink: 1: các mục có thể thu nhỏ hơn flex-basis.
  • flex-basis: auto: các mục có kích thước cơ sở là auto.

Việc sử dụng flex: auto sẽ khiến các mụ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ơn flex-basis.
  • flex-shrink: 1: các mục có thể thu nhỏ nhỏ hơn flex-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 tất cả các mục đều có kích thước bằng 0, vì vậy, tất cả không gian trong vùng chứa flex đều có thể được phân phối. Vì tất cả các mục đều có hệ số flex-grow1, nên tất cả các mục đều tăng lên như nhau và không gian được chia đều.

Cho phép mặt hàng tăng trưởng ở các tỷ lệ khác nhau

Bạn không cần phải đặt hệ số flex-grow của tất cả các mục là 1. Bạn có thể cung cấp cho các mục flex các hệ số flex-grow khác nhau. Trong bản minh hoạ bên dưới, mục đầu tiên có flex: 1, mục thứ hai có flex: 2 và mục thứ ba có flex: 3. Khi các mục này tăng từ 0, không gian có sẵn trong vùng chứa flex được chia thành 6 phần. 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, giá trị thứ hai là flex-shrink và giá trị thứ ba là flex-basis.

.item1 {
  flex: 1 1 auto;
}

.item2 {
  flex: 2 1 auto;
}

Đây là trường hợp sử dụng ít phổ biến hơn vì lý do sử dụng flex-basis của auto là để cho phép trình duyệt tìm ra cách phân bổ không gian. Tuy nhiên, nếu bạn muốn một mục tăng thêm một chút so với quyết định của thuật toán, thì điều này 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 flex bằng thuộc tính order. Thuộc tính này cho phép sắp xếp các mục trong nhóm thứ tự. Các mục được sắp xếp theo hướng do flex-direction chỉ định, giá trị thấp nhất trước. 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 của bạn về Flexbox

Mặc định flex-direction

row
Theo mặc định, hộp linh hoạt sẽ đưa các mục vào một hàng và sắp xếp chúng ngay từ đầu. Khi tính năng xuống dòng tự động, tính năng này sẽ tiếp tục tạo các hàng để trẻ chèn vào.
column
Đặt hướng linh hoạt thành cột là một cách hay để xếp chồng các phần tử, nhưng đây không phải là giá trị mặc định.

Theo mặc định, vùng chứa flex sẽ bao bọc các phần tử con.

đúng
Tính năng bao bọc phải được bật.
false
Sử dụng flex-wrap: wrap với display: flex để gói phần tử con

Một mục con flex có vẻ bị vỡ, thuộc tính flex nào giúp giảm thiểu điều này?

flex-grow
Thuộc tính này mô tả liệu các phần tử có thể phát triển vượt quá kích thước cơ sở hay không, chứ không phải cách hoạt động của các phần tử đó trong cơ sở.
flex-shrink
Có, thuộc tính này mô tả cách xử lý kích thước nếu chiều rộng thấp hơn cơ sở.
flex-basis
Đây là điểm xuất phát của việc định cỡ, nhưng không phải là cách xử lý các trường hợp định cỡ mà chiều rộng thấp hơn cơ sở, chẳng hạn như trong trường hợp bị vỡ.

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 đã được chuyển vào quy cách riêng, bạn cũng sẽ gặp các thuộc tính này 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.

Bạn có thể đặt tập hợp thuộc tính vào hai nhóm. Các thuộc tính để phân phối không gian và các thuộc tính để 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 flexbox:

  • 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 flex. Các mục được căn chỉnh ở đầu vùng chứa flex vì giá trị ban đầu của justify-contentflex-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 khoảng trống 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ộ 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 trống trong vùng chứa khi hoạt động dưới dạng cột, bạn cần cung cấp cho vùng chứa một height hoặc block-size. Nếu không, bạn sẽ không có không gian trống để phân phối.

Hãy thử các giá trị khác nhau, lần này với bố cục cột flexbox.

Phân bổ không gian giữa các dòng flex

Với vùng chứa flex được gói, bạn có thể có không gian để 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-contentstretch. 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-contentalign-content, bạn có thể sử 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-itemsalign-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-selfstretch, đó 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 gồm các mục flex 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 flex để đặt tất cả các thuộc tính align-self riêng lẻ dưới dạng 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 Flex hoạt động như một nhóm trên trục chính. Vì vậy, không có khái niệm nào 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-selfjustify-items hoạt động trên trục nội tuyến để căn chỉnh các mục trên trục đó trong vùng lưới của chúng. Do cách bố cục flex coi các mục là một nhóm, nên các thuộc tính này không được triển khai trong ngữ cảnh flex.

Bạn nên 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, đó 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 mức độ hiểu biết

Kiểm tra kiến thức của bạn về flexbox

.container {
  display: flex;
  direction: ltr;
}

Để căn chỉnh theo chiều dọc với flexbox, hãy sử dụng

căn chỉnh từ khoá
Rất tốt
căn đều từ khoá
Rất tiếc
.container {
  display: flex;
  direction: ltr;
}

Để căn chỉnh theo chiều ngang với flexbox, hãy sử dụng

căn chỉnh từ khoá
Rất tiếc
căn đều từ khoá
Rất tốt
.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
Thuộc tính căn đều là để căn chỉnh ngang, không phải theo chiều dọc.
align-content: start
content căn chỉnh các dòng flex, chứ không phải căn chỉnh mục con.
height: auto
Việc này sẽ không có hiệu lực.
align-items: flex-start
Có, chúng ta muốn căn chỉnh dọc theo 'trên cùng' hoặc bắt đầu để xoá giá trị kéo giãn mặc định và thay vào đó sử dụng chiều cao của nội dung.

Tài nguyên