Bảng HTML có tiêu đề cố định?


231

Có kỹ thuật CSS / JavaScript trên trình duyệt chéo để hiển thị bảng HTML dài sao cho các tiêu đề cột luôn cố định trên màn hình và không cuộn với thân bảng. Hãy nghĩ về hiệu ứng "đóng băng" trong Microsoft Excel.

Tôi muốn có thể cuộn qua các nội dung của bảng, nhưng để luôn có thể nhìn thấy các tiêu đề cột ở trên cùng.


3
Hãy thử điều này: Bảng có thể cuộn CSS thuần với EDIT tiêu đề cố định : Cái này sẽ hoạt động trong Internet Explorer 7 như trong ví dụ : Cuộn bảng HTML với tiêu đề cố định EDIT 2: Tôi tìm thấy một vài liên kết bổ sung có thể được sử dụng: - Ngốc tiêu đề cố định - Một plugin jQuery với một số hạn chế. - [Tiêu đề bảng cố định] ( cross-browser.com/x/examp
gcores

Tôi đã gặp nhiều giải pháp thường hoạt động nhưng không có giải pháp nào trong số đó hoạt động với div. Ý tôi là, bảng của bạn nằm trong div có thể cuộn và bạn vẫn muốn tiêu đề bảng của mình vẫn nằm trong div đó. Tôi đã giải quyết điều đó và chia sẻ giải pháp ở đây .
Yogee

9
Năm 2018, tất cả các trình duyệt có thể sử dụng giải pháp đơn giản sau : thead th { position: sticky; top: 0; }. Safari cần một tiền tố của nhà cung cấp:-webkit-sticky
Daniel Waltrip

1
@DanielWaltrip bạn nên thêm câu trả lời này để có thể được bình chọn lên vị trí hàng đầu - tất cả các câu trả lời khác đều dư thừa với vị trí: hiện tại đang được hỗ trợ tốt hơn
Peter Kerr

Câu trả lời:


88

Tôi đã tìm kiếm một giải pháp cho việc này trong một thời gian và thấy hầu hết các câu trả lời không hoạt động hoặc không phù hợp với tình huống của tôi, vì vậy tôi đã viết một giải pháp đơn giản với jQuery.

Đây là phác thảo giải pháp:

  1. Sao chép bảng cần có một tiêu đề cố định và đặt bản sao được nhân bản lên trên bản gốc.
  2. Hủy bỏ cơ thể bảng từ bảng đầu.
  3. Loại bỏ tiêu đề bảng từ bảng dưới cùng.
  4. Điều chỉnh độ rộng cột. (Chúng tôi theo dõi độ rộng cột ban đầu)

Dưới đây là mã trong một bản demo chạy được.

function scrolify(tblAsJQueryObject, height) {
  var oTbl = tblAsJQueryObject;

  // for very large tables you can remove the four lines below
  // and wrap the table with <div> in the mark-up and assign
  // height and overflow property  
  var oTblDiv = $("<div/>");
  oTblDiv.css('height', height);
  oTblDiv.css('overflow', 'scroll');
  oTbl.wrap(oTblDiv);

  // save original width
  oTbl.attr("data-item-original-width", oTbl.width());
  oTbl.find('thead tr td').each(function() {
    $(this).attr("data-item-original-width", $(this).width());
  });
  oTbl.find('tbody tr:eq(0) td').each(function() {
    $(this).attr("data-item-original-width", $(this).width());
  });


  // clone the original table
  var newTbl = oTbl.clone();

  // remove table header from original table
  oTbl.find('thead tr').remove();
  // remove table body from new table
  newTbl.find('tbody tr').remove();

  oTbl.parent().parent().prepend(newTbl);
  newTbl.wrap("<div/>");

  // replace ORIGINAL COLUMN width				
  newTbl.width(newTbl.attr('data-item-original-width'));
  newTbl.find('thead tr td').each(function() {
    $(this).width($(this).attr("data-item-original-width"));
  });
  oTbl.width(oTbl.attr('data-item-original-width'));
  oTbl.find('tbody tr:eq(0) td').each(function() {
    $(this).width($(this).attr("data-item-original-width"));
  });
}

$(document).ready(function() {
  scrolify($('#tblNeedsScrolling'), 160); // 160 is height
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>

<div style="width:300px;border:6px green solid;">
  <table border="1" width="100%" id="tblNeedsScrolling">
    <thead>
      <tr><th>Header 1</th><th>Header 2</th></tr>
    </thead>
    <tbody>
      <tr><td>row 1, cell 1</td><td>row 1, cell 2</td></tr>
      <tr><td>row 2, cell 1</td><td>row 2, cell 2</td></tr>
      <tr><td>row 3, cell 1</td><td>row 3, cell 2</td></tr>
      <tr><td>row 4, cell 1</td><td>row 4, cell 2</td></tr>			
      <tr><td>row 5, cell 1</td><td>row 5, cell 2</td></tr>
      <tr><td>row 6, cell 1</td><td>row 6, cell 2</td></tr>
      <tr><td>row 7, cell 1</td><td>row 7, cell 2</td></tr>
      <tr><td>row 8, cell 1</td><td>row 8, cell 2</td></tr>			
    </tbody>
  </table>
</div>

Giải pháp này hoạt động trong Chrome và IE. Vì nó dựa trên jQuery, nên nó cũng hoạt động trong các trình duyệt được hỗ trợ jQuery khác.


4
và làm thế nào chúng ta có thể giải quyết vấn đề khi nội dung lớn hơn chiều rộng?
Maertz

1
@tetra td {chiều rộng tối đa: 30px; } điều này sẽ cho phép nhà phát triển kiểm soát cách hiển thị các hàng.
Lyuben Todorov

Nhưng nếu nội dung trong một số ô tiêu đề dài hơn trong các ô td thì sao? Tôi đã thử điều đó trong IE7 và width () phá vỡ mọi thứ. IE8 và IE9 hoạt động tốt, mặc dù ...
JustAMartin

4
Thật không may, nếu bạn yêu cầu căn chỉnh hoàn hảo pixel của các cột, điều này không hoạt động: jsbin.com/elekiq/1 ( mã nguồn ). Bạn có thể thấy rằng một số tiêu đề được bù từ nơi chúng cần, chỉ một chút. Hiệu quả rõ ràng hơn nếu bạn đang sử dụng hình nền: jsbin.com/elekiq/2 ( mã nguồn ). . chiều rộng của các ô ...
TJ Crowder

Điều này dường như không hoạt động với cuộn ngang - nó tạo ra tiêu đề, nhưng nó vượt ra ngoài khu vực có thể cuộn (rõ ràng) và không cuộn với nội dung.
Tai nạn

183

Điều này có thể được giải quyết rõ ràng trong bốn dòng mã.

Nếu bạn chỉ quan tâm đến các trình duyệt hiện đại, một tiêu đề cố định có thể đạt được dễ dàng hơn nhiều bằng cách sử dụng các biến đổi CSS. Nghe có vẻ lạ, nhưng hoạt động rất tốt:

  • HTML và CSS vẫn như cũ.
  • Không phụ thuộc JavaScript bên ngoài.
  • Bốn dòng mã.
  • Hoạt động cho tất cả các cấu hình (bố trí bảng: cố định, v.v.).
document.getElementById("wrap").addEventListener("scroll", function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

Hỗ trợ cho các biến đổi CSS có sẵn rộng rãi ngoại trừ Internet Explorer 8-.

Dưới đây là ví dụ đầy đủ để tham khảo:


8
Tôi phải nói rằng, nhận xét trước đây của tôi mặc dù, đây là điều gần nhất với một giải pháp hoàn hảo mà tôi đã thấy. Ngay cả cuộn ngang cũng hoàn hảo (tốt hơn giải pháp của riêng tôi). Dưới đây là một ví dụ với các đường viền (bạn không thể sử dụng thu gọn đường viền) và một thanh cuộn dính vào bảng thay vì thùng chứa: jsfiddle
DoctorDeststallo

11
Phát hiện ra, nó hoạt động nhưng phải áp dụng biến đổi cho th / td, không phải thead.
tóc đỏ

5
@AlexAlexeev, giải pháp của bạn thật tuyệt vời. Cảm ơn bạn. Tôi nhận thấy rằng, tiêu đề cố định kết quả không có các đường viền phân biệt các cột. Kiểu CSS mặc định bị mất. Ngay cả khi tôi bao gồm điều này ... $(this).addClass('border')thay đổi phần còn lại của bảng có phông chữ, kích thước, màu sắc mà tôi vượt qua trong lớp viền. Nhưng, không thêm dòng vào tiêu đề cố định. Đánh giá cao, bất kỳ đầu vào nào về cách khắc phục điều này
user5249203

5
@ user5249203 Tôi biết bạn đã hỏi vài tháng trước nhưng tôi cũng gặp vấn đề tương tự và đó là do sự sụp đổ biên giới: hãy xem điều này: stackoverflow.com/questions/33777751/ .
archz

6
Điều này không hoạt động trong bất kỳ phiên bản IE hoặc Edge nào. Đây là phiên bản dựa trên nhận xét của @ redhead jsfiddle.net/n6o8ocwb/2
cướp

58

Tôi vừa hoàn thành việc kết hợp một plugin jQuery sẽ lấy một bảng duy nhất hợp lệ bằng cách sử dụng HTML hợp lệ (phải có thead và tbody) và sẽ xuất ra một bảng có các tiêu đề cố định, chân trang cố định tùy chọn có thể là tiêu đề nhân bản hoặc bất kỳ nội dung bạn đã chọn (phân trang, v.v.). Nếu bạn muốn tận dụng màn hình lớn hơn, nó cũng sẽ thay đổi kích thước bảng khi trình duyệt được thay đổi kích thước. Một tính năng được thêm vào khác là có thể cuộn bên nếu các cột của bảng không thể vừa trong tầm nhìn.

http://fixedheadertable.com/

trên github: http://markmalek.github.com/Fixed-Header-Table/

Việc cài đặt cực kỳ dễ dàng và bạn có thể tạo các kiểu tùy chỉnh của riêng mình cho nó. Nó cũng sử dụng các góc tròn trong tất cả các trình duyệt. Hãy nhớ rằng tôi vừa phát hành nó, vì vậy nó vẫn là bản beta về mặt kỹ thuật và có rất ít vấn đề nhỏ tôi đang giải quyết.

Nó hoạt động trong Internet Explorer 7, Internet Explorer 8, Safari, Firefox và Chrome.


Cảm ơn! Tôi sẽ thêm một bản phát hành mới vào hôm nay khi tôi đi làm về. Đây là một liên kết đến mục blog của tôi với những gì tôi đang thêm: fixedheadertable.mmalek.com/2009/10/07/
Mark

Cảm ơn vì điều này. Tôi biết câu hỏi này đã hơn một năm tuổi, nhưng thậm chí có nguy cơ khuấy động phù sa đã ổn định, tôi muốn nói với bạn rằng công việc của bạn được đánh giá cao
sova

Trong bản demo của bạn, độ rộng bị tắt trong eg6 :-( tiêu đề và thân bảng không được căn chỉnh.
Cheekysoft

4
Phiên bản mới nhất không hoạt động trong IE6. Tôi không còn hỗ trợ IE6.
Đánh dấu

công việc tuyệt vời Mark - không may có một số vấn đề với việc cuộn tiêu đề và cột cố định trong thiết bị di động (iPad, máy tính bảng Android) - khi tôi cuộn nội dung những phần cố định đó không cuộn - khi tôi dừng cuộn và chạm một lần vào bảng , các bộ phận cố định "nhảy" đến các vị trí thích hợp - có cách nào đơn giản để khắc phục điều này không?
Okizb

23

Tôi cũng đã tạo một plugin giải quyết vấn đề này. Dự án của tôi - jQuery.floatThead đã được hơn 4 năm và rất trưởng thành.

Nó không yêu cầu kiểu dáng bên ngoài và không mong muốn bảng của bạn được tạo kiểu theo bất kỳ cách cụ thể nào. Nó hỗ trợ Internet Explorer9 + và Firefox / Chrome.

Hiện tại (2018-05) nó có:

405 cam kết và 998 sao trên GitHub


Nhiều (không phải tất cả) các câu trả lời ở đây là những bản hack nhanh có thể đã giải quyết vấn đề mà một người đang gặp phải, nhưng sẽ không hoạt động cho mọi bảng.

Một số plugin khác đã cũ và có thể hoạt động tốt với Internet Explorer, nhưng sẽ phá vỡ trên Firefox và Chrome.


1
Plugin tuyệt vời, hỗ trợ các bảng lồng và offset.
Mihai Alex

2
Tuyệt quá. Cảm ơn rất nhiều. Plugin hoạt động tốt trong Firefox 45.2, Chromium 51 và IE 11. Ngoài ra, nó không can thiệp vào rất nhiều mã JS và jQuery được xây dựng trên cùng một trang.
Aldo Paradiso

Cảm ơn bạn. Tôi vui mừng báo cáo rằng dự án nhận được khoảng 1 báo cáo lỗi cứ sau 4 tháng vào thời điểm này. Tôi không thực hiện nhiều thay đổi phá vỡ. Nó là khá vững chắc và hoạt động.
mkoryak

20

TL; DR

Nếu bạn nhắm mục tiêu các trình duyệt hiện đại và không có nhu cầu tạo kiểu xa hoa: http://jsfiddle.net/dPixie/byB9d/3/ ... Mặc dù phiên bản bốn lớn khá ngọt ngào, phiên bản này xử lý chiều rộng chất lỏng tốt hơn rất nhiều.

Tin vui nhé mọi người!

Với những tiến bộ của HTML5 và CSS3, điều này hiện có thể, ít nhất là đối với các trình duyệt hiện đại. Việc triển khai hơi hackish mà tôi nghĩ ra có thể được tìm thấy ở đây: http://jsfiddle.net/dPixie/byB9d/3/ . Tôi đã thử nghiệm nó trong FX 25, Chrome 31 và IE 10 ...

HTML có liên quan (mặc dù chèn một loại tài liệu HTML5 ở đầu tài liệu của bạn):

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

section {
  position: relative;
  border: 1px solid #000;
  padding-top: 37px;
  background: #500;
}

section.positioned {
  position: absolute;
  top: 100px;
  left: 100px;
  width: 800px;
  box-shadow: 0 0 15px #333;
}

.container {
  overflow-y: auto;
  height: 200px;
}

table {
  border-spacing: 0;
  width: 100%;
}

td+td {
  border-left: 1px solid #eee;
}

td,
th {
  border-bottom: 1px solid #eee;
  background: #ddd;
  color: #000;
  padding: 10px 25px;
}

th {
  height: 0;
  line-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  color: transparent;
  border: none;
  white-space: nowrap;
}

th div {
  position: absolute;
  background: transparent;
  color: #fff;
  padding: 9px 25px;
  top: 0;
  margin-left: -25px;
  line-height: normal;
  border-left: 1px solid #800;
}

th:first-child div {
  border: none;
}
<section class="positioned">
  <div class="container">
    <table>
      <thead>
        <tr class="header">
          <th>
            Table attribute name
            <div>Table attribute name</div>
          </th>
          <th>
            Value
            <div>Value</div>
          </th>
          <th>
            Description
            <div>Description</div>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>align</td>
          <td>left, center, right</td>
          <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the alignment of a table according to surrounding text</td>
        </tr>
        <tr>
          <td>bgcolor</td>
          <td>rgb(x,x,x), #xxxxxx, colorname</td>
          <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the background color for a table</td>
        </tr>
        <tr>
          <td>border</td>
          <td>1,""</td>
          <td>Specifies whether the table cells should have borders or not</td>
        </tr>
        <tr>
          <td>cellpadding</td>
          <td>pixels</td>
          <td>Not supported in HTML5. Specifies the space between the cell wall and the cell content</td>
        </tr>
        <tr>
          <td>cellspacing</td>
          <td>pixels</td>
          <td>Not supported in HTML5. Specifies the space between cells</td>
        </tr>
        <tr>
          <td>frame</td>
          <td>void, above, below, hsides, lhs, rhs, vsides, box, border</td>
          <td>Not supported in HTML5. Specifies which parts of the outside borders that should be visible</td>
        </tr>
        <tr>
          <td>rules</td>
          <td>none, groups, rows, cols, all</td>
          <td>Not supported in HTML5. Specifies which parts of the inside borders that should be visible</td>
        </tr>
        <tr>
          <td>summary</td>
          <td>text</td>
          <td>Not supported in HTML5. Specifies a summary of the content of a table</td>
        </tr>
        <tr>
          <td>width</td>
          <td>pixels, %</td>
          <td>Not supported in HTML5. Specifies the width of a table</td>
        </tr>
      </tbody>
    </table>
  </div>
</section>

Nhưng bằng cách nào?!

Đơn giản chỉ cần đặt bạn có một tiêu đề bảng, mà bạn ẩn trực quan bằng cách làm cho nó cao 0px, cũng chứa các div được sử dụng làm tiêu đề cố định. Hộp chứa của bảng để lại đủ chỗ ở trên cùng để cho phép tiêu đề được định vị tuyệt đối và bảng có thanh cuộn xuất hiện như bạn mong đợi.

Đoạn mã trên sử dụng lớp định vị để định vị bảng hoàn toàn (Tôi đang sử dụng nó trong hộp thoại kiểu bật lên) nhưng bạn cũng có thể sử dụng nó trong luồng tài liệu bằng cách xóa positionedlớp khỏi vùng chứa.

Nhưng ...

Nó không hoàn hảo. Firefox từ chối tạo hàng tiêu đề 0px (ít nhất là tôi không tìm thấy cách nào) nhưng vẫn ngoan cố giữ nó ở mức tối thiểu 4px ... Đó không phải là vấn đề lớn, nhưng tùy thuộc vào kiểu dáng của bạn, nó sẽ gây rối với đường viền của bạn, v.v.

Bảng cũng đang sử dụng một cách tiếp cận cột giả trong đó màu nền của chính container được sử dụng làm nền cho các div tiêu đề, trong suốt.

Tóm lược

Tất cả trong tất cả có thể có các vấn đề về kiểu dáng tùy thuộc vào yêu cầu của bạn, đặc biệt là đường viền hoặc nền phức tạp. Cũng có thể có vấn đề với khả năng tính toán, tôi chưa kiểm tra nó trên nhiều trình duyệt khác nhau (vui lòng nhận xét với trải nghiệm của bạn nếu bạn dùng thử), nhưng tôi không tìm thấy bất cứ điều gì giống như vậy nên tôi nghĩ rằng nó đáng để đăng dù sao ...


Nếu bạn thu nhỏ chiều rộng của cửa sổ cho đến khi cuộn ngang bắt đầu, thì tiêu đề không cuộn theo chiều ngang với cơ thể. Chết tiệt.
dlaliberte

@dlaliberte - Chà, vì tiêu đề và bảng thực sự là hai yếu tố khác nhau mà bạn có thể, ofc, trở nên kỳ lạ. Nhưng ví dụ của tôi không cho phép tràn trên các cột của bảng và các tiêu đề thường dễ kiểm soát hơn nội dung bảng. Điều đó nói rằng, nếu bạn làm cho tiêu đề "tràn" nếu sẽ dính vào bên phải của bảng và trông bị hỏng nghiêm trọng. Bạn có thể khắc phục điều này bằng cách đặt chiều rộng tối thiểu trên bàn, buộc nó cũng tràn vào trang ... Nhưng đó là một bản hack nên nó sẽ không bao giờ hoàn hảo ...
Jonas Schubert Erlandsson

1
Đáng chỉ ra rằng điều này đòi hỏi một thiết kế trong đó một bảng chiều cao cố định có thể được chỉ định.
Cheekysoft

1
@Cheekysoft - Không, bảng và nội dung hàng có thể chảy tự do. Container, trong ví dụ của tôi <section>, phần tử, chỉ cần được giới hạn chiều cao để buộc nó tràn và hiển thị cuộn. Bất kỳ bố trí nào sẽ làm cho container tràn sẽ hoạt động. Nếu bạn tìm thấy một trường hợp không, xin vui lòng gửi một liên kết đến một fiddle.
Jonas Schubert Erlandsson

padding-topGiá trị được mã hóa cứng cũng có nghĩa là nếu văn bản tiêu đề bảng nằm trên nhiều dòng thì nó sẽ xuất hiện trên đầu các ô của bảng. Đáng tiếc, bởi vì điều này làm việc như một sự quyến rũ hầu hết thời gian. Bí quyết thật sự tốt đẹp với divtrong thđể có được xung quanh vấn đề cột cỡ nhất các giải pháp khác có.
Bernhard Hofmann

19

Tất cả những nỗ lực để giải quyết vấn đề này từ bên ngoài đặc tả CSS là những cái bóng nhạt của những gì chúng ta thực sự muốn: Giao hàng theo lời hứa ngụ ý của THEAD.

Vấn đề về tiêu đề đông lạnh này đã trở thành một vết thương mở trong HTML / CSS trong một thời gian dài.

Trong một thế giới hoàn hảo, sẽ có một giải pháp CSS thuần cho vấn đề này. Thật không may, dường như không có một vị trí tốt.

Các tiêu chuẩn liên quan - các cuộc thảo luận về chủ đề này bao gồm:

CẬP NHẬT : Firefox xuất xưởng position:stickytrong phiên bản 32. Mọi người đều thắng!


Thật tuyệt vời khi có những cột cáo giống như vậy
Csaba Toth

4
Re. Firefox và vị trí: dính, nó không hoạt động cho các tiêu đề bảng: bugzilla.mozilla.org/show_orms.cgi?id=925259#c8 ... Bản vá cho lỗi đó nêu rõ: "Chúng tôi hiện không hỗ trợ định vị tương đối của các yếu tố bảng bên trong, vì vậy chúng tôi cũng loại trừ chúng khỏi vị trí dính. "
Jonas Schubert Erlandsson

2
Điều này hoạt động trong tất cả các trình duyệt bây giờ : thead th { position: sticky; top: 0; }. Chúng ta có thể cập nhật câu trả lời này để nêu rõ điều này không?
Daniel Waltrip

1
@DanielWaltrip tất cả các trình duyệt? stackoverflow.com/a/37646284/3640407 Vẫn còn nhiều MSIE hơn Edges
edc65

Điểm công bằng. Nó được hỗ trợ cho 86% người dùng web toàn cầu, theo caniuse.com/#search=poseition%3Asticky
Daniel Waltrip

14

Đây là một plugin jQuery cho các tiêu đề bảng cố định. Nó cho phép toàn bộ trang cuộn, đóng băng tiêu đề khi nó đạt đến đỉnh. Nó hoạt động tốt với các bảng Twitter Bootstrap .

Kho lưu trữ GitHub: https://github.com/oma/table-fixed-header

không chỉ cuộn nội dung bảng. Hãy tìm đến các công cụ khác cho điều đó, như một trong những câu trả lời khác. Bạn quyết định những gì phù hợp với trường hợp của bạn là tốt nhất.


1
Bummer - liên kết ví dụ đã chết. "Rất tiếc! Denne siden ble ikke funnet ..." Ước gì mã được dán ở đây.
JosephK

vâng ... xin lỗi về điều đó xóa liên kết. Dự án không còn được duy trì
oma

Đừng lo lắng - Tôi đã thử một vài trong số các giải pháp có mục đích được tạo sẵn này - không có giải pháp nào hoạt động với bảng flex-col-width vượt quá chiều rộng màn hình. Tôi cố gắng viết ra giải pháp của riêng tôi.
JosephK

9

Hầu hết các giải pháp được đăng ở đây đều yêu cầu jQuery. Nếu bạn đang tìm kiếm một giải pháp độc lập khung, hãy thử Grid: http://www.matts411.com/post/grid/

Nó được lưu trữ trên Github tại đây: https://github.com/mmurph211/Grid

Nó không chỉ hỗ trợ các tiêu đề cố định, nó còn hỗ trợ các cột và chân trang cố định bên trái, trong số những thứ khác.


Điều này thực sự gọn gàng nếu nó đáp ứng nhu cầu của bạn, tôi chỉ chơi với nó ngày hôm nay. Thật không may, nó thực sự là một lưới hình chữ nhật (đúng như tên gọi của nó) và không phải là một bảng thực sự với chiều cao hàng được điều chỉnh bởi nội dung. Và tạo kiểu cho các hàng riêng lẻ có vẻ khó khăn. Tôi không thể quản lý để tạo ra một bảng sọc ngựa vằn nhưng đã không cố gắng rất nhiều vì nhu cầu của tôi thực sự phức tạp hơn. Dù sao, công việc tốt đẹp.
mplwork

1
Này tôi biết bạn! Chúng tôi dường như đã viết shit rất giống nhau ( github.com/mkoryak/floatThead ) - Misha
mkoryak

9

Thuộc tính CSS position: stickycó sự hỗ trợ tuyệt vời trong hầu hết các trình duyệt hiện đại (tôi gặp vấn đề với Edge, xem bên dưới).

Điều này cho phép chúng tôi giải quyết vấn đề của các tiêu đề cố định khá dễ dàng:

thead th { position: sticky; top: 0; }

Safari cần một tiền tố nhà cung cấp : -webkit-sticky.

Đối với Firefox, tôi đã phải thêm min-height: 0vào một trong các phần tử cha. Tôi quên chính xác tại sao điều này là cần thiết.

Thật không may, việc triển khai Microsoft Edge dường như chỉ hoạt động được. Ít nhất, tôi đã có một số ô bảng nhấp nháy và sai lệch trong thử nghiệm của mình. Chiếc bàn vẫn có thể sử dụng được, nhưng có vấn đề thẩm mỹ quan trọng.


Sử dụng position: sticky;với bảng bên trong một div có overflow: scroll;, overflow-x: scroll;hoặc overflow-y: scroll;. dường như là giải pháp tốt nhất và đơn giản nhất cho các tiêu đề và cột cố định trong các trình duyệt hiện đại. Câu trả lời này cần được bình chọn lên hàng đầu.
Aberrant

Thật đơn giản nhưng hiệu quả. Đó là những gì tôi đang tìm kiếm. Cảm ơn.
Catbuilts

6

Một bảng cuộn CSS tinh khiết hơn

Tất cả các giải pháp CSS thuần túy mà tôi đã thấy cho đến nay - thông minh mặc dù chúng có thể-- thiếu một mức độ đánh bóng nhất định hoặc chỉ không hoạt động đúng trong một số tình huống. Vì vậy, tôi quyết định tự tạo ...

Đặc trưng:

  • Đó là CSS thuần túy, vì vậy không cần jQuery (hoặc bất kỳ mã JavaScript nào), cho vấn đề đó)
  • Bạn có thể đặt chiều rộng của bảng thành phần trăm (còn gọi là "chất lỏng") hoặc giá trị cố định hoặc để nội dung xác định chiều rộng của bảng (còn gọi là "tự động")
  • Độ rộng cột cũng có thể là chất lỏng, cố định hoặc tự động.
  • Các cột sẽ không bao giờ bị sai lệch với các tiêu đề do cuộn ngang (một vấn đề xảy ra trong mọi giải pháp dựa trên CSS khác mà tôi thấy không yêu cầu độ rộng cố định).
  • Tương thích với tất cả các trình duyệt máy tính để bàn phổ biến, bao gồm cả Internet Explorer trở lại phiên bản 8
  • Ngoại hình sạch sẽ, lịch sự; không có khoảng trống 1 pixel trông cẩu thả hoặc đường viền sai; trông giống nhau trong tất cả các trình duyệt

Dưới đây là một số câu đố hiển thị các tùy chọn chiều rộng chất lỏng và tự động:

  • Chiều rộng và chiều cao chất lỏng (thích ứng với kích thước màn hình): jsFiddle (Lưu ý rằng thanh cuộn chỉ hiển thị khi cần trong cấu hình này, do đó bạn có thể phải thu nhỏ khung hình để xem nó)

  • Chiều rộng tự động, Chiều cao cố định (dễ tích hợp hơn với nội dung khác): jsFiddle

Cấu hình Chiều rộng tự động, Chiều cao cố định có thể có nhiều trường hợp sử dụng hơn, vì vậy tôi sẽ đăng mã bên dưới.

/* The following 'html' and 'body' rule sets are required only
   if using a % width or height*/

/*html {
  width: 100%;
  height: 100%;
}*/

body {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0 20px 0 20px;
  text-align: center;
}
.scrollingtable {
  box-sizing: border-box;
  display: inline-block;
  vertical-align: middle;
  overflow: hidden;
  width: auto; /* If you want a fixed width, set it here, else set to auto */
  min-width: 0/*100%*/; /* If you want a % width, set it here, else set to 0 */
  height: 188px/*100%*/; /* Set table height here; can be fixed value or % */
  min-height: 0/*104px*/; /* If using % height, make this large enough to fit scrollbar arrows + caption + thead */
  font-family: Verdana, Tahoma, sans-serif;
  font-size: 16px;
  line-height: 20px;
  padding: 20px 0 20px 0; /* Need enough padding to make room for caption */
  text-align: left;
  color: black;
}
.scrollingtable * {box-sizing: border-box;}
.scrollingtable > div {
  position: relative;
  border-top: 1px solid black;
  height: 100%;
  padding-top: 20px; /* This determines column header height */
}
.scrollingtable > div:before {
  top: 0;
  background: cornflowerblue; /* Header row background color */
}
.scrollingtable > div:before,
.scrollingtable > div > div:after {
  content: "";
  position: absolute;
  z-index: -1;
  width: 100%;
  height: 100%;
  left: 0;
}
.scrollingtable > div > div {
  min-height: 0/*43px*/; /* If using % height, make this large
                            enough to fit scrollbar arrows */
  max-height: 100%;
  overflow: scroll/*auto*/; /* Set to auto if using fixed
                               or % width; else scroll */
  overflow-x: hidden;
  border: 1px solid black; /* Border around table body */
}
.scrollingtable > div > div:after {background: white;} /* Match page background color */
.scrollingtable > div > div > table {
  width: 100%;
  border-spacing: 0;
  margin-top: -20px; /* Inverse of column header height */
  /*margin-right: 17px;*/ /* Uncomment if using % width */
}
.scrollingtable > div > div > table > caption {
  position: absolute;
  top: -20px; /*inverse of caption height*/
  margin-top: -1px; /*inverse of border-width*/
  width: 100%;
  font-weight: bold;
  text-align: center;
}
.scrollingtable > div > div > table > * > tr > * {padding: 0;}
.scrollingtable > div > div > table > thead {
  vertical-align: bottom;
  white-space: nowrap;
  text-align: center;
}
.scrollingtable > div > div > table > thead > tr > * > div {
  display: inline-block;
  padding: 0 6px 0 6px; /*header cell padding*/
}
.scrollingtable > div > div > table > thead > tr > :first-child:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 20px; /*match column header height*/
  border-left: 1px solid black; /*leftmost header border*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div > div:first-child,
.scrollingtable > div > div > table > thead > tr > * + :before {
  position: absolute;
  top: 0;
  white-space: pre-wrap;
  color: white; /*header row font color*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div[label]:after {content: attr(label);}
.scrollingtable > div > div > table > thead > tr > * + :before {
  content: "";
  display: block;
  min-height: 20px; /* Match column header height */
  padding-top: 1px;
  border-left: 1px solid black; /* Borders between header cells */
}
.scrollingtable .scrollbarhead {float: right;}
.scrollingtable .scrollbarhead:before {
  position: absolute;
  width: 100px;
  top: -1px; /* Inverse border-width */
  background: white; /* Match page background color */
}
.scrollingtable > div > div > table > tbody > tr:after {
  content: "";
  display: table-cell;
  position: relative;
  padding: 0;
  border-top: 1px solid black;
  top: -1px; /* Inverse of border width */
}
.scrollingtable > div > div > table > tbody {vertical-align: top;}
.scrollingtable > div > div > table > tbody > tr {background: white;}
.scrollingtable > div > div > table > tbody > tr > * {
  border-bottom: 1px solid black;
  padding: 0 6px 0 6px;
  height: 20px; /* Match column header height */
}
.scrollingtable > div > div > table > tbody:last-of-type > tr:last-child > * {border-bottom: none;}
.scrollingtable > div > div > table > tbody > tr:nth-child(even) {background: gainsboro;} /* Alternate row color */
.scrollingtable > div > div > table > tbody > tr > * + * {border-left: 1px solid black;} /* Borders between body cells */
<div class="scrollingtable">
  <div>
    <div>
      <table>
        <caption>Top Caption</caption>
        <thead>
          <tr>
            <th><div label="Column 1"/></th>
            <th><div label="Column 2"/></th>
            <th><div label="Column 3"/></th>
            <th>
              <!-- More versatile way of doing column label; requires two identical copies of label -->
              <div><div>Column 4</div><div>Column 4</div></div>
            </th>
            <th class="scrollbarhead"/> <!-- ALWAYS ADD THIS EXTRA CELL AT END OF HEADER ROW -->
          </tr>
        </thead>
        <tbody>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
        </tbody>
      </table>
    </div>
    Faux bottom caption
  </div>
</div>

<!--[if lte IE 9]><style>.scrollingtable > div > div > table {margin-right: 17px;}</style><![endif]-->

Phương pháp tôi đã sử dụng để đóng băng hàng tiêu đề tương tự như d-Pixie, vì vậy hãy tham khảo bài đăng của anh ấy để được giải thích. Có một loạt lỗi và hạn chế với kỹ thuật đó chỉ có thể được sửa chữa với hàng đống CSS bổ sung và một hoặc hai thùng chứa div bổ sung.


Câu trả lời này là cách đánh giá thấp! Tôi đã dành nhiều ngày cố gắng để có được các giải pháp khác để làm việc cho trường hợp đặc biệt khó chịu của tôi. Mỗi một người trong số họ không thể liên kết theo cách này hay cách khác. Điều này cuối cùng đã làm nó! Có vẻ quá phức tạp lúc đầu, nhưng một khi bạn đã hiểu rõ về nó, thật tuyệt vời. Cuối cùng, bạn có thể loại bỏ khá nhiều thứ bạn không cần, khi không sử dụng chiều rộng chất lỏng, v.v.
Justin Sane

1
@JustinSane Vui mừng bạn thích nó! Tôi đoán sự thiếu đánh giá cao là do thực tế là nó chia sẻ trang với giải pháp tuyệt vời của Maximilian Hils . Nếu bạn không phản đối việc sử dụng một chút JS, bạn chắc chắn nên kiểm tra nó.
DoctorDeststallo

Chết tiệt, đó một giải pháp gần như hoàn hảo thực sự. Dù sao tôi cũng đang sử dụng jQuery, đã cố gắng làm cho nó hoạt động với điều đó trước khi tôi tìm thấy bạn (thông qua nhận xét của bạn cho một câu hỏi khác). Không nghĩ đến một người nghe cuộn và dịch ... Chà, họ nói rằng cần có một thiên tài để đưa ra các giải pháp đơn giản ..;) Tôi đã hoàn thành dự án và nó hoạt động hoàn hảo mà không cần js, nhưng tôi sẽ giữ nó tâm trí cho tương lai. Tuy nhiên, mũ cho bạn là tuyệt vời!
Justin Sane

Một vấn đề nhỏ nhưng nếu bạn đang sử dụng các Màu hệ thống khác nhau, bạn có thể thấy màu văn bản chưa được đặt cho bất kỳ thứ gì ngoại trừ các tiêu đề nhưng nền bảng có màu nền rõ ràng. Tôi có văn bản màu vàng trên nền trắng và xám cho bảng này.
Matt Arnold

1
@MattArnold Đã sửa. Thx cho tiền boa!
DoctorDeststallo

5

Một plugin jQuery đơn giản

Đây là một biến thể về giải pháp của Mahes. Bạn có thể gọi nó như$('table#foo').scrollableTable();

Ý tưởng là:

  • Tách theadtbodythành các tableyếu tố riêng biệt
  • Làm cho chiều rộng ô của chúng khớp lại
  • Gói thứ hai tabletrong mộtdiv.scrollable
  • Sử dụng CSS để div.scrollablethực sự cuộn

CSS có thể là:

div.scrollable { height: 300px; overflow-y: scroll;}

Hãy cẩn thận

  • Rõ ràng, việc tách các bảng này làm cho việc đánh dấu ít ngữ nghĩa hơn. Tôi không chắc điều này có ảnh hưởng gì đến khả năng tiếp cận.
  • Plugin này không xử lý chân trang, nhiều tiêu đề, v.v.
  • Tôi chỉ thử nghiệm nó trong phiên bản Chrome 20.

Điều đó nói rằng, nó hoạt động cho mục đích của tôi và bạn có thể tự do lấy và sửa đổi nó.

Đây là plugin:

jQuery.fn.scrollableTable = function () {
  var $newTable, $oldTable, $scrollableDiv, originalWidths;
  $oldTable = $(this);

  // Once the tables are split, their cell widths may change. 
  // Grab these so we can make the two tables match again.
  originalWidths = $oldTable.find('tr:first td').map(function() {
    return $(this).width();
  });

  $newTable = $oldTable.clone();
  $oldTable.find('tbody').remove();
  $newTable.find('thead').remove();

  $.each([$oldTable, $newTable], function(index, $table) {
    $table.find('tr:first td').each(function(i) {
      $(this).width(originalWidths[i]);
    });
  });

  $scrollableDiv = $('<div/>').addClass('scrollable');
  $newTable.insertAfter($oldTable).wrap($scrollableDiv);
};

1
Kịch bản hay, cái này hoạt động tốt nhất trong môi trường của tôi. Tôi mở rộng tập lệnh của bạn với sự hỗ trợ chân trang cố định, kiểm tra bài viết của tôi dưới đây.
gitaarik

4

:)

Không sạch sẽ, nhưng giải pháp HTML / CSS thuần túy.

table {
    overflow-x:scroll;
}

tbody {
    max-height: /*your desired max height*/
    overflow-y:scroll;
    display:block;
}

Đã cập nhật cho ví dụ về IE8 + JSFiddle


2
Giải pháp tốt, chỉ đề cập đến là các ô này được thả nổi và do đó, theo nội dung có thể có độ cao khác nhau, nó có thể nhìn thấy nếu bạn đặt đường viền của chúng: jsfiddle.net/ZdeEH/15
Stano

3

Hỗ trợ chân trang cố định

Tôi đã mở rộng chức năng của Nathan để hỗ trợ chân trang cố định và chiều cao tối đa. Ngoài ra, chức năng sẽ tự thiết lập CSS và bạn chỉ phải hỗ trợ chiều rộng.

Sử dụng:

Chiều cao cố định:

$('table').scrollableTable({ height: 100 });

Chiều cao tối đa (nếu trình duyệt hỗ trợ tùy chọn 'chiều cao tối đa' CSS):

$('table').scrollableTable({ maxHeight: 100 });

Kịch bản:

jQuery.fn.scrollableTable = function(options) {

    var $originalTable, $headTable, $bodyTable, $footTable, $scrollableDiv, originalWidths;

    // Prepare the separate parts of the table
    $originalTable = $(this);
    $headTable = $originalTable.clone();

    $headTable.find('tbody').remove();
    $headTable.find('tfoot').remove();

    $bodyTable = $originalTable.clone();
    $bodyTable.find('thead').remove();
    $bodyTable.find('tfoot').remove();

    $footTable = $originalTable.clone();
    $footTable.find('thead').remove();
    $footTable.find('tbody').remove();

    // Grab the original column widths and set them in the separate tables
    originalWidths = $originalTable.find('tr:first td').map(function() {
        return $(this).width();
    });

    $.each([$headTable, $bodyTable, $footTable], function(index, $table) {
        $table.find('tr:first td').each(function(i) {
            $(this).width(originalWidths[i]);
        });
    });

    // The div that makes the body table scroll
    $scrollableDiv = $('<div/>').css({
        'overflow-y': 'scroll'
    });

    if(options.height) {
        $scrollableDiv.css({'height': options.height});
    }
    else if(options.maxHeight) {
        $scrollableDiv.css({'max-height': options.maxHeight});
    }

    // Add the new separate tables and remove the original one
    $headTable.insertAfter($originalTable);
    $bodyTable.insertAfter($headTable);
    $footTable.insertAfter($bodyTable);
    $bodyTable.wrap($scrollableDiv);
    $originalTable.remove();
};

3

Bằng cách nào đó tôi đã kết thúc Position:Stickytốt đẹp với trường hợp của mình:

table{
  width: 100%;
  border: collapse;
}

th{
    position: sticky;
    top: 0px;
    border: 1px solid black;
    background: #ff5722;
    color: #f5f5f5;
    font-weight: 600;
}
td{
    background: #d3d3d3;
    border: 1px solid black;
    color: #f5f5f5;
    font-weight: 600;
}

div{
  height: 150px
  overflow: auto;
  width: 100%
}
<div>
    <table>
        <thead>
            <tr>
                <th>header 1</th>
                <th>header 2</th>
                <th>header 3</th>
                <th>header 4</th>
                <th>header 5</th>
                <th>header 6</th>
                <th>header 7</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
        </tbody>
    </table>
</div>


1
Đây là giải pháp sạch nhất tôi thấy cho đến nay. caniuse cho thấy kể từ ngày 5/2/2020, vị trí chưa được xác định: dính được hưởng 90,06% hỗ trợ toàn cầu. Vì vậy, giải pháp này hoạt động tốt trong tất cả các trình duyệt hiện đại.
AlienKevin

2

Hai div, một cho tiêu đề, một cho dữ liệu. Làm cho div dữ liệu có thể cuộn và sử dụng JavaScript để đặt độ rộng của các cột trong tiêu đề giống với chiều rộng của dữ liệu. Tôi nghĩ rằng chiều rộng cột dữ liệu cần phải được cố định chứ không phải là động.


3
Nếu bạn quan tâm đến khả năng tiếp cận, đây là một thất bại.
eprebello

1
Khả năng truy cập lại, có lẽ chúng ta có thể thay thế việc sử dụng div bằng kiểu dáng trên <thead> và <tbody> ??
Cheekysoft

1

Tôi nhận ra câu hỏi cho phép JavaScript, nhưng đây là một giải pháp CSS thuần túy mà tôi đã làm việc cũng cho phép bảng mở rộng theo chiều ngang. Nó đã được thử nghiệm với Internet Explorer 10 và các trình duyệt Chrome và Firefox mới nhất. Một liên kết đến jsFiddle ở phía dưới.

HTML:

Putting some text here to differentiate between the header
aligning with the top of the screen and the header aligning
with the top of one of its ancestor containers.

<div id="positioning-container">
<div id="scroll-container">
    <table>
        <colgroup>
            <col class="col1"></col>
            <col class="col2"></col>
        </colgroup>
        <thead>
            <th class="header-col1"><div>Header 1</div></th>
            <th class="header-col2"><div>Header 2</div></th>
        </thead>
        <tbody>
            <tr><td>Cell 1.1</td><td>Cell 1.2</td></tr>
            <tr><td>Cell 2.1</td><td>Cell 2.2</td></tr>
            <tr><td>Cell 3.1</td><td>Cell 3.2</td></tr>
            <tr><td>Cell 4.1</td><td>Cell 4.2</td></tr>
            <tr><td>Cell 5.1</td><td>Cell 5.2</td></tr>
            <tr><td>Cell 6.1</td><td>Cell 6.2</td></tr>
            <tr><td>Cell 7.1</td><td>Cell 7.2</td></tr>

        </tbody>
    </table>
</div>
</div>

Và CSS:

table{
    border-collapse: collapse;
    table-layout: fixed;
    width: 100%;
}
/* Not required, just helps with alignment for this example */
td, th{
    padding: 0;
    margin: 0;
}

tbody{
    background-color: #ddf;
}

thead {
    /* Keeps the header in place. Don't forget top: 0 */
    position: absolute;
    top: 0;
    background-color: #ddd;

    /* The 17px is to adjust for the scrollbar width.
     * This is a new css value that makes this pure
     * css example possible */
    width: calc(100% - 17px);
    height: 20px;
}

/* Positioning container. Required to position the
 * header since the header uses position:absolute
 * (otherwise it would position at the top of the screen) */
#positioning-container{
    position: relative;
}

/* A container to set the scroll-bar and
 * includes padding to move the table contents
 * down below the header (padding = header height) */
#scroll-container{
    overflow-y: auto;
    padding-top: 20px;
    height: 100px;
}
.header-col1{
    background-color: red;
}

/* Fixed-width header columns need a div to set their width */
.header-col1 div{
    width: 100px;
}

/* Expandable columns need a width set on the th tag */
.header-col2{
    width: 100%;
}
.col1 {
    width: 100px;
}
.col2{
    width: 100%;
}

http://jsfiddle.net/HNHRv/3/


1

Đối với những người đã thử giải pháp tuyệt vời do Maximilian Hils đưa ra và không thành công để đưa nó vào hoạt động với Internet Explorer, tôi đã gặp vấn đề tương tự (Internet Explorer 11) và tìm hiểu vấn đề là gì.

Trong Internet Explorer 11, biến đổi kiểu (ít nhất là với dịch) không hoạt động <THEAD>. Tôi đã giải quyết điều này bằng cách thay vì áp dụng kiểu cho tất cả <TH>trong một vòng lặp. Điều đó đã làm việc. Mã JavaScript của tôi trông như thế này:

document.getElementById('pnlGridWrap').addEventListener("scroll", function () {
  var translate = "translate(0," + this.scrollTop + "px)";
  var myElements = this.querySelectorAll("th");
  for (var i = 0; i < myElements.length; i++) {
    myElements[i].style.transform=translate;
  }
});

Trong trường hợp của tôi, bảng là một GridView trong ASP.NET. Đầu tiên tôi nghĩ rằng đó là vì nó không có <THEAD>, nhưng ngay cả khi tôi buộc nó phải có nó, nó vẫn không hoạt động. Sau đó tôi tìm ra những gì tôi đã viết ở trên.

Đó là một giải pháp rất tốt đẹp và đơn giản. Trên Chrome thì hoàn hảo, trên Firefox hơi giật và trên Internet Explorer thậm chí còn giật hơn. Nhưng tất cả trong một giải pháp tốt.


0

Tôi ước tôi đã tìm thấy giải pháp của @ Mark sớm hơn, nhưng tôi đã đi và tự viết trước khi tôi thấy câu hỏi SO này ...

Mine là một plugin jQuery rất nhẹ hỗ trợ tiêu đề cố định, chân trang, kéo dài cột (colspan), thay đổi kích thước, cuộn ngang và một số hàng tùy chọn để hiển thị trước khi bắt đầu cuộn.

jQuery.scrollTableBody (GitHub)

Chừng nào bạn có một bảng với thích hợp <thead>, <tbody>và (không bắt buộc) <tfoot>, tất cả các bạn cần làm là:

$('table').scrollTableBody();

0

Tôi đã tìm thấy cách giải quyết này - di chuyển hàng tiêu đề trong bảng phía trên bảng có dữ liệu:

<html>
<head>
	<title>Fixed header</title>
	<style>
		table td {width:75px;}
	</style>
</head>

<body>
<div style="height:auto; width:350px; overflow:auto">
<table border="1">
<tr>
	<td>header 1</td>
	<td>header 2</td>
	<td>header 3</td>
</tr>
</table>
</div>

<div style="height:50px; width:350px; overflow:auto">
<table border="1">
<tr>
	<td>row 1 col 1</td>
	<td>row 1 col 2</td>
	<td>row 1 col 3</td>		
</tr>
<tr>
	<td>row 2 col 1</td>
	<td>row 2 col 2</td>
	<td>row 2 col 3</td>		
</tr>
<tr>
	<td>row 3 col 1</td>
	<td>row 3 col 2</td>
	<td>row 3 col 3</td>		
</tr>
<tr>
	<td>row 4 col 1</td>
	<td>row 4 col 2</td>
	<td>row 4 col 3</td>		
</tr>
<tr>
	<td>row 5 col 1</td>
	<td>row 5 col 2</td>
	<td>row 5 col 3</td>		
</tr>
<tr>
	<td>row 6 col 1</td>
	<td>row 6 col 2</td>
	<td>row 6 col 3</td>		
</tr>
</table>
</div>


</body>
</html>


hoạt động cho các bảng nhỏ, nhưng nếu bạn cuộn ngang thì giải pháp này sẽ không hoạt động.
crh225

Nó cũng sẽ không hoạt động đúng vì các cột của bảng sẽ không căn chỉnh. Ở đây bạn đang buộc chiều rộng cho td nhưng chúng ta không được làm ...
Ziggler

0

Bằng cách áp dụng plugin jQueryTableHeaders vào bảng, các tiêu đề cột sẽ bám vào đầu khung nhìn khi bạn cuộn xuống.

Thí dụ:

$(function () {
    $("table").stickyTableHeaders();
});

/*! Copyright (c) 2011 by Jonas Mosbech - https://github.com/jmosbech/StickyTableHeaders
	MIT license info: https://github.com/jmosbech/StickyTableHeaders/blob/master/license.txt */

;
(function ($, window, undefined) {
    'use strict';

    var name = 'stickyTableHeaders',
        id = 0,
        defaults = {
            fixedOffset: 0,
            leftOffset: 0,
            marginTop: 0,
            scrollableArea: window
        };

    function Plugin(el, options) {
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;

        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;
        base.id = id++;
        base.$window = $(window);
        base.$document = $(document);

        // Listen for destroyed, call teardown
        base.$el.bind('destroyed',
        $.proxy(base.teardown, base));

        // Cache DOM refs for performance reasons
        base.$clonedHeader = null;
        base.$originalHeader = null;

        // Keep track of state
        base.isSticky = false;
        base.hasBeenSticky = false;
        base.leftOffset = null;
        base.topOffset = null;

        base.init = function () {
            base.$el.each(function () {
                var $this = $(this);

                // remove padding on <table> to fix issue #7
                $this.css('padding', 0);

                base.$originalHeader = $('thead:first', this);
                base.$clonedHeader = base.$originalHeader.clone();
                $this.trigger('clonedHeader.' + name, [base.$clonedHeader]);

                base.$clonedHeader.addClass('tableFloatingHeader');
                base.$clonedHeader.css('display', 'none');

                base.$originalHeader.addClass('tableFloatingHeaderOriginal');

                base.$originalHeader.after(base.$clonedHeader);

                base.$printStyle = $('<style type="text/css" media="print">' +
                    '.tableFloatingHeader{display:none !important;}' +
                    '.tableFloatingHeaderOriginal{position:static !important;}' +
                    '</style>');
                $('head').append(base.$printStyle);
            });

            base.setOptions(options);
            base.updateWidth();
            base.toggleHeaders();
            base.bind();
        };

        base.destroy = function () {
            base.$el.unbind('destroyed', base.teardown);
            base.teardown();
        };

        base.teardown = function () {
            if (base.isSticky) {
                base.$originalHeader.css('position', 'static');
            }
            $.removeData(base.el, 'plugin_' + name);
            base.unbind();

            base.$clonedHeader.remove();
            base.$originalHeader.removeClass('tableFloatingHeaderOriginal');
            base.$originalHeader.css('visibility', 'visible');
            base.$printStyle.remove();

            base.el = null;
            base.$el = null;
        };

        base.bind = function () {
            base.$scrollableArea.on('scroll.' + name, base.toggleHeaders);
            if (!base.isWindowScrolling) {
                base.$window.on('scroll.' + name + base.id, base.setPositionValues);
                base.$window.on('resize.' + name + base.id, base.toggleHeaders);
            }
            base.$scrollableArea.on('resize.' + name, base.toggleHeaders);
            base.$scrollableArea.on('resize.' + name, base.updateWidth);
        };

        base.unbind = function () {
            // unbind window events by specifying handle so we don't remove too much
            base.$scrollableArea.off('.' + name, base.toggleHeaders);
            if (!base.isWindowScrolling) {
                base.$window.off('.' + name + base.id, base.setPositionValues);
                base.$window.off('.' + name + base.id, base.toggleHeaders);
            }
            base.$scrollableArea.off('.' + name, base.updateWidth);
        };

        base.toggleHeaders = function () {
            if (base.$el) {
                base.$el.each(function () {
                    var $this = $(this),
                        newLeft,
                        newTopOffset = base.isWindowScrolling ? (
                        isNaN(base.options.fixedOffset) ? base.options.fixedOffset.outerHeight() : base.options.fixedOffset) : base.$scrollableArea.offset().top + (!isNaN(base.options.fixedOffset) ? base.options.fixedOffset : 0),
                        offset = $this.offset(),

                        scrollTop = base.$scrollableArea.scrollTop() + newTopOffset,
                        scrollLeft = base.$scrollableArea.scrollLeft(),

                        scrolledPastTop = base.isWindowScrolling ? scrollTop > offset.top : newTopOffset > offset.top,
                        notScrolledPastBottom = (base.isWindowScrolling ? scrollTop : 0) < (offset.top + $this.height() - base.$clonedHeader.height() - (base.isWindowScrolling ? 0 : newTopOffset));

                    if (scrolledPastTop && notScrolledPastBottom) {
                        newLeft = offset.left - scrollLeft + base.options.leftOffset;
                        base.$originalHeader.css({
                            'position': 'fixed',
                                'margin-top': base.options.marginTop,
                                'left': newLeft,
                                'z-index': 3 // #18: opacity bug
                        });
                        base.leftOffset = newLeft;
                        base.topOffset = newTopOffset;
                        base.$clonedHeader.css('display', '');
                        if (!base.isSticky) {
                            base.isSticky = true;
                            // make sure the width is correct: the user might have resized the browser while in static mode
                            base.updateWidth();
                        }
                        base.setPositionValues();
                    } else if (base.isSticky) {
                        base.$originalHeader.css('position', 'static');
                        base.$clonedHeader.css('display', 'none');
                        base.isSticky = false;
                        base.resetWidth($('td,th', base.$clonedHeader), $('td,th', base.$originalHeader));
                    }
                });
            }
        };

        base.setPositionValues = function () {
            var winScrollTop = base.$window.scrollTop(),
                winScrollLeft = base.$window.scrollLeft();
            if (!base.isSticky || winScrollTop < 0 || winScrollTop + base.$window.height() > base.$document.height() || winScrollLeft < 0 || winScrollLeft + base.$window.width() > base.$document.width()) {
                return;
            }
            base.$originalHeader.css({
                'top': base.topOffset - (base.isWindowScrolling ? 0 : winScrollTop),
                    'left': base.leftOffset - (base.isWindowScrolling ? 0 : winScrollLeft)
            });
        };

        base.updateWidth = function () {
            if (!base.isSticky) {
                return;
            }
            // Copy cell widths from clone
            if (!base.$originalHeaderCells) {
                base.$originalHeaderCells = $('th,td', base.$originalHeader);
            }
            if (!base.$clonedHeaderCells) {
                base.$clonedHeaderCells = $('th,td', base.$clonedHeader);
            }
            var cellWidths = base.getWidth(base.$clonedHeaderCells);
            base.setWidth(cellWidths, base.$clonedHeaderCells, base.$originalHeaderCells);

            // Copy row width from whole table
            base.$originalHeader.css('width', base.$clonedHeader.width());
        };

        base.getWidth = function ($clonedHeaders) {
            var widths = [];
            $clonedHeaders.each(function (index) {
                var width, $this = $(this);

                if ($this.css('box-sizing') === 'border-box') {
                    width = $this[0].getBoundingClientRect().width; // #39: border-box bug
                } else {
                    var $origTh = $('th', base.$originalHeader);
                    if ($origTh.css('border-collapse') === 'collapse') {
                        if (window.getComputedStyle) {
                            width = parseFloat(window.getComputedStyle(this, null).width);
                        } else {
                            // ie8 only
                            var leftPadding = parseFloat($this.css('padding-left'));
                            var rightPadding = parseFloat($this.css('padding-right'));
                            // Needs more investigation - this is assuming constant border around this cell and it's neighbours.
                            var border = parseFloat($this.css('border-width'));
                            width = $this.outerWidth() - leftPadding - rightPadding - border;
                        }
                    } else {
                        width = $this.width();
                    }
                }

                widths[index] = width;
            });
            return widths;
        };

        base.setWidth = function (widths, $clonedHeaders, $origHeaders) {
            $clonedHeaders.each(function (index) {
                var width = widths[index];
                $origHeaders.eq(index).css({
                    'min-width': width,
                        'max-width': width
                });
            });
        };

        base.resetWidth = function ($clonedHeaders, $origHeaders) {
            $clonedHeaders.each(function (index) {
                var $this = $(this);
                $origHeaders.eq(index).css({
                    'min-width': $this.css('min-width'),
                        'max-width': $this.css('max-width')
                });
            });
        };

        base.setOptions = function (options) {
            base.options = $.extend({}, defaults, options);
            base.$scrollableArea = $(base.options.scrollableArea);
            base.isWindowScrolling = base.$scrollableArea[0] === window;
        };

        base.updateOptions = function (options) {
            base.setOptions(options);
            // scrollableArea might have changed
            base.unbind();
            base.bind();
            base.updateWidth();
            base.toggleHeaders();
        };

        // Run initializer
        base.init();
    }

    // A plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[name] = function (options) {
        return this.each(function () {
            var instance = $.data(this, 'plugin_' + name);
            if (instance) {
                if (typeof options === 'string') {
                    instance[options].apply(instance);
                } else {
                    instance.updateOptions(options);
                }
            } else if (options !== 'destroy') {
                $.data(this, 'plugin_' + name, new Plugin(this, options));
            }
        });
    };

})(jQuery, window);
body {
    margin: 0 auto;
    padding: 0 20px;
    font-family: Arial, Helvetica, sans-serif;
    font-size: 11px;
    color: #555;
}
table {
    border: 0;
    padding: 0;
    margin: 0 0 20px 0;
    border-collapse: collapse;
}
th {
    padding: 5px;
    /* NOTE: th padding must be set explicitly in order to support IE */
    text-align: right;
    font-weight:bold;
    line-height: 2em;
    color: #FFF;
    background-color: #555;
}
tbody td {
    padding: 10px;
    line-height: 18px;
    border-top: 1px solid #E0E0E0;
}
tbody tr:nth-child(2n) {
    background-color: #F7F7F7;
}
tbody tr:hover {
    background-color: #EEEEEE;
}
td {
    text-align: right;
}
td:first-child, th:first-child {
    text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div style="width:3000px">some really really wide content goes here</div>
<table>
    <thead>
        <tr>
            <th colspan="9">Companies listed on NASDAQ OMX Copenhagen.</th>
        </tr>
        <tr>
            <th>Full name</th>
            <th>CCY</th>
            <th>Last</th>
            <th>+/-</th>
            <th>%</th>
            <th>Bid</th>
            <th>Ask</th>
            <th>Volume</th>
            <th>Turnover</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>A.P. Møller...</td>
            <td>DKK</td>
            <td>33,220.00</td>
            <td>760</td>
            <td>2.34</td>
            <td>33,140.00</td>
            <td>33,220.00</td>
            <td>594</td>
            <td>19,791,910</td>
        </tr>
        <tr>
            <td>A.P. Møller...</td>
            <td>DKK</td>
            <td>34,620.00</td>
            <td>640</td>
            <td>1.88</td>
            <td>34,620.00</td>
            <td>34,700.00</td>
            <td>9,954</td>
            <td>346,530,246</td>
        </tr>
        <tr>
            <td>Carlsberg A</td>
            <td>DKK</td>
            <td>380</td>
            <td>0</td>
            <td>0</td>
            <td>371</td>
            <td>391.5</td>
            <td>6</td>
            <td>2,280</td>
        </tr>
        <tr>
            <td>Carlsberg B</td>
            <td>DKK</td>
            <td>364.4</td>
            <td>8.6</td>
            <td>2.42</td>
            <td>363</td>
            <td>364.4</td>
            <td>636,267</td>
            <td>228,530,601</td>
        </tr>
        <tr>
            <td>Chr. Hansen...</td>
            <td>DKK</td>
            <td>114.5</td>
            <td>-1.6</td>
            <td>-1.38</td>
            <td>114.2</td>
            <td>114.5</td>
            <td>141,822</td>
            <td>16,311,454</td>
        </tr>
        <tr>
            <td>Coloplast B</td>
            <td>DKK</td>
            <td>809.5</td>
            <td>11</td>
            <td>1.38</td>
            <td>809</td>
            <td>809.5</td>
            <td>85,840</td>
            <td>69,363,301</td>
        </tr>
        <tr>
            <td>D/S Norden</td>
            <td>DKK</td>
            <td>155</td>
            <td>-1.5</td>
            <td>-0.96</td>
            <td>155</td>
            <td>155.1</td>
            <td>51,681</td>
            <td>8,037,225</td>
        </tr>
        <tr>
            <td>Danske Bank</td>
            <td>DKK</td>
            <td>69.05</td>
            <td>2.55</td>
            <td>3.83</td>
            <td>69.05</td>
            <td>69.2</td>
            <td>1,723,719</td>
            <td>115,348,068</td>
        </tr>
        <tr>
            <td>DSV</td>
            <td>DKK</td>
            <td>105.4</td>
            <td>0.2</td>
            <td>0.19</td>
            <td>105.2</td>
            <td>105.4</td>
            <td>674,873</td>
            <td>71,575,035</td>
        </tr>
        <tr>
            <td>FLSmidth &amp; Co.</td>
            <td>DKK</td>
            <td>295.8</td>
            <td>-1.8</td>
            <td>-0.6</td>
            <td>295.1</td>
            <td>295.8</td>
            <td>341,263</td>
            <td>100,301,032</td>
        </tr>
        <tr>
            <td>G4S plc</td>
            <td>DKK</td>
            <td>22.53</td>
            <td>0.05</td>
            <td>0.22</td>
            <td>22.53</td>
            <td>22.57</td>
            <td>190,920</td>
            <td>4,338,150</td>
        </tr>
        <tr>
            <td>Jyske Bank</td>
            <td>DKK</td>
            <td>144.2</td>
            <td>1.4</td>
            <td>0.98</td>
            <td>142.8</td>
            <td>144.2</td>
            <td>78,163</td>
            <td>11,104,874</td>
        </tr>
        <tr>
            <td>Københavns ...</td>
            <td>DKK</td>
            <td>1,580.00</td>
            <td>-12</td>
            <td>-0.75</td>
            <td>1,590.00</td>
            <td>1,620.00</td>
            <td>82</td>
            <td>131,110</td>
        </tr>
        <tr>
            <td>Lundbeck</td>
            <td>DKK</td>
            <td>103.4</td>
            <td>-2.5</td>
            <td>-2.36</td>
            <td>103.4</td>
            <td>103.8</td>
            <td>157,162</td>
            <td>16,462,282</td>
        </tr>
        <tr>
            <td>Nordea Bank</td>
            <td>DKK</td>
            <td>43.22</td>
            <td>-0.06</td>
            <td>-0.14</td>
            <td>43.22</td>
            <td>43.25</td>
            <td>167,520</td>
            <td>7,310,143</td>
        </tr>
        <tr>
            <td>Novo Nordisk B</td>
            <td>DKK</td>
            <td>552.5</td>
            <td>-3.5</td>
            <td>-0.63</td>
            <td>550.5</td>
            <td>552.5</td>
            <td>843,533</td>
            <td>463,962,375</td>
        </tr>
        <tr>
            <td>Novozymes B</td>
            <td>DKK</td>
            <td>805.5</td>
            <td>5.5</td>
            <td>0.69</td>
            <td>805</td>
            <td>805.5</td>
            <td>152,188</td>
            <td>121,746,199</td>
        </tr>
        <tr>
            <td>Pandora</td>
            <td>DKK</td>
            <td>39.04</td>
            <td>0.94</td>
            <td>2.47</td>
            <td>38.8</td>
            <td>39.04</td>
            <td>350,965</td>
            <td>13,611,838</td>
        </tr>
        <tr>
            <td>Rockwool In...</td>
            <td>DKK</td>
            <td>492</td>
            <td>0</td>
            <td>0</td>
            <td>482</td>
            <td>492</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>Rockwool In...</td>
            <td>DKK</td>
            <td>468</td>
            <td>12</td>
            <td>2.63</td>
            <td>465.2</td>
            <td>468</td>
            <td>9,885</td>
            <td>4,623,850</td>
        </tr>
        <tr>
            <td>Sydbank</td>
            <td>DKK</td>
            <td>95</td>
            <td>0.05</td>
            <td>0.05</td>
            <td>94.7</td>
            <td>95</td>
            <td>103,438</td>
            <td>9,802,899</td>
        </tr>
        <tr>
            <td>TDC</td>
            <td>DKK</td>
            <td>43.6</td>
            <td>0.13</td>
            <td>0.3</td>
            <td>43.5</td>
            <td>43.6</td>
            <td>845,110</td>
            <td>36,785,339</td>
        </tr>
        <tr>
            <td>Topdanmark</td>
            <td>DKK</td>
            <td>854</td>
            <td>13.5</td>
            <td>1.61</td>
            <td>854</td>
            <td>855</td>
            <td>38,679</td>
            <td>32,737,678</td>
        </tr>
        <tr>
            <td>Tryg</td>
            <td>DKK</td>
            <td>290.4</td>
            <td>0.3</td>
            <td>0.1</td>
            <td>290</td>
            <td>290.4</td>
            <td>94,587</td>
            <td>27,537,247</td>
        </tr>
        <tr>
            <td>Vestas Wind...</td>
            <td>DKK</td>
            <td>90.15</td>
            <td>-4.2</td>
            <td>-4.45</td>
            <td>90.1</td>
            <td>90.15</td>
            <td>1,317,313</td>
            <td>121,064,314</td>
        </tr>
        <tr>
            <td>William Dem...</td>
            <td>DKK</td>
            <td>417.6</td>
            <td>0.1</td>
            <td>0.02</td>
            <td>417</td>
            <td>417.6</td>
            <td>64,242</td>
            <td>26,859,554</td>
        </tr>
    </tbody>
</table>
<div style="height: 4000px">lots of content down here...</div>


0

Tôi thích câu trả lời của Maximillian Hils nhưng tôi có một số vấn đề:

  1. biến đổi không hoạt động trong Edge hoặc IE trừ khi bạn áp dụng nó cho th
  2. các tiêu đề nhấp nháy trong khi cuộn trong Edge và IE
  3. bảng của tôi được tải bằng ajax, vì vậy tôi muốn đính kèm vào sự kiện cuộn cửa sổ hơn là sự kiện cuộn của trình bao bọc

Để thoát khỏi nhấp nháy, tôi sử dụng thời gian chờ để đợi cho đến khi người dùng cuộn xong, sau đó tôi áp dụng biến đổi - để tiêu đề không hiển thị trong khi cuộn.

Tôi cũng đã viết điều này bằng cách sử dụng jQuery, một lợi thế của việc đó là jQuery sẽ xử lý các tiền tố của nhà cung cấp cho bạn

    var isScrolling, lastTop, lastLeft, isLeftHidden, isTopHidden;

    //Scroll events don't bubble https://stackoverflow.com/a/19375645/150342
    //so can't use $(document).on("scroll", ".table-container-fixed", function (e) {
    document.addEventListener('scroll', function (event) {
        var $container = $(event.target);
        if (!$container.hasClass("table-container-fixed"))
            return;    

        //transform needs to be applied to th for Edge and IE
        //in this example I am also fixing the leftmost column
        var $topLeftCell = $container.find('table:first > thead > tr > th:first');
        var $headerCells = $topLeftCell.siblings();
        var $columnCells = $container
           .find('table:first > tbody > tr > td:first-child, ' +
                 'table:first > tfoot > tr > td:first-child');

        //hide the cells while returning otherwise they show on top of the data
        if (!isLeftHidden) {
            var currentLeft = $container.scrollLeft();
            if (currentLeft < lastLeft) {
                //scrolling left
                isLeftHidden = true;
                $topLeftCell.css('visibility', 'hidden');
                $columnCells.css('visibility', 'hidden');
            }
            lastLeft = currentLeft;
        }

        if (!isTopHidden) {
            var currentTop = $container.scrollTop();
            if (currentTop < lastTop) {
                //scrolling up
                isTopHidden = true;
                $topLeftCell.css('visibility', 'hidden');
                $headerCells.css('visibility', 'hidden');
            }
            lastTop = currentTop;
        }

        // Using timeout to delay transform until user stops scrolling
        // Clear timeout while scrolling
        window.clearTimeout(isScrolling);

        // Set a timeout to run after scrolling ends
        isScrolling = setTimeout(function () {
            //move the table cells. 
            var x = $container.scrollLeft();
            var y = $container.scrollTop();

            $topLeftCell.css('transform', 'translate(' + x + 'px, ' + y + 'px)');
            $headerCells.css('transform', 'translateY(' + y + 'px)');
            $columnCells.css('transform', 'translateX(' + x + 'px)');

            isTopHidden = isLeftHidden = false;
            $topLeftCell.css('visibility', 'inherit');
            $headerCells.css('visibility', 'inherit');
            $columnCells.css('visibility', 'inherit');
        }, 100);

    }, true);

Bảng được bọc trong một div với lớp table-container-fixed.

.table-container-fixed{
    overflow: auto;
    height: 400px;
}

Tôi đặt thu gọn đường viền thành tách biệt vì nếu không, chúng tôi sẽ mất viền trong quá trình dịch và tôi xóa đường viền trên bảng để dừng nội dung xuất hiện ngay phía trên ô nơi đường viền đang cuộn.

.table-container-fixed > table {
   border-collapse: separate;
   border:none;
}

Tôi tạo thnền trắng để che các ô bên dưới và tôi thêm một đường viền khớp với đường viền bảng - được tạo kiểu bằng Bootstrap và cuộn ra khỏi tầm nhìn.

 .table-container-fixed > table > thead > tr > th {
        border-top: 1px solid #ddd !important;
        background-color: white;        
        z-index: 10;
        position: relative;/*to make z-index work*/
    }

            .table-container-fixed > table > thead > tr > th:first-child {
                z-index: 20;
            }

.table-container-fixed > table > tbody > tr > td:first-child,
.table-container-fixed > table > tfoot > tr > td:first-child {
    background-color: white;        
    z-index: 10;
    position: relative;
}

0

Sử dụng phiên bản mới nhất của jQuery và bao gồm mã JavaScript sau.

$(window).scroll(function(){
  $("id of the div element").offset({top:$(window).scrollTop()});
});

1
Điều này dường như không hoạt động. Có lẽ bạn có thể làm rõ những gì bạn muốn chúng tôi làm?
Chris

1
Những gì div? Chúng ta đang nói về các bảng ở đây
isapir

0

Đây không phải là một giải pháp chính xác cho hàng tiêu đề cố định, nhưng tôi đã tạo ra một phương pháp khá khéo léo để lặp lại hàng tiêu đề trong suốt bảng dài, nhưng vẫn giữ khả năng sắp xếp.

Tùy chọn nhỏ gọn này yêu cầu plugin jQuerytablesorter . Đây là cách nó hoạt động:

HTML

<table class="tablesorter boxlist" id="pmtable">
    <thead class="fixedheader">
        <tr class="boxheadrow">
            <th width="70px" class="header">Job Number</th>
            <th width="10px" class="header">Pri</th>
            <th width="70px" class="header">CLLI</th>
            <th width="35px" class="header">Market</th>
            <th width="35px" class="header">Job Status</th>
            <th width="65px" class="header">Technology</th>
            <th width="95px;" class="header headerSortDown">MEI</th>
            <th width="95px" class="header">TEO Writer</th>
            <th width="75px" class="header">Quote Due</th>
            <th width="100px" class="header">Engineer</th>
            <th width="75px" class="header">ML Due</th>
            <th width="75px" class="header">ML Complete</th>
            <th width="75px" class="header">SPEC Due</th>
            <th width="75px" class="header">SPEC Complete</th>
            <th width="100px" class="header">Install Supervisor</th>
            <th width="75px" class="header">MasTec OJD</th>
            <th width="75px" class="header">Install Start</th>
            <th width="30px" class="header">Install Hours</th>
            <th width="75px" class="header">Revised CRCD</th>
            <th width="75px" class="header">Latest Ship-To-Site</th>
            <th width="30px" class="header">Total Parts</th>
            <th width="30px" class="header">OEM Rcvd</th>
            <th width="30px" class="header">Minor Rcvd</th>
            <th width="30px" class="header">Total Received</th>
            <th width="30px" class="header">% On Site</th>
            <th width="60px" class="header">Actions</th>
        </tr>
    </thead>
        <tbody class="scrollable">
            <tr data-job_id="3548" data-ml_id="" class="odd">
                <td class="c black">FL-8-RG9UP</td>
                <td data-pri="2" class="priority c yellow">M</td>
                <td class="c">FTLDFLOV</td>
                <td class="c">SFL</td>
                <td class="c">NOI</td>
                <td class="c">TRANSPORT</td>
                <td class="c"></td>
                <td class="c">Chris Byrd</td>
                <td class="c">Apr 13, 2013</td>
                <td class="c">Kris Hall</td>
                <td class="c">May 20, 2013</td>
                <td class="c">May 20, 2013</td>
                <td class="c">Jun 5, 2013</td>
                <td class="c">Jun 7, 2013</td>
                <td class="c">Joseph Fitz</td>
                <td class="c">Jun 10, 2013</td>
                <td class="c">TBD</td>
                <td class="c">123</td>
                <td class="c revised_crcd"><input readonly="true" name="revised_crcd" value="Jul 26, 2013" type="text" size="12" class="smInput r_crcd c hasDatepicker" id="dp1377194058616"></td>
                <td class="c">TBD</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="actions"><span style="float:left;" class="ui-icon ui-icon-folder-open editJob" title="View this job" s="" details'=""></span></td>
            </tr>
            <tr data-job_id="4264" data-ml_id="2959" class="even">
                <td class="c black">MTS13009SF</td>
                <td data-pri="2" class="priority c yellow">M</td>
                <td class="c">OJUSFLTL</td>
                <td class="c">SFL</td>
                <td class="c">NOI</td>
                <td class="c">TRANSPORT</td>
                <td class="c"></td>
                <td class="c">DeMarcus Stewart</td>
                <td class="c">May 22, 2013</td>
                <td class="c">Ryan Alsobrook</td>
                <td class="c">Jun 19, 2013</td>
                <td class="c">Jun 27, 2013</td>
                <td class="c">Jun 19, 2013</td>
                <td class="c">Jul 4, 2013</td>
                <td class="c">Randy Williams</td>
                <td class="c">Jun 21, 2013</td>
                <td class="c">TBD</td>
                <td class="c">95</td>
                <td class="c revised_crcd"><input readonly="true" name="revised_crcd" value="Aug 9, 2013" type="text" size="12" class="smInput r_crcd c hasDatepicker" id="dp1377194058632"></td><td class="c">TBD</td>
                <td class="c">0</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="actions"><span style="float:left;" class="ui-icon ui-icon-folder-open editJob" title="View this job" s="" details'=""></span><input style="float:left;" type="hidden" name="req_ship" class="reqShip hasDatepicker" id="dp1377194058464"><span style="float:left;" class="ui-icon ui-icon-calendar requestShip" title="Schedule this job for shipping"></span><span class="ui-icon ui-icon-info viewOrderInfo" style="float:left;" title="Show material details for this order"></span></td>
            </tr>
            .
            .
            .
            .
            <tr class="boxheadrow repeated-header">
                <th width="70px" class="header">Job Number</th>
                <th width="10px" class="header">Pri</th>
                <th width="70px" class="header">CLLI</th>
                <th width="35px" class="header">Market</th>
                <th width="35px" class="header">Job Status</th>
                <th width="65px" class="header">Technology</th>
                <th width="95px;" class="header">MEI</th>
                <th width="95px" class="header">TEO Writer</th>
                <th width="75px" class="header">Quote Due</th>
                <th width="100px" class="header">Engineer</th>
                <th width="75px" class="header">ML Due</th>
                <th width="75px" class="header">ML Complete</th>
                <th width="75px" class="header">SPEC Due</th>
                <th width="75px" class="header">SPEC Complete</th>
                <th width="100px" class="header">Install Supervisor</th>
                <th width="75px" class="header">MasTec OJD</th>
                <th width="75px" class="header">Install Start</th>
                <th width="30px" class="header">Install Hours</th>
                <th width="75px" class="header">Revised CRCD</th>
                <th width="75px" class="header">Latest Ship-To-Site</th>
                <th width="30px" class="header">Total Parts</th>
                <th width="30px" class="header">OEM Rcvd</th>
                <th width="30px" class="header">Minor Rcvd</th>
                <th width="30px" class="header">Total Received</th>
                <th width="30px" class="header">% On Site</th>
                <th width="60px" class="header">Actions</th>
            </tr>

Rõ ràng, bảng của tôi có nhiều hàng hơn thế này. Chính xác là 193, nhưng bạn có thể thấy nơi hàng tiêu đề lặp lại. Hàng tiêu đề lặp lại được thiết lập bởi chức năng này:

jQuery

// Clone the original header row and add the "repeated-header" class
var tblHeader = $('tr.boxheadrow').clone().addClass('repeated-header');

// Add the cloned header with the new class every 34th row (or as you see fit)
$('tbody tr:odd:nth-of-type(17n)').after(tblHeader);

// On the 'sortStart' routine, remove all the inserted header rows
$('#pmtable').bind('sortStart', function() {
    $('.repeated-header').remove();
    // On the 'sortEnd' routine, add back all the header row lines.
}).bind('sortEnd', function() {
    $('tbody tr:odd:nth-of-type(17n)').after(tblHeader);
});

0

Rất nhiều người dường như đang tìm kiếm câu trả lời này. Tôi thấy nó bị chôn vùi trong một câu trả lời cho một câu hỏi khác ở đây: Đồng bộ hóa độ rộng cột giữa các bảng trong hai khung khác nhau, v.v.

Trong số hàng tá phương thức tôi đã thử, đây là phương pháp duy nhất tôi thấy hoạt động đáng tin cậy để cho phép bạn có một bảng dưới cùng cuộn với bảng tiêu đề có cùng độ rộng.

Đây là cách tôi đã làm, đầu tiên tôi đã cải thiện jsfiddle ở trên để tạo chức năng này, hoạt động trên cả hai tdth(trong trường hợp làm vấp ngã những người khác sử dụng thđể tạo kiểu cho các hàng tiêu đề của họ).

var setHeaderTableWidth= function (headertableid,basetableid) {
            $("#"+headertableid).width($("#"+basetableid).width());
            $("#"+headertableid+" tr th").each(function (i) {
                $(this).width($($("#"+basetableid+" tr:first td")[i]).width());
            });
            $("#" + headertableid + " tr td").each(function (i) {
                $(this).width($($("#" + basetableid + " tr:first td")[i]).width());
            });
        }

Tiếp theo, bạn cần tạo hai bảng, GHI CHÚ bảng tiêu đề nên có thêm một khoảng trống TDđể rời khỏi phòng trong bảng trên cùng cho thanh cuộn, như thế này:

 <table id="headertable1" class="input-cells table-striped">
        <thead>
            <tr style="background-color:darkgray;color:white;"><th>header1</th><th>header2</th><th>header3</th><th>header4</th><th>header5</th><th>header6</th><th></th></tr>
        </thead>
     </table>
    <div id="resizeToBottom" style="overflow-y:scroll;overflow-x:hidden;">
        <table id="basetable1" class="input-cells table-striped">
            <tbody >
                <tr>
                    <td>testdata</td>
                    <td>2</td>
                    <td>3</td>
                    <td>4</span></td>
                    <td>55555555555555</td>
                    <td>test</td></tr>
            </tbody>
        </table>
    </div>

Sau đó làm một cái gì đó như:

        setHeaderTableWidth('headertable1', 'basetable1');
        $(window).resize(function () {
            setHeaderTableWidth('headertable1', 'basetable1');
        });

Đây là giải pháp duy nhất mà tôi tìm thấy trên Stack Overflow hoạt động trong số nhiều câu hỏi tương tự đã được đăng, hoạt động trong tất cả các trường hợp của tôi.

Ví dụ: tôi đã dùng thử plugin stickytables của jQuery không hoạt động với durandal và dự án Google Code tại đây https://code.google.com.vn/p/js-scroll-table-header/issues/detail?id=2

Các giải pháp khác liên quan đến nhân bản các bảng, có hiệu suất kém hoặc hút và không hoạt động trong mọi trường hợp.

Không cần cho các giải pháp quá phức tạp. Chỉ cần tạo hai bảng như các ví dụ dưới đây và gọi hàm setHeaderTableWidth như được mô tả ở đây và boom, bạn đã hoàn thành .

Nếu điều này không phù hợp với bạn, có lẽ bạn đã chơi với thuộc tính kích thước hộp CSS của mình và bạn cần đặt chính xác. Thật dễ dàng để làm hỏng nội dung CSS của bạn một cách tình cờ. Có rất nhiều điều có thể đi sai, vì vậy chỉ cần nhận thức / cẩn thận về điều đó. Cách tiếp cận này làm việc cho tôi .


0

Đây là một giải pháp mà chúng tôi đã kết thúc với (để giải quyết một số trường hợp cạnh và các phiên bản Internet Explorer cũ hơn, cuối cùng chúng tôi cũng làm mờ thanh tiêu đề khi cuộn sau đó mờ dần khi cuộn kết thúc, nhưng trong trình duyệt Firefox và WebKit giải pháp này chỉ hoạt động . Nó giả định sụp đổ biên giới: sụp đổ.

Chìa khóa cho giải pháp này là một khi bạn áp dụng thu gọn viền , các phép biến đổi CSS hoạt động trên tiêu đề, do đó, chỉ cần chặn các sự kiện cuộn và đặt biến đổi chính xác. Bạn không cần phải sao chép bất cứ điều gì. Thiếu hành vi này được thực hiện đúng trong trình duyệt, thật khó để tưởng tượng một giải pháp nhẹ hơn.

Mã thông báo: http://jsfiddle.net/podperson/tH9VU/2/

Nó được triển khai như một plugin jQuery đơn giản. Bạn chỉ cần làm cho thead của bạn dính với một cuộc gọi như $ ('thead'). Dính (), và họ sẽ đi loanh quanh. Nó hoạt động cho nhiều bảng trên một trang và phần đầu nằm ở giữa các bảng lớn.

$.fn.sticky = function(){
    $(this).each( function(){
        var thead = $(this),
            tbody = thead.next('tbody');

        updateHeaderPosition();

        function updateHeaderPosition(){
            if(
                thead.offset().top < $(document).scrollTop()
                && tbody.offset().top + tbody.height() > $(document).scrollTop()
            ){
                var tr = tbody.find('tr').last(),
                    y = tr.offset().top - thead.height() < $(document).scrollTop()
                        ? tr.offset().top - thead.height() - thead.offset().top
                        : $(document).scrollTop() - thead.offset().top;

                thead.find('th').css({
                    'z-index': 100,
                    'transform': 'translateY(' + y + 'px)',
                    '-webkit-transform': 'translateY(' + y + 'px)'
                });
            } else {
                thead.find('th').css({
                    'transform': 'none',
                    '-webkit-transform': 'none'
                });
            }
        }

        // See http://www.quirksmode.org/dom/events/scroll.html
        $(window).on('scroll', updateHeaderPosition);
    });
}

$('thead').sticky();

giải pháp tốt nhưng làm thế nào để bạn bao gồm các đường viền cột giữa các cột (cả trong tiêu đề cố định, được căn chỉnh với dữ liệu td)?
dùng5249203

Tôi không chắc tôi hiểu vấn đề của bạn. thu gọn biên giới không ngăn bạn sử dụng các đường viền, lề, v.v., nó chỉ loại bỏ các số liệu bảng voodoo của ngày xưa.
podperson

1
Thêm border: 2px solid red;vào th, cuộn, và bạn sẽ thấy vấn đề. Tôi đã tự mình nghĩ ra giải pháp cơ bản hơn này: jsfiddle.net/x6pLcor9/19
calandoa

Thêm đường viền cùng kích thước vào td và không có vấn đề gì. Tôi không thấy quan điểm của bạn. Phiên bản của bạn sạch hơn nhiều và không sử dụng jQuery vì vậy tôi chắc chắn sẽ sử dụng một cái gì đó giống như ngày hôm nay. (Mặc dù, thành thật mà nói, tôi không nghĩ rằng tôi sẽ sử dụng một bảng cả ngày hôm nay.)
podperson

0

Dưới đây là một câu trả lời được cải thiện cho câu trả lời được đăng bởi Maximilian Hils .

Cái này hoạt động trong Internet Explorer 11 mà không nhấp nháy gì:

var headerCells = tableWrap.querySelectorAll("thead td");
for (var i = 0; i < headerCells.length; i++) {
    var headerCell = headerCells[i];
    headerCell.style.backgroundColor = "silver";
}
var lastSTop = tableWrap.scrollTop;
tableWrap.addEventListener("scroll", function () {
    var stop = this.scrollTop;
    if (stop < lastSTop) {
        // Resetting the transform for the scrolling up to hide the headers
        for (var i = 0; i < headerCells.length; i++) {
            headerCells[i].style.transitionDelay = "0s";
            headerCells[i].style.transform = "";
        }
    }
    lastSTop = stop;
    var translate = "translate(0," + stop + "px)";
    for (var i = 0; i < headerCells.length; i++) {
        headerCells[i].style.transitionDelay = "0.25s";
        headerCells[i].style.transform = translate;
    }
});

0

Tôi đã phát triển một trình cắm jQuery trọng lượng nhẹ đơn giản để chuyển đổi một bảng HTML được định dạng tốt thành một bảng có thể cuộn với các tiêu đề và cột của bảng cố định.

Plugin hoạt động tốt để khớp định vị pixel-pixel với phần cố định với phần có thể cuộn. Ngoài ra, bạn cũng có thể đóng băng số lượng cột sẽ luôn ở chế độ xem khi cuộn theo chiều ngang.

Bản giới thiệu & Tài liệu: http://meetselva.github.io/fixed-table-rows-cols/

Kho lưu trữ GitHub: https://github.com/meetselva/fixed-table-rows-cols

Dưới đây là cách sử dụng cho một bảng đơn giản với tiêu đề cố định,

$(<table selector>).fxdHdrCol({
    width:     "100%",
    height:    200,
    colModal: [{width: 30, align: 'center'},
               {width: 70, align: 'center'}, 
               {width: 200, align: 'left'}, 
               {width: 100, align: 'center'}, 
               {width: 70, align: 'center'}, 
               {width: 250, align: 'center'}
              ]
});

Là gì "một bảng HTML tốt" ?
Peter Mortensen

@PeterMortensen Đáng lẽ phải là "HTML được định dạng tốt". Đã chỉnh sửa, Cảm ơn.
Selvakumar Arumugam

0
<html>
<head>
    <script src="//cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
    <script>
        function stickyTableHead (tableID) {
            var $tmain = $(tableID);
            var $tScroll = $tmain.children("thead")
                .clone()
                .wrapAll('<table id="tScroll" />')
                .parent()
                .addClass($(tableID).attr("class"))
                .css("position", "fixed")
                .css("top", "0")
                .css("display", "none")
                .prependTo("#tMain");

            var pos = $tmain.offset().top + $tmain.find(">thead").height();


            $(document).scroll(function () {
                var dataScroll = $tScroll.data("scroll");
                dataScroll = dataScroll || false;
                if ($(this).scrollTop() >= pos) {
                    if (!dataScroll) {
                        $tScroll
                            .data("scroll", true)
                            .show()
                            .find("th").each(function () {
                                $(this).width($tmain.find(">thead>tr>th").eq($(this).index()).width());
                            });
                    }
                } else {
                    if (dataScroll) {
                        $tScroll
                            .data("scroll", false)
                            .hide()
                        ;
                    }
                }
            });
        }

        $(document).ready(function () {
            stickyTableHead('#tMain');
        });
    </script>
</head>

<body>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>

    <table id="tMain" >
        <thead>
        <tr>
            <th>1</th> <th>2</th><th>3</th> <th>4</th><th>5</th> <th>6</th><th>7</th> <th>8</th>

        </tr>
        </thead>
        <tbody>
            <tr><td>11111111111111111111111111111111111111111111111111111111</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
        </tbody>
    </table>
</body>
</html>

0

Bổ sung cho câu trả lời @Daniel Waltrip. Bảng cần phải kèm theo div position: relativeđể làm việc với position:sticky. Vì vậy, tôi muốn gửi mã mẫu của tôi ở đây.

CSS

/* Set table width/height as you want.*/
div.freeze-header {
  position: relative;
  max-height: 150px;
  max-width: 400px;
  overflow:auto;
}

/* Use position:sticky to freeze header on top*/
div.freeze-header > table > thead > tr > th {
  position: sticky;
  top: 0;
  background-color:yellow;
}

/* below is just table style decoration.*/
div.freeze-header > table {
  border-collapse: collapse;
}

div.freeze-header > table td {
  border: 1px solid black;
}

HTML

<html>
<body>
  <div>
   other contents ...
  </div>
  <div>
   other contents ...
  </div>
  <div>
   other contents ...
  </div>

  <div class="freeze-header">
    <table>
       <thead>
         <tr>
           <th> header 1 </th>
           <th> header 2 </th>
           <th> header 3 </th>
           <th> header 4 </th>
           <th> header 5 </th>
           <th> header 6 </th>
           <th> header 7 </th>
           <th> header 8 </th>
           <th> header 9 </th>
           <th> header 10 </th>
           <th> header 11 </th>
           <th> header 12 </th>
           <th> header 13 </th>
           <th> header 14 </th>
           <th> header 15 </th>
          </tr>
       </thead>
       <tbody>
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
       </tbody>
    </table>
  </div>
</body>
</html>

Bản giới thiệu

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.