Cần ý kiến phản hồi: Chúng tôi nên xác định khối xây CSS như thế nào?

Ian Kilpatrick
Ian Kilpatrick
Tab Atkins-Bittner
Tab Atkins-Bittner

Ngày xuất bản: 19 tháng 9 năm 2024

Nhóm làm việc CSS đã kết hợp hai đề xuất về kiểu xếp kề CSS thành một bản quy cách nháp. Nhóm này hy vọng rằng việc này sẽ giúp bạn dễ dàng so sánh hai phiên bản và đưa ra quyết định cuối cùng. Nhóm Chrome vẫn tin rằng cú pháp xếp kề riêng biệt sẽ là cách tốt nhất để tiếp tục. Mặc dù vấn đề hiệu suất lớn nhất được đề cập trong bài đăng trước của chúng tôi đã được giải quyết, nhưng vẫn còn những mối lo ngại về cú pháp, giá trị ban đầu và mức độ dễ học của phiên bản kết hợp với lưới.

Tuy nhiên, để kiểm tra các giả định của mình, chúng tôi đã thực hiện một số ví dụ để cho thấy cách hoạt động của bố cục xếp kề với từng phiên bản. Hãy xem các ví dụ trong bài đăng này và gửi ý kiến phản hồi cho chúng tôi để chúng tôi có thể đưa ra quyết định và tiếp tục triển khai tính năng này.

Bài đăng này không đề cập đến tất cả các trường hợp sử dụng có thể có, tuy nhiên, rõ ràng là việc tách bố cục xếp kề khỏi bố cục lưới sẽ không khiến tính năng này thiếu chức năng. Trên thực tế, điều ngược lại có thể đúng. Như bạn sẽ thấy trong bài đăng này, phiên bản display: masonry tạo ra các cơ hội mới và cú pháp đơn giản hơn. Ngoài ra, nhiều nhà phát triển đã nêu ra mối lo ngại về khả năng sắp xếp lại các mục theo kiểu xếp kề gây ra vấn đề về khả năng hỗ trợ tiếp cận. Vấn đề này cũng đang được giải quyết cho cả hai phiên bản cú pháp, thông qua thuộc tính reading-flow được đề xuất.

Bố cục xếp kề cơ bản

Đây là bố cục mà hầu hết mọi người hình dung khi nghĩ đến kiểu xếp kề. Các mục hiển thị theo hàng và sau khi hàng đầu tiên được đặt, các mục tiếp theo sẽ di chuyển vào khoảng trống do các mục ngắn hơn để lại.

Bố cục có các cột, các mục lấp đầy cột mà không có khoảng trống.
Trong bố cục này, các cột được xác định, sau đó các mục được điền bằng kiểu xếp kề thay vì các hàng nghiêm ngặt.

Thông qua display: masonry

Để tạo bố cục kiểu xếp kề, hãy sử dụng giá trị masonry cho thuộc tính display. Thao tác này sẽ tạo một bố cục xếp kề với các kênh cột mà bạn xác định (hoặc được nội dung xác định) và bố cục xếp kề ở trục còn lại. Mục đầu tiên được hiển thị ở đầu khối và cùng dòng (do đó là ở trên cùng bên trái trong tiếng Anh) và các mục được bố trí theo hướng cùng dòng.

Để xác định các bản nhạc, hãy sử dụng masonry-template-tracks với các giá trị danh sách bản nhạc như được sử dụng trong bố cục lưới CSS.

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(3, 1fr);
  gap: 10px;
}

Thông qua display: grid

Để tạo bố cục xếp kề, trước tiên, hãy tạo bố cục lưới bằng cách sử dụng giá trị grid cho thuộc tính display. Xác định các cột bằng thuộc tính grid-template-columns, sau đó gán giá trị masonry cho grid-template-rows.

Thao tác này sẽ tạo một bố cục như bạn mong đợi với các mục lưới được đặt tự động, tuy nhiên, các mục trong mỗi hàng sử dụng bố cục kiểu xếp kề và sẽ sắp xếp lại để chiếm không gian do các mục nhỏ hơn trong hàng trước để lại.

.masonry {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: masonry;
  gap: 10px;
}

Những điểm cần cân nhắc giữa hai lựa chọn

Một điểm khác biệt đáng chú ý giữa các phương thức này là với phiên bản display: masonry, bạn sẽ có bố cục xếp kề ngay cả khi không chỉ định bất kỳ kênh nào bằng masonry-template-tracks. Do đó, display: masonry có thể là tất cả những gì bạn cần. Nguyên nhân là do giá trị ban đầu của masonry-template-tracksrepeat(auto-areas, auto). Bố cục này tạo ra nhiều kênh có kích thước tự động vừa với vùng chứa.

Luồng ngược với kết cấu bằng đá

Quy cách này bao gồm các cách thay đổi hướng của luồng xếp kề. Ví dụ: bạn có thể thay đổi luồng để hiển thị từ cuối khối.

Bố cục có các cột, các mục lấp đầy cột sẽ làm như vậy từ cuối bố cục.
Trong bố cục này, các cột được xác định, sau đó các mục được điền bằng kiểu xếp kề bắt đầu từ cuối khối.

Thông qua display: masonry

Tạo bố cục xếp kề bằng display: masonry, sau đó sử dụng masonry-direction với giá trị là column-reverse.

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(3, 1fr);
  masonry-direction: column-reverse;
}

Thông qua display: grid

Tạo bố cục kiểu xếp kề bằng display: gridgrid-template-rows: masonry. Sau đó, hãy sử dụng thuộc tính grid-auto-flow với giá trị mới là row-reverse để các mục bố cục từ cuối khối của vùng chứa lưới.

.masonry {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: masonry;
  grid-auto-flow: row-reverse;
}

Những điểm cần cân nhắc giữa hai lựa chọn

Phiên bản display: masonry rất giống với cách hoạt động của flexbox. Thay đổi hướng dòng chảy của các cột bằng cách sử dụng thuộc tính masonry-direction có giá trị là column-reverse.

Phiên bản lưới CSS sử dụng grid-auto-flow. Như đã xác định hiện tại, grid-auto-flow: row-reversegrid-auto-flow: column-reverse sẽ mang lại hiệu quả tương tự. Điều này có thể gây nhầm lẫn vì bạn có thể mong đợi các thành phần này sẽ làm một việc khác.

Kiểu xếp kề cho hàng

Bạn cũng có thể thay đổi hướng để xác định các hàng.

Bố cục có các hàng, các mục lấp đầy các hàng mà không có khoảng trống.
Trong bố cục này, các hàng được xác định, sau đó các mục được điền bằng kiểu xếp kề thay vì các cột nghiêm ngặt.

Thông qua display: masonry

Tạo bố cục kiểu xếp kề bằng display: masonry, sau đó đặt giá trị của masonry-direction thành row. Trừ phi bạn muốn các hàng có kích thước khối cụ thể, bạn không cần chỉ định kích thước kênh nào vì kích thước mặc định là auto, do đó, các kênh sẽ có kích thước theo nội dung mà chúng chứa.

.masonry {
  display: masonry;
  masonry-direction: row;
}

Thông qua display: grid

.masonry {
  display: grid;
  grid-template-columns: masonry;
  grid-template-rows: repeat(3, 1fr);
}

Những điểm cần cân nhắc giữa hai lựa chọn

Cũng như luồng đảo ngược, việc thay đổi phiên bản display: masonry từ cột thành hàng có nghĩa là thay đổi giá trị của masonry-direction. Với phiên bản lưới, bạn sẽ cần chuyển đổi các giá trị của thuộc tính grid-template-columnsgrid-template-rows. Hoặc nếu sử dụng viết tắt, hãy thay đổi thứ tự của cú pháp.

Với cả hai ví dụ về quy trình chuyển đổi này, phiên bản display: masonry có cảm giác trực quan hơn. Có một thuộc tính duy nhất kiểm soát luồng masonry-direction, thuộc tính này nhận một trong các giá trị sau:

  • row
  • column
  • row-reverse
  • column-reverse

Sau đó, bạn thêm mọi thông tin về kích thước cần thiết vào masonry-template-tracks, giả sử giá trị tự động mặc định không phải là giá trị bạn cần.

Với lưới, để làm theo hướng ngược lại, bạn cần sử dụng thuộc tính grid-auto-flow và để làm theo kiểu xếp kề hàng, hãy chuyển đổi giá trị của thuộc tính grid-template-*. Trong cú pháp lưới hiện tại, bạn cũng không thể để giá trị cho trục lưới không xác định. Bạn luôn cần chỉ định các thuộc tính grid-template-* trên trục không có giá trị masonry.

Vị trí của các mục

Trong cả hai phiên bản, bạn có thể định vị các mục một cách rõ ràng bằng cách sử dụng vị trí dựa trên dòng mà bạn sẽ quen thuộc với bố cục lưới. Trong cả hai phiên bản, bạn chỉ có thể đặt vị trí các mục trong trục lưới, đây là trục có các kênh được xác định trước, bạn không thể đặt vị trí các mục trên trục đang tạo bố cục kiểu xếp kề.

Thông qua display: masonry

CSS sau đây xác định bố cục kiểu xếp kề có 4 cột. Do đó, trục lưới là các cột. Mục có lớp a được đặt từ dòng cột đầu tiên đến dòng cột thứ ba, trải dài trên hai kênh có thuộc tính masonry-track-* mới. Bạn cũng có thể xác định đây là viết tắt của masonry-track: 1 / 3;.

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(4, 1fr);
}

.a {
  masonry-track-start: 1;
  masonry-track-end: 3;
}

Thông qua display: grid

CSS sau đây xác định bố cục kiểu xếp kề có 4 cột. Do đó, trục lưới là các cột. Mục có lớp a được đặt từ dòng cột đầu tiên đến dòng cột thứ ba, trải dài trên hai kênh có thuộc tính grid-column-*. Bạn cũng có thể xác định đây là viết tắt của grid-column: 1 / 3;.

Nếu trục lưới là cột thì các thuộc tính grid-row-* sẽ bị bỏ qua, còn nếu trục lưới là hàng thì các thuộc tính grid-columns-* sẽ bị bỏ qua.

.masonry {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: masonry;
}

.a {
  grid-column-start: 1;
  grid-column-end: 3;
}

Bạn có thể sử dụng dòng được đặt tên bằng cả hai cú pháp. Các ví dụ sau đây cho thấy một lưới có hai dòng cột có tên là a.

Thông qua display: masonry

Các dòng được đặt tên được xác định trong giá trị danh sách bản nhạc của masonry-template-tracks. Bạn có thể đặt mục này sau bất kỳ dòng nào có tên là a.

.masonry {
  display: masonry;
  masonry-template-tracks: 100px [a] auto [a] auto 100px;
}

.item {
  masonry-track: a;
}

Thông qua display: grid

Các dòng được đặt tên được xác định trong giá trị danh sách bản nhạc của grid-template-columns. Mục này được đặt sau dòng đầu tiên có tên là a. Nếu thuộc tính grid-row được xác định, thuộc tính này sẽ bị bỏ qua.

.masonry {
  display: grid;
  grid-template-columns: 100px [a] auto [a] auto 100px;
  grid-template-rows: masonry;
}

.item {
  grid-column: a;
  grid-row: a; /* ignored */
}

Bạn cũng có thể sử dụng vùng được đặt tên trong cả hai cú pháp. Các ví dụ sau đây cho thấy một lưới có ba kênh có tên là "a", "b" và "c".

Thông qua display: masonry

Các kênh được đặt tên theo giá trị của masonry-template-areas. Vì không có kích thước kênh nào được xác định, nên cả ba đều mặc định là kích thước auto. Mục này được đặt trong kênh "a".

.masonry {
  display: masonry;
  masonry-template-areas: "a b c";
}

.item {
  masonry-track: a;
}

Cách này hoạt động giống nhau cho dù bạn đang xác định hàng hay cột; điểm khác biệt duy nhất là thuộc tính masonry-direction.

Thông qua display: grid

Đối với cột, cú pháp về cơ bản giống hệt nhau. Tương tự, vì không có kích thước kênh nào được xác định, cả ba đều mặc định là kích thước auto, nhưng bạn vẫn cần phải nêu rõ rằng trục còn lại là kiểu xếp kề:

.masonry {
  display: grid;
  grid-template-areas: "a b c";
  grid-template-rows: masonry;
}

.item {
  grid-column: a;
}

Tuy nhiên, đối với hàng, bạn phải viết giá trị theo cách khác, vì grid-template-areas thực sự đang xác định một vùng hai chiều và mỗi hàng được viết dưới dạng một chuỗi riêng biệt:

.masonry {
  display: grid;
  grid-template-areas: "a" "b" "c"; /* Note the difference, each row is quoted. */
  grid-template-columns: masonry;
}

.item {
  grid-row: a;
}

Những điểm cần cân nhắc giữa hai lựa chọn

Với bất kỳ vị trí nào, cú pháp display: masonry sẽ hoạt động hiệu quả hơn khi nói đến việc chuyển đổi hướng. Vì thuộc tính masonry-track-* hoạt động theo hướng nào là trục lưới, nên tất cả những gì bạn cần làm để thay đổi hướng là thay đổi giá trị của masonry-direction. Với phiên bản lưới, ít nhất bạn sẽ cần các thuộc tính dư thừa để bật tính năng chuyển đổi. Tuy nhiên, hãy xem các ví dụ trước để biết các cách khác phức tạp hơn khi thay đổi hướng với phiên bản lưới.

Chữ viết tắt

Trong bài đăng này, chúng tôi đã sử dụng cách viết dài để làm rõ hơn những thuộc tính đang được sử dụng. Tuy nhiên, bạn có thể xác định cả phiên bản display: masonrydisplay: grid bằng cách sử dụng viết tắt.

Thông qua display: masonry

Từ viết tắt display: masonry sử dụng từ khoá masonry. Để tạo bố cục kiểu xếp kề cơ bản, hãy sử dụng CSS sau:

.masonry {
  display: masonry;
  masonry: repeat(3, 1fr);
}

Cách tạo bố cục xếp kề đơn giản dựa trên hàng:

.masonry {
  display: masonry;
  masonry: row;
}

Cách xác định các kênh và bố cục dựa trên hàng bằng ký hiệu viết tắt:

.masonry {
  display: masonry;
  masonry: repeat(3, 1fr) row;
}

Thông qua display: grid

Để tạo bố cục xếp kề cơ bản bằng cách sử dụng ký hiệu viết tắt grid.

.masonry {
  display: grid;
  grid: masonry / repeat(3, 1fr);
}

Cách tạo bố cục xếp kề đơn giản dựa trên hàng:

.masonry {
  display: grid;
  grid: repeat(3, auto) / masonry;
}

Trong các ví dụ phức tạp hơn, vì cú pháp display:masonry tổng thể đơn giản hơn, nên bạn có thể gói nhiều thuộc tính hơn vào viết tắt mà không cần quá phức tạp.

Ví dụ: hãy tưởng tượng bạn tạo ba cột có tên là "a", "b" và "c", được điền từ dưới lên.

Thông qua display:masonry

Trong display: masonry, bạn có thể đặt cả ba thuộc tính này cùng nhau theo cách viết tắt:

.masonry {
  display: masonry;
  masonry: column-reverse "a b c";
}

Vì các thành phần này được tự động định cỡ, nên bạn không cần chỉ định kích thước. Tuy nhiên, nếu muốn một kích thước cụ thể, bạn có thể thêm kích thước đó. Ví dụ: masonry: column-reverse 50px 100px 200px "a b c";.

Ngoài ra, bạn có thể tự do sắp xếp lại thứ tự của từng thành phần; không có thứ tự cụ thể nào mà bạn cần ghi nhớ. Và nếu muốn thực hiện các hàng, tất cả những gì bạn cần làm là hoán đổi column-reverse với row hoặc row-reverse; phần còn lại của cú pháp vẫn giữ nguyên.

Thông qua display: grid

Trong display: grid, bạn phải thiết lập riêng ba khía cạnh này:

.masonry {
  display: grid;
  grid-template-rows: masonry;
  grid-template-areas: "a b c";
  grid-auto-flow: wrap-reverse;
}

Giống như ví dụ về kiểu xếp kề, điều này làm cho tất cả các cột có kích thước auto, nhưng nếu muốn cung cấp kích thước rõ ràng, bạn có thể làm như sau:

.masonry {
  display: grid;
  grid: masonry / 50px 100px 200px;
  grid-template-areas: "a b c";
  grid-auto-flow: wrap-reverse;
}

Hoặc nếu bạn muốn sử dụng "lưới" để đặt kích thước và tên khu vực cùng nhau:

.masonry {
  display: grid;
  grid: "a b c" masonry / 50px 100px 200px;
  grid-auto-flow: wrap-reverse;
}

Trong cả hai ví dụ này, thứ tự là bắt buộc và khác nếu bạn muốn các hàng. Ví dụ: cách thay đổi thành hàng sẽ như sau:

.masonry {
  display: grid;
  grid: 50px 100px 200px / masonry;
  grid-template-areas: "a" "b" "c";
}

Hoặc để đưa tất cả các giá trị này vào một ký hiệu viết tắt:

.masonry {
  display: grid;
  grid: "a" 50px "b" 100px "c"  200px / masonry;
}

Những điểm cần cân nhắc giữa hai lựa chọn

Phương thức viết tắt display: masonry có thể được sử dụng rộng rãi, vì đây là một phương thức viết tắt tương đối đơn giản. Trong nhiều trường hợp, đối với bố cục xếp kề "tiêu chuẩn", bạn chỉ cần đặt định nghĩa kênh; tất cả các giá trị khác có thể giả định giá trị mặc định.

Phiên bản display: grid sử dụng ký hiệu viết tắt grid hiện có. Đây là ký hiệu viết tắt khá phức tạp và theo kinh nghiệm của chúng tôi, các nhà phát triển ít sử dụng ký hiệu này hơn. Như đã trình bày trong các ví dụ trước, ngay cả khi được dùng cho bố cục xếp kề đơn giản, bạn vẫn cần cẩn thận khi thiết lập thứ tự các giá trị.

Lưu ý khác

Bài đăng này xem xét một số trường hợp sử dụng phổ biến hiện nay, tuy nhiên chúng tôi không biết tương lai sẽ ra sao đối với bố cục lưới hoặc bố cục xếp kề. Một lý do lớn để sử dụng cú pháp display: masonry riêng biệt là nó cho phép hai loại này phân tách trong tương lai. Cụ thể, với các giá trị ban đầu (chẳng hạn như các giá trị cho masonry-template-tracks), bạn có thể làm một số việc khác trong bố cục xếp kề so với bố cục lưới. Chúng ta không thể thay đổi lưới mặc định nếu sử dụng phiên bản display: grid, điều này có thể hạn chế những việc chúng ta muốn làm trong tương lai.

Trong các ví dụ này, bạn có thể thấy những vị trí mà trình duyệt phải bỏ qua các thuộc tính hợp lệ trong lưới nếu sử dụng kiểu xếp kề. Ví dụ: grid-template-areas, trong đó hầu hết các giá trị bị loại bỏ vì giá trị này xác định bố cục lưới hai chiều, trong kiểu xếp kề, chúng ta chỉ xác định đầy đủ một hướng.

Đưa ra ý kiến phản hồi

Hãy xem các ví dụ này cũng như bản đặc tả nháp trình bày từng phiên bản cùng với các phiên bản khác. Hãy cho chúng tôi biết ý kiến của bạn bằng cách bình luận về Vấn đề 9041 hoặc nếu bạn muốn viết bài đăng trên blog của riêng mình hoặc trên mạng xã hội, hãy nhớ cho chúng tôi biết trên X hoặc LinkedIn.