4 điểm bởi GN⁺ 2024-02-25 | 1 bình luận | Chia sẻ qua WhatsApp
  • Với các bảng có nhiều hàng, càng cuộn thì càng dễ quên ý nghĩa của từng cột, khiến việc đọc dữ liệu trở nên bất tiện
  • Chỉ cần thêm position: sticky;top: 0; vào thead là có thể triển khai cố định header
  • sticky có mức hỗ trợ trình duyệt khoảng 96% trên toàn cầu, nên không còn gần với một tính năng thử nghiệm
  • Ngay cả khi xem các hàng ở phía dưới như mục thứ 300, tiêu đề cột vẫn còn hiển thị, giúp trải nghiệm duyệt bảng tốt hơn
  • Cách triển khai tuy nhỏ nhưng hiệu quả lớn, nên với các trang web cung cấp bảng dài, đây là cải thiện tính dễ dùng cơ bản đáng áp dụng

Vấn đề header biến mất trong các bảng dài

  • Với tập dữ liệu lớn hoặc bảng có hàng trăm hàng, sau khi cuộn, header của bảng sẽ biến mất khỏi màn hình
  • Khi kéo xuống đến mục thứ 300, có thể sẽ khó kiểm tra lại dữ liệu của từng cột biểu thị điều gì
  • Bảng càng mới với người xem thì họ càng phải vừa đọc vừa ghi nhớ ý nghĩa của các cột, làm tăng gánh nặng khi duyệt

Áp dụng sticky cho thead

  • Cách giải quyết là thêm hai thuộc tính CSS vào thead
position: sticky;
top: 0;
  • Khi dùng position: sticky cùng với top: 0, có thể cố định header ở phía trên màn hình ngay cả trong lúc cuộn
  • stickytỷ lệ hỗ trợ khoảng 96% trên toàn cầu, nên có thể dùng trên nhiều trình duyệt
  • Có thể kiểm tra cách hoạt động thực tế trong ví dụ CodePen

1 bình luận

 
GN⁺ 2024-02-25
Các ý kiến trên Hacker News
  • Tôi chấp nhận header cố định trên một trục, nhưng vẫn đang chờ ngày CSS hỗ trợ trên cả hai trục: https://github.com/w3c/csswg-drafts/issues/8286

    • Một trong những việc khó nhất là một hợp đồng mà tôi phải cố định cả cột lẫn header Nếu là bảng chuẩn thì dễ, nhưng đây là một bảng động bên thứ ba bằng VueJS phức tạp dùng CSS-as-JS được sinh ra, nên chỉ riêng việc xác định CSS và JS đến từ đâu đã mất rất lâu, và cuối cùng tôi phải ghi đè cả hàm class JS lẫn CSS được sinh ra Tôi thấy có lỗi với khách hàng vì mất quá nhiều thời gian, và từ đó cẩn thận hơn nhiều khi chọn thư viện trong codebase Vue/React. Bảng là phần tử cơ bản của HTML, vậy mà tôi không hiểu vì sao chỉ một việc đơn giản lại cần đến ba lớp class JS và cả CSS import bằng JSON
    • Tôi có lẽ đã theo dõi issue gốc sinh ra issue này 8 năm rồi, và đây là phần khó chịu nhất trong đặc tả CSS Đôi khi ta cần một bảng dữ liệu khổng lồ, muốn cố định phần trên đồng thời dùng overflow-x: auto, nhưng lại bị bắt chọn một trong hai
  • Thú thật là dù gần như không biết CSS, tôi vẫn đang làm các web app chạy tạm ổn. Gần đây tôi đã cố định header cho một bảng quái vật khoảng 20.000 hàng: https://www.datasciencemeta.com/rpackages Ban đầu tôi kỳ vọng các class bảng của Bootstrap sẽ có thứ gì đó như class="table table-header-sticky", nhưng không có; tôi mày mò các gợi ý từ Stack Overflow, GPT, CodePen khoảng 20 phút thì đều sinh ra tác dụng phụ kỳ lạ Thế mà với CodePen trong bài này, chỉ 2 phút là chạy được, và hiện tôi đang triển khai lên production

  • Cố định header bảng trông có vẻ dễ chỉ với position: sticky;, nhưng hễ bắt đầu thêm gì đó vào nội dung bảng là nó phức tạp ngay Tôi từng thêm chức năng cho một bảng có header cố định: khi người dùng cuộn phần thân rồi rời trang, lưu lại chỉ mục của hàng đầu tiên đang hiển thị và khôi phục khi quay lại, nhưng nó luôn khôi phục xuống dưới khoảng một hàng. Hóa ra hàng 5 thực ra đang ở ngay đầu bảng, nhưng thead chồng lên nên hàng 6 trông như hàng đầu tiên Vì vậy tôi điều chỉnh vị trí cuộn có tính đến chiều cao thead, nhưng đôi khi vẫn lệch vài pixel; do bảng lớn nên tôi lazy-load trong sự kiện cuộn và dùng layout bảng tự động mặc định, khiến ô header bị xuống dòng và toàn bộ chiều cao header thay đổi. Cuối cùng tôi gắn ResizeObserver vào thead để điều chỉnh động vị trí cuộn khi chiều cao thay đổi [1] https://developer.mozilla.org/en-US/docs/Web/API/ResizeObser...

  • Khi triển khai cái này, nếu muốn đường viền của header cũng cố định theo, có thể xử lý bằng cách đặt position: absolute, width: 100%, top: 0/bottom: 0, border-top/border-bottom cho table thead:beforetable thead:after

  • Giá mà header bảng tự động hoạt động như vậy. Nếu lập trình viên đã cố tình dùng các tag liên quan để làm thêm việc, thì thường rất có khả năng đây chính là hành vi họ muốn

    • Chỉ cần cài plugin trình duyệt cho phép tải stylesheet tùy chỉnh trên mọi trang là được Tuy nhiên dạo này ngày càng nhiều site tạo bảng bằng 500 thay vì, và bên trong mỗi lại có 45 lớp lồng nhau, nên chắc ở những nơi đó sẽ không ăn thua
    • Thay đổi kiểu này có vẻ rất dễ làm hỏng thứ gì đó theo cách không lường trước Lý do chính có lẽ là trước khi CSS Grid xuất hiện, nhiều website dùng bảng cho layout dạng lưới. Nếu header bị cố định, những layout đó có thể vỡ Thất bại lớn của ngữ nghĩa HTML là bảng đã bị hiểu như “lưới các phần tử tùy ý” thay vì “cách hiển thị dữ liệu dạng bảng”
  • Trên dòng lệnh, chỉ cần gửi header vào stderr, còn phần thân vào stdout Nếu không làm vậy, kết quả của heights | sort -k2 -nr sẽ thành George 186, Wally 173, NAME HEIGHT, nhưng nếu header đi vòng qua stdout thì thứ tự sẽ là NAME HEIGHT, George 186, Wally 173

    • heights | (sed -u 1q; sort -k2 -nr) hoạt động đúng Nguồn: https://stackoverflow.com/a/56151840
    • Nếu ghi ra file thì phải thử thêm vài lần nữa và cũng cần hiểu shell hơn Đây là hạn chế dai dẳng của mô hình chỉ có văn bản in-band, nhưng việc lạm dụng STDERR như thế này có vẻ sẽ gây rối hơn là giúp ích Nếu heights là file, có thể làm như % head -1 heights ; sed 1,1d heights | sort -k2 -nr; còn nếu heights là file thực thi tốn kém khi chạy hai lần, có thể làm như % heights > /tmp/heights ; head -1 /tmp/heights ; sed 1,1d /tmp/heights | sort -k2 -nr. Pipe qua awk cũng được Các lựa chọn khác kém tiện hơn nhưng ít gây bất ngờ hơn, và vẫn hoạt động dù tác giả file thực thi nghĩ khác
    • Ở đây thì cách nào tốt hơn? Gửi header vào stderr, hay chỉ in header khi stdout là TTY?
  • Cách này đã không hoạt động trong một thời gian dài. Trước đây Chrome từng vô hiệu hóa position: sticky trên các phần tử theadtr: https://issues.chromium.org/issues/41303743 Tôi nhớ bảng hỗ trợ trình duyệt gần như toàn màu xanh, nhưng trên bảng trong Chrome thì lại không dùng được

    • Thật ngạc nhiên là bây giờ nó đơn giản đến vậy. Hồi tôi cần thì để chạy được trên các trình duyệt khác nhau, phải nhét đủ thứ linh tinh vào HTML và CSS Dù vậy cũng không quá ngạc nhiên, vì phát triển web nhìn chung là như thế
  • Cũng có phía muốn nói rằng “làm ơn đừng làm vậy”: https://news.ycombinator.com/item?id=32998091

    • Nếu là trang web thông thường thì tôi hoàn toàn đồng ý. Vì nhanh hơn viết style Stylus, tôi thường dùng uBlock Origin để xóa phần tử cố định, và các style chung áp dụng toàn site cũng khá hiệu quả Nhưng bài gốc nói về bảng dữ liệu có hàng/cột header cố định, nên đề xuất này thực ra khá hữu ích
    • Đó là chuyện header cố định của toàn bộ trang web. Trong bảng thì hoàn toàn khác Tôi rất ghét cảnh đang xem một bảng có khoảng chục cột số, chỉ cần cuộn xuống một chút là chẳng còn biết cái gì là cái gì
    • Thuộc tính sticky có gì xấu?
  • CodePen sẽ trông đẹp hơn nếu offset top bằng độ dày đường viền. Ví dụ đặt -1px thay vì 0 để tránh phần thân bảng lộ lên phía trên header So sánh: https://codepen.io/bradleytaunt/pen/bGZyJBj Bản sửa: https://codepen.io/alokmenghrajani/pen/ExMBQow

  • Tôi đề xuất dùng chiều cao viewport bị giới hạn thay cho header cố định, để header luôn hiển thị Có thể làm như DataGridXL(https://datagridxl.com). Nhân tiện, đó là thứ tôi làm ra

    • Chỉ là ý nghĩ thoáng qua, nhưng cách này rất khó điều hướng nếu không có thiết bị trỏ, ví dụ chỉ dùng bàn phím
    • Không có ý phê phán, nhưng trên mobile tôi chưa bao giờ thích cách này. Tôi nghĩ nội dung nên cuộn cùng trang