2 điểm bởi GN⁺ 2024-08-17 | 1 bình luận | Chia sẻ qua WhatsApp
  • CSS Grid đã được các trình duyệt chính hỗ trợ rộng rãi từ tháng 3/2017, nhưng grid-template-areas vẫn còn ít được dùng hơn, dù nó cho phép biểu diễn bố cục trực quan ngay trong CSS mà không cần tính số dòng
  • grid-template-areas hoạt động bằng cách sắp tên vùng dưới dạng chuỗi và liên kết các phần tử con bằng grid-area; các tên trùng nhau bắt buộc phải tạo thành một vùng hình chữ nhật
  • Dòng lưới có tên là cách gắn tên cho các dòng như content-start / content-end thay vì dùng số, và mẫu *-start với *-end có thể được trình duyệt tận dụng như vùng ngầm định
  • Với lật thẻ, header responsive, bố cục editorial, bài đăng kiểu Threads, thẻ chồng lấp, và bố cục điều kiện bằng :has(), có thể quản lý biến thể sắp xếp chỉ bằng cách đổi chuỗi vùng ở phần tử cha
  • Chrome, Safari và Firefox đều cung cấp Grid area DevTools; riêng Firefox đặc biệt hữu ích nhờ hiển thị tên vùng rõ ràng và tự động gợi ý tên dòng khả dụng khi chỉnh grid-area

Làm bố cục dễ đọc hơn với grid-template-areas

  • Cách bố trí CSS Grid truyền thống thường dùng kiểu chỉ định trực tiếp số dòng như grid-column: 1 / 3
  • Số dòng không hiển thị cho tới khi kiểm tra trong DevTools, và với bố cục có cả cột lẫn hàng thì rất khó tính đúng số trong đầu
  • grid-template-areas gán tên cho từng ô để bố trí, nên bản thân mã CSS trông giống như bản đồ của bố cục
.page {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: "item1 item2";
  gap: 1rem;
}

.item-1 {
  grid-area: item1;
}

.item-2 {
  grid-area: item2;
}
  • Các phần tử con được ánh xạ vào vùng có tên bằng grid-area
  • Trong ví dụ thẻ, có thể định nghĩa như "featured featured article" để vùng featured chiếm 2 cột và vùng article chiếm 1 cột

Cú pháp và các quy tắc bắt buộc phải tuân thủ

  • grid-template-areas nhận một hoặc nhiều chuỗi vùng
    • Một chuỗi tạo ra bố cục 1 chiều chỉ có cột
    • Nhiều chuỗi tạo thành bố cục nhiều chiều có cả hàng và cột
  • Khi dùng nhiều chuỗi, xuống dòng sẽ giúp bố cục dễ đọc hơn
.element {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "aside main"
    "footer footer";
}
  • Mỗi chuỗi đại diện cho một hàng của lưới, có thể hình dung như một bảng
  • Các vùng được định nghĩa bằng cùng một tên phải là hình chữ nhật trong mã
/* invalid */
.layout {
  grid-template-areas:
    "header header"
    "sidebar main"
    "header footer";
}

/* valid */
.layout {
  grid-template-areas:
    "header header"
    "sidebar main"
    "sidebar footer";
}
  • Mọi hàng phải có cùng số lượng token vùng; dù không dùng một vùng nào đó thì bản thân ô vẫn phải được định nghĩa
  • Ô trống có thể biểu diễn bằng một dấu chấm hoặc nhiều dấu chấm
.element {
  grid-template-areas:
    "aside main"
    "... footer";
}
  • Dấu chấm là null cell token trong đặc tả CSS Grid, biểu thị một ô lưới trống

Quan hệ giữa dòng lưới có tên và vùng

  • Trong CSS Grid, số lượng dòng luôn nhiều hơn số cột một đơn vị
    • 3 cột thì sẽ có 4 dòng lưới
  • Dòng lưới có tên là cách gắn tên riêng cho dòng thay vì dùng số mặc định
.layout {
  grid-template-columns:
    [full-start] 1fr
    [content-start] 2fr
    [content-end] 1fr [full-end];
}

.item {
  grid-column: content-start / content-end;
}
  • Dù đã đặt tên dòng, vẫn có thể tiếp tục dùng dòng số
  • Kích thước track (track size) là kích thước của cột hoặc hàng; các giá trị như 1fr 1fr chính là kích thước track
  • Với dòng có tên, ta đặt tên cho các dòng bao quanh track
.layout {
  display: grid;
  grid-template-columns:
    [aside-start] 200px [aside-end main-start] 1fr [main-end];
}
  • Một dòng có thể mang nhiều tên; trong ví dụ trên, aside-endmain-start là cùng một dòng
  • Nếu định nghĩa tên như aside-startaside-end theo mẫu *-start / *-end, trình duyệt có thể cho phép dùng kiểu như grid-column: aside thông qua tên dòng ngầm định
  • Không cần đặt tên cho mọi dòng; có thể chỉ đặt tên chọn lọc cho các dòng quan trọng
  • Khi bố trí, có thể trộn số và tên như grid-column: 1 / content-end

Quản lý biến thể bố cục bằng chuỗi vùng của phần tử cha

  • Khi dùng grid-template-areas, có thể giữ nguyên tên grid-area của các phần tử con và chỉ thay đổi chuỗi vùng của phần tử cha để đổi toàn bộ bố cục
.aside {
  grid-area: aside;
}

.main {
  grid-area: main;
}

.footer {
  grid-area: footer;
}
  • Giữ nguyên các tên aside, main, footer và chỉ thay chuỗi grid-template-areas là toàn bộ cách sắp xếp sẽ tự cập nhật
  • Việc điều khiển bố cục được tập trung hóa vào phần định nghĩa vùng của phần tử cha nên dễ điều chỉnh hơn

Lật hướng thẻ

  • Với Flexbox, có thể dễ dàng lật hướng thẻ bằng flex-direction: row-reverse
  • Trong CSS Grid, nếu dùng số dòng thì khi đổi hướng phải sửa cả định nghĩa cột lẫn giá trị grid-column của từng phần tử con
  • Nếu dùng vùng có tên, chỉ cần gán ảnh và nội dung của thẻ vào các vùng rồi đổi thứ tự vùng ở phần tử cha
.card {
  display: grid;
  grid-template-columns: 150px 1fr;
  grid-template-areas: "thumb content";
}

.card__thumb {
  grid-area: thumb;
}

.card__content {
  grid-area: content;
}

.card--flip {
  grid-template-columns: 1fr 150px;
  grid-template-areas: "content thumb";
}
  • Cũng có thể biểu diễn cùng bố cục đó bằng thuộc tính rút gọn grid-template
.card--flip {
  grid-template: "content image" / 1fr 150px;
}
  • Thuộc tính rút gọn là tùy chọn; cũng có quan điểm cho rằng dạng đầy đủ dễ đọc hơn

Bố cục header responsive

  • Header có logo, navigation và vùng hành động ban đầu có thể được tạo bằng 3 cột bằng nhau
  • Nếu dùng số dòng, phải chỉ định grid-column cho từng .logo, .nav, .actions
  • Nếu dùng tên vùng, chỉ cần ánh xạ mỗi phần tử con vào logo, nav, actions, rồi thay grid-template-areas của phần tử cha theo từng viewport
.header {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-areas: "logo nav actions";
}

.logo {
  grid-area: logo;
}

.nav {
  grid-area: nav;
}

.actions {
  grid-area: actions;
}
  • Ở kích thước nhỏ, có thể đặt logo và actions trên dòng đầu, còn navigation chiếm toàn bộ chiều rộng
.header {
  grid-template-areas:
    "logo logo actions"
    "nav nav nav";
}
  • Từ 380px trở lên, có thể để logo bên trái và đặt navigation cùng actions ở bên phải
@media (min-width: 380px) {
  .header {
    grid-template-areas:
      "logo nav nav"
      "logo actions actions";
  }

  .nav {
    justify-self: end;
  }
}
  • Từ 900px trở lên, có thể quay lại bố cục một hàng
@media (min-width: 900px) {
  .header {
    grid-template-areas: "logo nav actions";
  }
}
  • Chuỗi vùng hoạt động như một ánh xạ hiển thị trực tiếp cách UI được sắp xếp ngay trong CSS

Ví dụ bố cục editorial

  • Với section gồm tiêu đề, văn bản và hình ảnh, grid-template-areas giúp đổi bố cục theo kích thước viewport một cách dễ dàng
.section {
  display: grid;
  grid-template-areas:
    ". title title"
    "thumb content content";
  gap: 1rem;
}
  • Dấu chấm bên trái tiêu đề là null cell token biểu thị khoảng trống
  • Trong ví dụ section kiểu time.com, các vùng feature, secondary, most-read được dùng cùng với các cột trống ở hai bên
.featured-section {
  display: grid;
  grid-template-areas:
    ". feature most-read ."
    ". secondary most-read .";
  grid-template-columns: 1fr minmax(auto, 57.313rem) minmax(12rem, 18.75rem) 1fr;
  grid-template-rows: minmax(auto, 25rem) 1fr;
}
  • Các cột trống hai bên chủ yếu đóng vai trò tạo khoảng cách trái phải
  • Trong bản responsive, trên màn hình nhỏ sẽ xếp feature, secondary, most-read theo chiều dọc; từ 500px900px trở lên thì thay đổi định nghĩa cột và vùng
  • grid-template-rows có thể được thay thế bằng định nghĩa vùng nên không bắt buộc phải có

Component bài đăng kiểu Threads

  • Khi xem lại CSS của Threads app by Meta, có thể thấy một trường hợp dùng CSS Grid cho component bài đăng
  • Ví dụ gốc bố trí item bằng grid-template-columns, grid-template-rows và số dòng
.postBody {
  grid-column-start: 2;
  grid-row-start: 2;
  grid-row-end: span 3;
}
  • Nhiều biến thể bài đăng có thể được biểu diễn dễ hơn bằng grid-template-areas
.post {
  grid-template-areas:
    "avatar header"
    "avatar body"
    ". body"
    ". footer";
}

.post--reply {
  grid-template-rows: 40px max-content max-content;
  grid-template-areas:
    "avatar header"
    "body body"
    "body body"
    "footer footer";
}

.post--nested {
  grid-template-areas:
    "avatar header"
    "avatar body"
    "line body"
    "footer footer";
}
  • Có thể phân biệt biến thể mặc định, trả lời và lồng nhau chỉ bằng cách nhìn vào chuỗi vùng

Item chồng lấp và tên vùng

  • Trong grid-template-areas, cùng một tên phải tạo thành hình chữ nhật, nên nếu lặp lại cùng tên theo hình không phải chữ nhật thì sẽ không hợp lệ
.layout {
  display: grid;
  grid-template-columns: 1fr 1fr fr;
  grid-template-areas:
    "card tag tag"
    "title title card";
}
  • Ví dụ trên là invalidcard không tạo thành hình chữ nhật
  • Với thẻ chồng lấp, có thể định nghĩa tên vùng mới như thumb-1, thumb-2 rồi dùng các tên đó trong grid-columngrid-row
.card {
  display: grid;
  grid-template-columns: auto auto 1fr;
  grid-template-rows: auto auto;
  grid-template-areas:
    "thumb-1 tag"
    "title thumb-2";
}

.thumb {
  grid-column: thumb-1 / thumb-2;
  grid-row: thumb-1 / thumb-2;
}
  • Tag và title có thể lần lượt đặt vào grid-area và căn chỉnh bằng align-self, justify-self
  • Nếu cần, phải quản lý thứ tự chồng lớp của phần tử con, nhưng trong ví dụ này chỉ cần thứ tự nguồn là đủ
  • Ví dụ chồng lấp này lấy cảm hứng từ trang Oddbird’s Cascading Layouts

:has() và bố cục điều kiện

  • Khi kết hợp selector CSS :has() với Grid area, có thể thay đổi bố cục tùy theo sự tồn tại của một phần tử cụ thể
  • Có thể áp dụng định nghĩa vùng khác nhau cho trường hợp trong <figure> có hoặc không có figcaption
figure {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-areas: "img img img";
  gap: 0.5rem;
}

img {
  grid-area: img;
}

figcaption {
  grid-area: caption;
}

.card:has(figcaption) {
  grid-template-areas:
    "img img caption"
    "img img .";
}

Hỗ trợ hướng đa ngôn ngữ LTR/RTL

  • CSS Grid tự điều chỉnh bố cục theo hướng trang là LTR hay RTL
  • Các vùng lưới có tên cũng đi theo hướng của trang, nên trong thiết lập RTL bố cục sẽ bị đảo lại
  • Có thể xem tài liệu RTL Styling 101 để viết bố cục RTL

Khác biệt về hỗ trợ DevTools

  • Chrome, Safari và Firefox đều cung cấp DevTools cho Grid area
  • Chrome
    • Tên vùng được đặt ở góc trên bên trái nên các vùng có thể trông bị chồng lên nhau
    • Lớp phủ màu có thể làm thay đổi cách thiết kế được nhìn thấy
  • Safari
    • Viền hồng giúp phân biệt item rõ ràng hơn
    • Có thể xem tên dòng
    • Cách hiển thị tên dòng vẫn còn chỗ để cải thiện, chẳng hạn kiểu xếp chồng các dòng
  • Firefox
    • Tên vùng hiển thị rõ ràng hơn Chrome và Safari
    • Cung cấp danh sách tự động hoàn thành khi nhập tên tùy chỉnh như *-start, *-end
    • Khi chỉnh grid-area của item con, nó cung cấp danh sách tất cả tên dòng khả dụng

Tài liệu tham khảo

1 bình luận

 
GN⁺ 2024-08-17
Ý kiến trên Hacker News
  • Bản demo animation khá thú vị, nhưng hóa ra animation đó không được làm bằng CSS, nên hơi tiếc
    Sau khi học Flexbox, tôi đã nghĩ “như vậy là đủ rồi”, và không học sâu về Grid. Có vẻ vẫn có lý do để ưu tiên Grid [0], nhưng nhìn chung tôi chưa từng cần làm việc gì chỉ Grid mới làm được, còn bảng dữ liệu thì tôi dùng <table> thật sự
    [0] https://css-tricks.com/css-grid-replace-flexbox/

    • Học được một công cụ đáp ứng hết những gì mình cần là chuyện tốt
      Tôi chỉ từng dùng Grid cho gallery ảnh responsive như https://labs.jensimmons.com/2016/examples/image-gallery-grid... hoặc các thẻ responsive như https://every-layout.dev/demos/grid-cards/. grid-template-columns đáng để học, còn grid-gap thì tiện. Ngoài ra thì cảm giác Flexbox xử lý được gần như mọi thứ
      Tuy nhiên grid-template-areas thì tôi vẫn thấy hơi lửng lơ. Bài viết đưa ra lý do như dễ điều chỉnh layout theo từng breakpoint hoặc “khi thành viên trong nhóm cần thay đổi layout”, nhưng cũng có thể đơn giản là tôi không phải độc giả mục tiêu
    • Một công cụ thú vị để học Grid: https://cssgridgarden.com/
    • Flex đủ dùng trong hầu hết trường hợp, nhưng Grid cũng có chỗ để dùng. Chẳng hạn layout thẻ 3 cột thu về mỗi hàng một thẻ trên màn hình nhỏ, cấu trúc trang có sidebar riêng, hoặc các phần tử cần giữ một cách sắp xếp nhất định ngay cả khi đang thay đổi kích thước
      Cứ dùng cả hai tùy nhu cầu; kết hợp lại thì chúng trở thành bộ công cụ layout rất mạnh
    • “Không, Flexbox không ‘đủ tốt’ đâu”
      https://www.youtube.com/watch?v=MWWcZzossc8
  • Khoan đã, 1/3 không phải là phân số mà là phạm vi từ 1 đến 3 à? Không hiểu sao lại chọn cú pháp như vậy. Trong lập trình có rất nhiều cú pháp hợp lý và quen thuộc để biểu diễn phạm vi, ví dụ như 1..3

    • Điều đầu tiên cần biết về CSS là CSS không dùng cách biểu đạt của ngôn ngữ lập trình, mà dùng ngôn ngữ của layout in ấn
      Có vẻ khá nhiều vấn đề lập trình viên gặp với CSS bắt nguồn từ hiểu lầm này
    • Tôi thích tính năng Grid, nhưng cú pháp của nó khá khác với phần còn lại của CSS nên dễ gây nhầm lẫn. Trông như góc này được tách riêng để làm, hoặc như dấu vết của cách tiếp cận kiểu “lần này hãy làm cho đúng”
    • Hai bên dấu gạch chéo không chỉ có số, mà cũng có thể là nhiều từ: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column...
    • Cứ tưởng tượng việc nói với lập trình viên rằng trong CSS, !important không có nghĩa là “không quan trọng”, mà là “quan trọng!”
  • Tôi vẫn chưa nắm chắc cả Grid lẫn Flexbox. Chiến lược layout cuối cùng mà tôi còn xử lý tương đối tốt là float. Đọc bài này khiến tôi tự tin sẽ thử dùng CSS Grid khi thiết kế layout tiếp theo, và bài viết cũng được làm rất tốt

    • Nếu đã từng xử lý float, thì Grid và Flex sẽ dễ hơn nhiều. Cứ dành một hai ngày tạo vài layout là được. Khác với thời phải vật lộn với trình duyệt cũ, hai thứ này đơn giản là hoạt động tốt, thật ra còn hơi nhàm chán
      Có nhiều bài hay, nhưng chỉ đọc hai bài này của CSS-Tricks là tôi thấy đủ
      https://css-tricks.com/snippets/css/a-guide-to-flexbox/
      https://css-tricks.com/snippets/css/complete-guide-grid/
    • Không học Grid thì vẫn có thể xoay xở ở mức nào đó, nhưng Flexbox gần như là bắt buộc. Vì nó tiện hơn các hack dùng float ngày trước rất nhiều và nằm nền trong CSS hiện đại nói chung
      Ngoài các bài CSS-Tricks đã nêu, tôi cũng khuyên đọc hướng dẫn Flexbox của MDN[1] và tài liệu tham khảo “CSS flexible box layout”[2]. Chúng giúp hiểu sâu hơn các khái niệm, thuộc tính và shorthand property phía sau Flexbox thực sự hoạt động ra sao
      [1]: https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layou...
      [2]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexibl...
    • Flexbox giống như phiên bản làm cho đúng của hệ thống lưới dựa trên float. Bạn có thể sắp xếp phần tử con theo chiều dọc hoặc chiều ngang, còn float dùng hack clearfix thực chất chỉ bố trí theo từng hàng
      Tuy vậy Flexbox cũng gần với layout một chiều có thể xuống dòng, nên mẹo là lồng và xếp chồng các phần tử. Grid thì có template, các phần tử con trực tiếp chiếm những vùng đã định sẵn, nên tĩnh hơn Flexbox; nó cũng có hạn chế là không ảnh hưởng đến các phần tử lồng bên trong. Dù vậy có vẻ subgrid sẽ thay đổi phần đó
    • Nếu đã hiểu float, chỉ riêng điều đó đã là một thành tựu hiếm rồi, nên bạn hẳn sẽ dùng Flex/Grid khá vui vẻ
    • Grid có nhiều tính năng, nhưng Flex thì đủ đơn giản mà vẫn cực kỳ mạnh
  • Tài liệu liên quan:
    Grid Garden https://cssgridgarden.com
    Flexbox Froggy https://flexboxfroggy.com

  • Ước gì có một phiên bản “trước nhập môn” còn cơ bản hơn tài liệu này. Mình đã bị mắc ngay từ phần giới thiệu nên không đi tiếp được. Đặc biệt là đoạn “để bố trí các item con bên trong Grid, cần chỉ định số đường của từng item bằng grid-column”, mình không hiểu số đường ở đây là gì
    Mình cứ nghĩ đọc theo ngữ cảnh rồi sẽ hiểu, nhưng ngay sau đó lại bị kẹt ở các biểu thức như 1 / 3, 1 / 4

    • Số đường là các đường chia giữa các cột. Nếu có 2 cột thì sẽ có 3 đường: trong |a||b|, hai đường ở giữa thực ra được tính là một, nên tổng cộng là 3 đường
      Vì vậy 1/3 không phải là phân số mà là phạm vi cột, nghĩa là “bắt đầu từ đường số 1 và kết thúc ở đường số 3”
    • Chỉ cần cuộn xuống dưới một chút là có demo trực tiếp để tự thao tác và xem chuyện gì xảy ra
      Tên gọi “số đường” không hay lắm, nhưng thực chất đó là mép của các cột. Vì vậy 1/3 đi từ mép số 1, tức mép ngoài cùng bên trái, đến mép số 3, và chiếm toàn bộ 2 cột
  • Với CSS Grid, mình cực kỳ khuyên xem Jen Simmons Mondrian with auto flow. Chỉ cần vào https://labs.jensimmons.com/2017/01-011.html, nhấn CD rồi thay đổi kích thước cửa sổ. Cũng có video YouTube để xem cùng: https://www.youtube.com/watch?v=qNtJ5p3h2A4
    Thực sự rất tuyệt
    Điều mình vẫn muốn hiểu ở auto flow là cách phát hiện và lấp các ô trống. Khi có các đối tượng kích thước khác nhau được đặt ngẫu nhiên, làm thế nào để auto flow không để lại ô trống? Hoặc có thể phát hiện ô trống rồi thêm gì đó vào không?

  • Hy vọng đây không phải câu hỏi ngốc, nhưng tại sao cú pháp lại được định nghĩa bằng dấu gạch chéo như 1/2, 3/4? Viết kiểu từ cột 1 đến cột 2 như 1-2, hoặc 1->2 chẳng phải tự nhiên hơn sao?

    • Số cột có thể là số âm. Vậy trong 1--1, 1->-1, 1/-1 thì cái nào tốt hơn?
    • Mũi tên có thể cũng được, nhưng việc có khoảng trắng ở hai bên là có lý do. Không phải chỉ có số mới xuất hiện được: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column...
      Trong CSS, các giá trị vốn đã được phân tách bằng khoảng trắng, và nếu xét thêm trực giác thông thường khi thấy dấu gạch ngang, thì cách dưới đây tốt hơn nhiều
      grid-column: 4 somegridarea / 6;
      grid-column: span 3 / 6;
      grid-column: span somegridarea / span someothergridarea;
      Rõ ràng hơn rất nhiều so với viết như dưới đây
      grid-column: 4 somegridarea-6;
      grid-column: span 3-6;
      grid-column: span 3->6;
      grid-column: span somegridarea-span someothergridarea;
      grid-column: span somegridarea->span someothergridarea;
  • Mình rất thích kiểu bài blog tương tác như thế này. Với Grid, mình rất khuyến khích trực tiếp thử grid area bằng các công cụ như https://grid.layoutit.com/
    Mình đã dùng trang đó để lên kế hoạch layout Grid suốt vài năm nay, và việc chỉnh khoảng cách trở nên dễ hơn nhiều

  • Có lẽ đây là lần đầu tiên mình thực sự hiểu CSS Grid. Hiển thị số giúp ích rất nhiều, và đây sẽ là bài mình thường xuyên tham khảo sau này

    • Trong công cụ dành cho nhà phát triển của Firefox cũng có thể bật hiển thị các số đó theo mặc định. Chrome thì mình không chắc
  • Mình thích CSS Grid và khái niệm area, nhưng vẫn nghĩ phần khó nhất là quản lý responsive, đặc biệt giữa kích thước mobile và desktop. Tùy UI element nào cần mở, có cần toàn màn hình hay không, nhiều khi phải cập nhật grid-template-area và kích thước hàng/cột bằng JavaScript
    Mình vẫn chưa tìm được thế giới nơi minmax hay calc giải quyết được chuyện này, và hy vọng có ai đó biết câu trả lời

    • https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_contain...
    • Trong trường hợp này, một cách hay là vẫn dùng Grid như cũ nhưng đặt giá trị hàng/cột bằng biến CSS như var(--foo) thay vì giá trị cố định
      Khi đó JavaScript chỉ cần cập nhật giá trị của biến tương ứng, và Grid sẽ phản ánh giá trị đó
    • Mình khá ngạc nhiên là bài viết không nhấn mạnh template area tốt thế nào cho responsive. Dùng media query, bạn có thể định nghĩa các vùng Grid khác nhau cho từng màn hình, rồi di chuyển từng phần tử đến vị trí mong muốn phù hợp với kích thước màn hình đó. Nếu cần ẩn phần tử ở một kích thước cụ thể, chỉ cần đặt display: none ở kích thước đó
      Ví dụ rất đơn giản: https://codepen.io/trescenzi/pen/vYqpjvL
    • Có vẻ khá nhiều trường hợp như vậy có thể giải bằng :has() hoặc subgrid, nhưng mình chưa có nhiều trải nghiệm trực tiếp
    • Bạn đã thử dùng media query chưa?