Chuyển đến nội dung
MINH VO Ghi chép từ công việc
của một kỹ sư tại Việt Nam
Cơ bản10 phút đọc

Cột Grid vừa nội dung: tính số cột và hiểu cột trống

Tính ngưỡng đổi số cột Grid, phân biệt cột trống với ô trống ở hàng cuối, rồi thử auto-fit, auto-fill và nội dung gây tràn.

Các bố cục trình duyệt bằng giấy màu ô liu và be mô tả trang máy tính và trang di động hẹp hơn

Một danh sách thẻ tự co giãn không cần mốc chuyển bố cục riêng cho từng số cột. Khi bạn biết chiều rộng tối thiểu hữu ích của một thẻ và khoảng cách giữa các thẻ, Grid có thể tính số cột vừa chỗ. Phần cần cân nhắc là yêu cầu nào được phép nhường khi vùng chứa hẹp hơn cả một thẻ.

Ví dụ này dành cho bạn đã biết định kiểu một khối và muốn dự đoán biểu thức Grid tự động sẽ bố trí các thẻ như thế nào. Ta dùng khối thông thường với hướng viết ngang từ trái sang phải, chiều rộng nội dung khả dụng, bốn thẻ không trải qua nhiều cột và không có quy tắc đặt vị trí bổ sung. Nếu phần tử tổ tiên co theo kích thước nội tại của nội dung, bạn cần phân tích riêng; giá trị tối thiểu theo phần trăm không độc lập với vùng chứa.

Bắt đầu bằng bốn thẻ thông thường

Các liên kết dưới đây dùng địa chỉ minh họa hư cấu. Hãy thay bằng đường dẫn ghi chú thực khi đưa thành phần vào ứng dụng. Mỗi thẻ có một liên kết, tiêu đề có nghĩa và không dùng mã để biến toàn bộ vùng văn bản thành vùng bấm. Vai trò danh sách được khai báo rõ để giữ quan hệ này khi bỏ dấu đầu dòng; MDN giải thích vì sao điều đó cần thiết trong Safari.

<ul class="cards" role="list">
  <li><h2><a href="https://example.com/notes/forms">Nhãn biểu mẫu</a></h2>
    <p>Gắn trường nhập với tên mà người đọc sử dụng.</p></li>
  <li><h2><a href="https://example.com/notes/images">Lựa chọn hình ảnh</a></h2>
    <p>Chọn văn bản thay thế theo mục đích của hình.</p></li>
  <li><h2><a href="https://example.com/notes/keyboard">Đường đi bàn phím</a></h2>
    <p>Đi qua các điều khiển theo thứ tự tài liệu.</p></li>
  <li><h2><a href="https://example.com/notes/tables">Tiêu đề bảng</a></h2>
    <p>Giữ mỗi giá trị gắn với hàng và cột của nó.</p></li>
</ul>
.cards {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cards > li {
  box-sizing: border-box;
  padding: 1rem;
  border: 1px solid #777;
  overflow-wrap: anywhere;
}
.cards h2 { margin: 0 0 .75rem; font-size: 1.25rem; }
.cards p { margin: 0; }
.cards a { color: inherit; }
.cards a:focus-visible { outline: 3px solid #526b32; outline-offset: 3px; }

Đọc biểu thức kích thước cột từ trong ra ngoài. Hàm min chọn giá trị nhỏ hơn giữa chiều rộng khả dụng và mười sáu đơn vị cỡ chữ gốc. Giá trị đó làm giới hạn dưới của dải cột, gọi là track. minmax cho phép cột lớn lên từ giới hạn dưới này; 1fr chia phần không gian khả dụng cho các cột linh hoạt tương đương. repeat yêu cầu số lần lặp vừa chỗ theo các quy tắc tính kích thước đã chỉ định.

Khi cỡ chữ tính toán của phần tử gốc là 16px, chiều rộng tối thiểu ưu tiên là 256px. Với vùng chứa rộng 220px, biểu thức min bên trong chọn 220px, nên một cột có thể vừa chỗ. Nếu thay biểu thức đó bằng 16rem cố định, cột vẫn cần 256px. Lúc này thẻ đã tràn trước khi văn bản hoặc hình ảnh bên trong có cơ hội gây vấn đề.

Mười sáu đơn vị là lựa chọn thiết kế, không phải kết luận của trình duyệt về khả năng đọc. Hãy dùng tiêu đề và mô tả tiêu biểu để chọn giá trị. Trong ví dụ này, phần đệm và đường viền nằm bên trong chiều rộng thẻ được đo; bản thân lưới không có hai phần đó. Phép tính dùng chiều rộng nội dung của lưới, không dùng chiều rộng ngoài của khung bao quanh nó.

Tính ngưỡng rồi đo lại

Với cỡ chữ gốc trên, khoảng cách 1.5rem bằng 24px. Ba cột ở mức tối thiểu ưu tiên cần ba lần 256 cộng hai khoảng cách, tức 816px. Bốn cột cần 1096px. Số khoảng cách ít hơn số cột một đơn vị; nếu thêm khoảng cách ở cả hai mép, bạn đang tính một bố cục khác.

Ở chiều rộng 1000px, ba cột vừa chỗ. Trừ 48px cho hai khoảng cách rồi chia 952px còn lại cho ba, mỗi cột rộng khoảng 317,33px. Ở chiều rộng 800px chỉ còn hai cột, mỗi cột rộng 388px. Hướng dẫn khái niệm Grid giải thích cách đơn vị phân số chia không gian khả dụng: 1fr không phải một phần ba toàn bộ vùng chứa trước khi trừ khoảng cách.

Ba cột đạt mức tối thiểu 256 pixel trong vùng chứa 816 pixel; bốn cột cần 1096 pixel, còn một cột có thể thu về vùng chứa 220 pixelMở ảnh kích thước đầy đủ ↗

Các hàng trong hình dùng cùng một tỉ lệ, nên bạn thấy rõ phần chiều rộng phải thêm cho cột thứ tư và khoảng cách của nó. Ngay tại ngưỡng, các cột bằng đúng mức tối thiểu ưu tiên. Ngay dưới ngưỡng, bố cục đổi số cột thay vì ép từng cột hẹp thêm một chút.

Những con số này phụ thuộc vào cỡ chữ tính toán của phần tử gốc, không phải mốc cố định của khung nhìn. Nếu cỡ chữ gốc thành 32px, mức tối thiểu ưu tiên thành 512px và khoảng cách thành 48px. Hai cột lúc này cần 1072px. Vì thế lưới rộng 1000px chỉ có một cột, kể cả trên màn hình rộng. Một thanh bên cũng có thể làm giảm chiều rộng khả dụng mà không thay đổi khung nhìn.

Cột trống khác với ô trống

Tài liệu repeat và đặc tả Grid phân biệt auto-fill với auto-fit. Cả hai đều xác định trước số lần lặp vừa chỗ. Sau khi đặt các phần tử, auto-fit thu cột lặp trống về chiều rộng 0, đồng thời thu các khoảng cách bên cạnh cột đó. Một cột được coi là trống khi không có phần tử trong luồng bố cục nào nằm trong hoặc trải qua nó ở bất kỳ hàng nào của lưới.

Nếu chỉ có hai thẻ trong vùng rộng 1000px, auto-fill giữ ba cột, mỗi cột khoảng 317,33px. Cột thứ ba bỏ trống. auto-fit thu cột đó lại, để lại một khoảng cách và hai thẻ rộng 488px. Đây là lựa chọn thiết kế: một tập kết quả nhỏ nên giãn ra hết chỗ, hay nên giữ chiều rộng gần với lúc lưới đầy hơn?

Đưa đủ bốn thẻ trở lại. Hàng đầu dùng cả ba cột, thẻ thứ tư bắt đầu hàng thứ hai. Không cột nào trống trên toàn bộ lưới, nên cả hai từ khóa đều không thu cột nào. Thẻ cuối vẫn rộng khoảng 317,33px. auto-fit không có nghĩa là mỗi hàng được phân phối lại không gian một cách độc lập.

Hai thẻ với auto-fill để lại cột thứ ba trống; auto-fit giãn mỗi thẻ tới 488 pixel, nhưng bốn thẻ vẫn giữ ba cột và thẻ cuối hẹp như các thẻ khácMở ảnh kích thước đầy đủ ↗

Các ô trống bên cạnh thẻ thứ tư không phải là cột trống. Nếu yêu cầu thực sự là giãn riêng từng hàng chưa đầy, hãy cân nhắc Flexbox có xuống dòng. Cách đó đưa ra cam kết khác về việc thẳng cột giữa các hàng. Hiểu sự đánh đổi này hữu ích hơn việc coi một hệ bố cục luôn tốt hơn hệ còn lại.

Chạy đoạn chẩn đoán sau trong console của ví dụ bốn thẻ, khi cỡ chữ gốc là 16px. Nó tạm đặt lưới rộng 1000px, so sánh hai từ khóa, rồi khôi phục các nút con và thuộc tính style nội tuyến ban đầu. Đây là thí nghiệm cho tài liệu riêng này, không phải mã kết xuất ứng dụng hay công cụ kiểm tra Grid tổng quát.

{
  const grid = document.querySelector('.cards');
  const originalNodes = [...grid.childNodes];
  const items = [...grid.children];
  const originalStyle = grid.getAttribute('style');
  const rows = [];
  try {
    grid.style.inlineSize = '1000px';
    for (const count of [2, 4]) {
      grid.replaceChildren(...items.slice(0, count));
      for (const mode of ['auto-fit', 'auto-fill']) {
        grid.style.gridTemplateColumns =
          `repeat(${mode}, minmax(min(100%, 16rem), 1fr))`;
        const first = grid.firstElementChild.getBoundingClientRect();
        const last = grid.lastElementChild.getBoundingClientRect();
        rows.push({
          count, mode,
          firstWidth: Number(first.width.toFixed(2)),
          lastWidth: Number(last.width.toFixed(2)),
          lastOnAnotherRow: last.top > first.top
        });
      }
    }
    console.table(rows);
  } finally {
    grid.replaceChildren(...originalNodes);
    if (originalStyle === null) grid.removeAttribute('style');
    else grid.setAttribute('style', originalStyle);
  }
}

Các dòng với hai thẻ dự kiến hiển thị 488px cho auto-fit và khoảng 317,33px cho auto-fill. Cả hai dòng với bốn thẻ dự kiến cho khoảng 317,33px và báo rằng thẻ cuối bắt đầu hàng khác. Sai khác nhỏ ở phần thập phân là bình thường khi đo bố cục. Chương trình đọc hộp đường viền; vì các thẻ giãn vừa dải cột trong ví dụ này, những chiều rộng đó cũng cho biết chiều rộng dải cột.

Thử nội dung không chịu co theo bố cục

Hàm min bên trong loại bỏ một nguyên nhân gây tràn. Nó không làm mọi phần tử con tự co giãn. Thêm hình rộng cố định 500px vào trường hợp vùng chứa 220px, hình có thể tràn khỏi một thẻ vẫn được tính kích thước đúng. Với hình thông thường, max-inline-size: 100%; block-size: auto giới hạn chiều rộng mà giữ tỉ lệ. Một đoạn mã giữ nguyên định dạng có thể cần vùng cuộn ngang riêng.

Quy tắc của thẻ dùng overflow-wrap: anywhere để tiêu đề dài liền mạch có thể xuống dòng. Nó không cắt bớt văn bản gốc. Bỏ quy tắc này rồi dán một định danh dài để quan sát sự khác nhau giữa ranh giới thẻ và phần nội dung được vẽ ra ngoài. Đừng hạ mức tối thiểu của mọi cột để che một phần tử con có yêu cầu không phù hợp.

Để nội dung quyết định chiều cao thẻ. Các cột bằng nhau không đòi hỏi lượng văn bản giống nhau; bản dịch dài hơn nên làm hàng cao lên thay vì biến mất sau giới hạn chiều cao cố định. Nếu cần căn thẳng phần cuối các thẻ, hãy cho bên trong mỗi thẻ một bố cục riêng, thay vì giả định lưới bên ngoài giải quyết luôn việc đó.

Giữ trình tự có ích trong mã nguồn

Cách đặt theo hàng thông thường đi theo thứ tự nguồn của danh sách này. Vị trí chỉ định riêng, order hoặc chế độ xếp dày dense có thể đổi vị trí nhìn thấy mà không đổi thứ tự di chuyển tuần tự mặc định. Phần khả năng tiếp cận của đặc tả nêu rõ sự khác biệt đó. Xếp dày lấp các chỗ trống do cách đặt phần tử; nó không phải giải pháp masonry tổng quát cho mọi thẻ cao thấp khác nhau.

Nhấn Tab qua bốn liên kết, rồi bỏ định kiểu và đọc danh sách. Cả hai cách nên cho cùng một trình tự có ích. Cũng hãy thử không có thẻ, một thẻ, hai thẻ và bốn thẻ. Với auto-fit, lưới lặp hoàn toàn trống có thể thu tất cả các dải cột; ứng dụng vẫn phải cung cấp thông báo kết quả trống dễ hiểu của riêng mình.

Bài tập cuối là đổi khoảng cách thành 2rem với cỡ chữ gốc 16px. Ba cột lúc này cần 832px, bốn cột cần 1120px. Với chiều rộng nội dung 820px, hãy dự đoán hai cột rộng 394px rồi kiểm tra trong trình duyệt. Sau đó tăng cỡ chữ gốc, đặt lưới trong vùng chứa hẹp và thêm một tiêu đề dài hơn nhiều. Chỉ giữ biểu thức tự động nếu các trường hợp đó vẫn đáp ứng yêu cầu đọc và điều hướng ban đầu của bạn.

Nguồn tham khảo & đọc thêm

  1. MDN: basic concepts of Grid layout
  2. MDN: repeat, auto-fill and auto-fit
  3. MDN: the min function
  4. CSS Grid Level 2: automatic tracks, placement and accessibility
  5. MDN: list-style accessibility
← Về trang bài viết

Hình minh họa

100%