- CSS Subgrid là một tính năng cho phép mở rộng cấu trúc Grid hiện có vượt qua các giới hạn trước đây, để cả các phần tử DOM con bên dưới cũng có thể tham gia vào cấu trúc lưới của phần tử cha
- Trước đây chỉ các phần tử con trực tiếp mới có thể tham gia vào Grid, nhưng với subgrid, các cấu trúc lồng nhau như
<ul>·<li> cũng có thể được sắp xếp vào cùng các ô lưới
- Nó giải quyết sự mất cân đối giữa các phần tử anh em phát sinh do chênh lệch độ dài nội dung, đồng thời hỗ trợ tạo bố cục mà mỗi thẻ hoặc mỗi section có thể phản hồi động
- Tuy vậy vẫn có những điểm cần lưu ý như vấn đề đặt trước hàng, đánh số lại line, và không tương thích với fluid grid dựa trên auto-fill
- Tính năng này đã được hỗ trợ trên các trình duyệt lớn và có thể áp dụng dần dần, hứa hẹn nâng cao đáng kể độ linh hoạt trong thiết kế UI trong tương lai
Khái niệm cơ bản về Subgrid
- CSS Grid ban đầu chỉ cho phép các phần tử con trực tiếp tham gia vào bố cục
- Ví dụ, trong UI portfolio, các ảnh trong
<li> bên trong <ul> về cơ bản sẽ bị gói vào cùng một ô
- Khi dùng
grid-template-rows: subgrid, grid-template-columns: subgrid, ta có thể kế thừa định nghĩa hàng và cột từ grid cha
- Nhờ đó, mỗi
<li> có thể được đặt trực tiếp vào các ô của grid cha, vừa giữ được cấu trúc HTML mang tính ngữ nghĩa, vừa duy trì căn chỉnh trực quan
- Có thể đạt kết quả tương tự bằng Flexbox và Grid lồng nhau, nhưng subgrid mang lại cách tiếp cận gọn gàng hơn nhờ chia sẻ một cấu trúc grid duy nhất
Những khả năng bố cục mới
- Trong ví dụ thẻ portfolio, mỗi
<article> có một grid 2 cột để bố trí hình ảnh và văn bản
- Đơn vị
fr linh hoạt, nhưng vì mỗi thẻ tự tính toán độc lập nên dễ phát sinh mất cân đối về độ rộng cột
- Khi áp dụng
grid-template-columns: subgrid, mọi thẻ sẽ chia sẻ cùng một tỷ lệ cột của grid cha
- Khi nội dung thay đổi, chẳng hạn độ dài tiêu đề, toàn bộ grid sẽ tự động được điều chỉnh lại
- Với cách này có thể hiện thực bố cục có nhận thức lẫn nhau giữa các phần tử anh em
- Ví dụ: nếu rút ngắn tiêu đề “Infinite Supercomputer”, tỷ lệ ảnh và văn bản của toàn bộ các thẻ sẽ được điều chỉnh ngay lập tức
Những điểm cần chú ý khi dùng Subgrid (Gotchas)
Đặt trước không gian hàng
- Việc chia sẻ cột khá trực quan, nhưng khi chia sẻ hàng thì cần đặt trước số hàng một cách tường minh
- Ví dụ: trong thẻ bảng giá, nếu muốn các mục của từng
<ul> thẳng hàng trên cùng một hàng thì cần chỉ định số lượng hàng bằng grid-row: span N
- Theo mặc định, subgrid chỉ chiếm một ô duy nhất, nên nếu muốn dùng nhiều hàng thì trước hết cần mở rộng vùng grid của phần tử cha
Đánh số trong grid lồng nhau
- Subgrid kế thừa template hàng và cột của phần tử cha, nhưng số line sẽ được đánh lại
- Ví dụ: dù kế thừa line 2 đến 5 của phần tử cha, bên trong nó vẫn sẽ được đánh số lại thành 1 đến 4
- Mỗi grid có chỉ mục riêng, nên số line hoạt động như chỉ mục tương đối chứ không phải ID duy nhất
Không tương thích với fluid grid
- Fluid grid có dạng
repeat(auto-fill, minmax()) không thể dùng cùng subgrid
- Subgrid cần số lượng cột đã được xác định, nên không hỗ trợ
auto-fill·auto-fit
- Tác giả cũng nói rõ rằng họ chưa tìm ra cách giải quyết cho tổ hợp này
Hỗ trợ trên trình duyệt cũ
- Từ sau năm 2023, tính năng này đã được hỗ trợ trên các trình duyệt lớn, nhưng tỷ lệ hỗ trợ vẫn dưới 90%
- Có thể cung cấp bố cục thay thế bằng điều kiện
@supports not (grid-template-columns: subgrid)
- Ví dụ: đề xuất một cấu trúc fallback xếp ảnh và văn bản theo chiều dọc
Ví dụ thực tế và kết luận
- Trang dành cho nhà phát triển của Stripe (stripe.dev) tổ chức toàn bộ trang dưới dạng một grid lớn duy nhất, và hiện thực cách bố trí chi tiết thông qua nhiều tầng subgrid
- Subgrid không chỉ hữu ích cho các bố cục quy mô lớn mà còn phù hợp với những tinh chỉnh UI nhỏ
- Có thể triển khai dần dần mà không cần tái cấu trúc toàn bộ dự án
- Đây là một công cụ mới giúp mở rộng độ linh hoạt của bố cục CSS, rất đáng để thử nghiệm trong thực tế
1 bình luận
Ý kiến trên Hacker News
Tính năng subgrid thực sự rất tuyệt, nhưng ở ví dụ đơn giản đầu tiên, cũng có thể dùng
ul { display: contents }để các phần tử con tham gia vào bố cục gridNếu không nhất thiết phải dùng subgrid thì cách này hiệu quả hơn
display: contentssẽ loại bỏ hoàn toàn phần tử UL khỏi layoutVì vậy không thể áp dụng style hoặc nhận sự kiện UI trên phần tử đó
Nếu muốn dùng UL làm vùng highlight hoặc một section có thể cuộn, thì subgrid hữu ích hơn nhiều
fr, và dùngfrcho phần văn bản để nó lấp đầy không gian còn lạiTrước đây khi làm UI so sánh giá, tôi đã rất khổ sở vì không có subgrid
Việc đặt hai bảng cạnh nhau rồi căn các hàng cho khớp là bất khả thi
Có thể xử lý bằng chiều cao cố định hoặc tính toán bằng JS, nhưng trong cấu trúc component React thì quá kém hiệu quả
Tôi từng nghĩ container queries có phải là lời giải tốt hơn không
Nhưng để giữ tính nhất quán của toàn bộ grid thì subgrid có thể phù hợp hơn
Nhân tiện, xem ví dụ CodePen sẽ dễ hiểu hơn
Hơn nữa, dùng container sẽ tạo ra stacking context mới nên khá bất tiện
Thật tiếc là không thể dùng subgrid cùng với container. Nếu phần tử con có thể tham chiếu kích thước của subgrid thì sẽ cực kỳ mạnh mẽ
Tôi có cảm giác như “rốt cuộc lại quay về layout bằng <table> à?”
<table>ngày xưa là một kiểu hack để giải quyết vấn đề, nhưng có nhiều giới hạn về khả năng truy cập và kỹ thuậtHệ thống Grid là công cụ cho việc sắp xếp trực quan, khác với bảng dùng để biểu diễn cấu trúc dữ liệu
Giờ grid đã trở thành tiêu chuẩn, nên tôi mong mọi người đừng tiếp tục so sánh nó với table nữa
Nhưng hoàn toàn không tính đến responsive hay accessibility. Rốt cuộc chúng ta như đang phát minh lại table vậy
<table>là nó là một cấu trúc dùng để mô tả nội dung. Bản thân grid thì không có vấn đề gìRốt cuộc CSS chỉ là tái hiện lại chức năng đó dưới một hình thức được cải tiến hơn
Một trong những lỗi grid tôi từng gặp là khi đặt kích thước phần tử
<img>bằng đơn vị phần trăm, kích thước ô bị méo theo kích thước ảnh gốcNó xảy ra trên cả Firefox và Chromium, và bug liên quan nằm ở Mozilla Bug 1857365
Thật đáng tiếc khi CSS đôi lúc buộc phải thêm thông tin về cấu trúc tài liệu chỉ để phục vụ layout
Ví dụ như phải khai báo rõ số lượng hàng
Hoặc sẽ rất hay nếu một flex container có thể mô phỏng cách phân bố của container khác
Nhưng làm vậy có thể khiến DX trở nên phức tạp hơn nhiều
Tôi thắc mắc vì sao trong ví dụ code lại có style nằm ở cả file HTML lẫn CSS
Chỉ nhìn CSS của ví dụ subgrid đầu tiên, tôi đã mất khá lâu để tìm xem UL đang được áp dụng style gì
Tôi lại có cảm giác như “rốt cuộc lại quay về grid à?”
Thời HTML trước đây chúng ta cũng từng làm những thứ tương tự
Bài viết trên blog của Josh lúc nào cũng đáng ngưỡng mộ
Độ rõ ràng trong cách viết, cảm quan thiết kế, và cả website có tính tương tác đều rất xuất sắc
Cá nhân tôi vẫn thấy grid khó dùng
Cú pháp khá gượng gạo và cảm giác về layout cũng không hợp lắm. Flexbox trực quan và linh hoạt hơn nhiều
Flexbox kiểm soát kích thước theo hướng nội dung, còn Grid theo hướng container
Nội dung không tự động khớp theo nhiều trục, và mọi thứ đều phải đặt bằng tay
Có lẽ là tôi chưa hiểu đúng bản chất của grid, hoặc kiểu công việc của tôi không phù hợp với nó