Tabel HTML dengan tajuk tetap?


231

Apakah ada teknik CSS / JavaScript lintas-browser untuk menampilkan tabel HTML yang panjang sehingga tajuk kolom tetap terpasang di layar dan tidak menggulir dengan badan tabel. Pikirkan efek "panel beku" di Microsoft Excel.

Saya ingin dapat menggulir isi tabel, tetapi untuk selalu dapat melihat tajuk kolom di bagian atas.


3
Coba ini: Tabel Digulir CSS Murni dengan Fixed Header EDIT : Yang ini harus bekerja di Internet Explorer 7 seperti yang terlihat dalam contoh : Menggulir Tabel HTML dengan Fixed Header EDIT 2: Saya menemukan beberapa tautan tambahan yang dapat digunakan: - Bodoh header tetap - Sebuah plugin jQuery dengan beberapa batasan. - [Fixed Table Headers] ( cross-browser.com/x/examp
gcores

Saya telah menemukan banyak solusi yang umumnya bekerja tetapi tidak satupun dari mereka yang bekerja scrolling div. Maksud saya, meja Anda berada di dalam div yang dapat digulir dan Anda tetap menginginkan tajuk tabel Anda masih di dalam div itu. Saya telah memecahkannya dan membagikan solusinya di sini .
Yogee

9
Pada tahun 2018, semua browser dapat menggunakan solusi sederhana berikut: thead th { position: sticky; top: 0; }. Safari membutuhkan awalan vendor:-webkit-sticky
Daniel Waltrip

1
@DanielWaltrip Anda harus menambahkan jawaban ini sehingga dapat naik-memilih ke posisi teratas - semua jawaban lain berlebihan dengan posisi: lengket menjadi dukungan yang lebih baik saat ini
Peter Kerr

Jawaban:


88

Saya mencari solusi untuk sementara waktu dan menemukan sebagian besar jawaban tidak berfungsi atau tidak cocok untuk situasi saya, jadi saya menulis solusi sederhana dengan jQuery.

Ini adalah garis besar solusinya:

  1. Kloning tabel yang perlu memiliki header tetap, dan tempatkan salinan yang dikloning di atas aslinya.
  2. Hapus tubuh tabel dari tabel atas.
  3. Hapus header tabel dari tabel bawah.
  4. Sesuaikan lebar kolom. (Kami melacak lebar kolom asli)

Di bawah ini adalah kode dalam demo yang dapat dijalankan.

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>

Solusi ini berfungsi di Chrome dan IE. Karena didasarkan pada jQuery, ini juga bisa digunakan di browser lain yang didukung jQuery.


4
dan bagaimana kita bisa menyelesaikan masalah ketika konten lebih besar dari lebarnya?
Maertz

1
@tetra td {max-width: 30px; } ini akan memungkinkan Anda pengembang untuk mengontrol bagaimana baris ditampilkan.
Lyuben Todorov

Tetapi bagaimana jika konten di beberapa sel header lebih panjang daripada di sel td? Saya mencoba itu di IE7, dan width () merusak segalanya. IE8 dan IE9 berfungsi dengan baik, ...
JustAMartin

4
Sayangnya, jika Anda memerlukan penyelarasan piksel-sempurna pada kolom, ini tidak berfungsi: jsbin.com/elekiq/1 ( kode sumber ). Anda dapat melihat bahwa beberapa header diimbangi dari tempat seharusnya, hanya sedikit. Efeknya lebih jelas jika Anda menggunakan latar belakang: jsbin.com/elekiq/2 ( kode sumber ). (Saya bekerja di sepanjang baris yang sama ini, berlari ke ini dalam kode saya, menemukan milik Anda dan berpikir, "Oh, saya ingin tahu apakah dia telah memecahkannya untuk saya!" Sayangnya tidak. :-)) Peramban seperti rasa sakit karena ingin mengendalikan lebar sel ...
TJ Crowder

Ini tampaknya tidak berfungsi dengan pengguliran horizontal - ia menciptakan tajuk, tetapi meluas di luar area yang dapat digulir (tampak) dan tidak menggulir dengan konten.
Kecelakaan

183

Ini dapat diselesaikan dengan rapi dalam empat baris kode.

Jika Anda hanya peduli dengan browser modern, header tetap dapat dicapai lebih mudah dengan menggunakan transformasi CSS. Kedengarannya aneh, tetapi bekerja dengan sangat baik:

  • HTML dan CSS tetap apa adanya.
  • Tidak ada ketergantungan JavaScript eksternal.
  • Empat baris kode.
  • Bekerja untuk semua konfigurasi (tata letak tabel: diperbaiki, dll.).
document.getElementById("wrap").addEventListener("scroll", function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

Dukungan untuk transformasi CSS tersedia secara luas kecuali untuk Internet Explorer 8-.

Ini adalah contoh lengkap untuk referensi:


8
Saya harus mengatakan itu, meskipun komentar saya sebelumnya, ini adalah hal yang paling dekat dengan solusi sempurna yang pernah saya lihat. Bahkan pengguliran horizontal sempurna (lebih baik daripada solusi saya sendiri). Berikut ini adalah contoh dengan border (Anda tidak dapat menggunakan border-collapse) dan scrollbar yang menempel pada tabel alih-alih wadah: jsfiddle
DoctorDestructo

11
Ditemukan, itu berfungsi tetapi harus menerapkan transformasi ke th / td, bukan thead.
Si rambut merah

5
@AlexAlexeev, solusi Anda luar biasa. Terima kasih. Saya perhatikan bahwa, tajuk tetap yang dihasilkan tidak memiliki garis batas yang membedakan kolom. Gaya CSS default hilang. Bahkan ketika saya memasukkan ini ... $(this).addClass('border')mengubah sisa tabel fitur font, ukuran, warna yang saya lewati di kelas perbatasan. Tapi, tidak menambahkan baris ke header tetap. Hargai, masukan apa pun tentang cara memperbaikinya
user5249203

5
@ user5249203 Saya tahu Anda bertanya beberapa bulan yang lalu tetapi saya memiliki masalah yang sama dan itu karena perbatasan-runtuh: lihat ini: stackoverflow.com/questions/33777751/… .
archz

6
Ini tidak berfungsi di versi IE atau di Edge. Ini adalah versi yang didasarkan pada komentar @ redhead jsfiddle.net/n6o8ocwb/2
rob

58

Saya baru saja selesai menyusun plugin jQuery yang akan mengambil tabel tunggal yang valid menggunakan HTML yang valid (harus memiliki thead dan tbody) dan akan menampilkan tabel yang memiliki header tetap, footer tetap opsional yang bisa berupa header kloning atau konten yang Anda pilih (pagination, dll.). Jika Anda ingin memanfaatkan monitor yang lebih besar, itu juga akan mengubah ukuran tabel saat browser diubah ukurannya. Fitur lain yang ditambahkan adalah dapat menggulir ke samping jika kolom tabel tidak dapat semuanya terlihat.

http://fixedheadertable.com/

pada github: http://markmalek.github.com/Fixed-Header-Table/

Ini sangat mudah untuk diatur dan Anda dapat membuat gaya kustom Anda sendiri untuk itu. Ini juga menggunakan sudut bulat di semua browser. Perlu diingat saya baru saja merilisnya, jadi masih secara teknis beta dan ada sedikit masalah kecil yang saya setrika.

Ini bekerja di Internet Explorer 7, Internet Explorer 8, Safari, Firefox dan Chrome.


Terima kasih! Saya menambahkan rilis baru hari ini ketika saya pulang kerja. Berikut ini tautan ke entri blog saya dengan apa yang saya tambahkan: fixedheadertable.mmalek.com/2009/10/07/…
Mark

Terima kasih untuk ini. Aku tahu pertanyaan ini adalah lebih dari satu tahun, tapi bahkan pada risiko mengaduk lumpur menetap, saya ingin memberitahu Anda bahwa pekerjaan Anda dihargai
sova

Dalam demo Anda, lebar tidak ada dalam ie6 :-( header tabel dan tubuh tidak selaras.
Cheekysoft

4
Versi terbaru tidak berfungsi di IE6. Saya tidak lagi mendukung IE6.
Tandai

pekerjaan hebat Tandai - sayangnya ada beberapa masalah dengan pengguliran tajuk dan kolom tetap di perangkat seluler (iPad, tablet Android) - ketika saya menggulir konten bagian yang tidak digulir - ketika saya berhenti menggulir dan mengetuk sekali tabel , bagian yang diperbaiki "melompat" ke posisi yang tepat - apakah ada cara sederhana untuk memperbaikinya?
Okizb

23

Saya juga membuat plugin yang membahas masalah ini. Proyek saya - jQuery.floatThead telah ada selama lebih dari 4 tahun sekarang dan sangat matang.

Tidak memerlukan gaya eksternal dan tidak mengharapkan meja Anda ditata dengan cara tertentu. Ini mendukung Internet Explorer9 + dan Firefox / Chrome.

Saat ini (2018-05) ia memiliki:

405 komit dan 998 bintang di GitHub


Banyak (tidak semua) jawaban di sini adalah peretasan cepat yang mungkin telah memecahkan masalah yang dialami satu orang, tetapi tidak akan berhasil untuk setiap tabel.

Beberapa plugin lain sudah tua dan mungkin bekerja sangat baik dengan Internet Explorer, tetapi akan rusak pada Firefox dan Chrome.


1
Plugin hebat, mendukung tabel dan offset bersarang.
Mihai Alex

2
Bagus. Terima kasih banyak. Plugin ini bekerja dengan baik di Firefox 45.2, Chromium 51 dan IE 11. Selain itu, plugin ini tidak mengganggu banyak kode JS dan jQuery yang dibangun di halaman yang sama.
Aldo Paradiso

Terima kasih. Saya senang melaporkan bahwa proyek mendapat sekitar 1 laporan bug setiap 4 bulan pada saat ini. Saya tidak membuat banyak perubahan. Ini cukup solid dan berfungsi.
mkoryak

20

TL; DR

Jika Anda menargetkan peramban modern dan tidak memiliki kebutuhan penataan yang mewah: http://jsfiddle.net/dPixie/byB9d/3/ ... Meskipun versi empat besar cukup manis juga versi ini menangani lebar cairan jauh lebih baik.

Berita baik semuanya!

Dengan kemajuan HTML5 dan CSS3 ini sekarang mungkin, setidaknya untuk browser modern. Implementasi yang sedikit meretas yang saya buat dapat ditemukan di sini: http://jsfiddle.net/dPixie/byB9d/3/ . Saya telah mengujinya di FX 25, Chrome 31 dan IE 10 ...

HTML yang relevan (masukkan doctype HTML5 di bagian atas dokumen Anda):

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>

Tapi bagaimana caranya?!

Sederhananya Anda memiliki header tabel, yang Anda sembunyikan secara visual dengan membuatnya tinggi 0px, yang juga mengandung div yang digunakan sebagai header tetap. Wadah tabel menyisakan cukup ruang di bagian atas untuk memungkinkan tajuk yang benar-benar diposisikan, dan tabel dengan bilah gulir muncul seperti yang Anda harapkan.

Kode di atas menggunakan kelas yang diposisikan untuk benar-benar memposisikan tabel (Saya menggunakannya dalam dialog gaya popup) tetapi Anda dapat menggunakannya dalam aliran dokumen juga dengan menghapus positioned kelas dari wadah.

Tapi ...

Itu tidak sempurna. Firefox menolak untuk membuat baris tajuk 0px (setidaknya saya tidak menemukan cara apa pun) tetapi dengan keras kepala mempertahankannya pada minimum 4px ... Ini bukan masalah besar, tetapi tergantung pada gaya Anda, itu akan mengacaukan perbatasan Anda dll.

Tabel ini juga menggunakan pendekatan kolom palsu di mana warna latar belakang wadah itu sendiri digunakan sebagai latar belakang untuk header header, yang transparan.

Ringkasan

Semua dalam semua mungkin ada masalah styling yang tergantung pada kebutuhan Anda, terutama perbatasan atau latar belakang yang rumit. Mungkin juga ada masalah dengan kemampuan komputasi, saya belum memeriksanya di berbagai peramban (tolong beri komentar dengan pengalaman Anda jika Anda mencobanya), tetapi saya tidak menemukan yang seperti itu jadi saya pikir pantas untuk diposkan pokoknya ...


Jika Anda mengecilkan lebar jendela hingga menggulir secara horizontal menendang, maka tajuk tidak menggulir secara horizontal dengan tubuh. Menisik.
dlaliberte

@ dlaliberte - Ya, karena header dan tabel sebenarnya adalah dua elemen berbeda yang Anda dapat, tentu saja, menjadi aneh. Tapi contoh saya tidak memungkinkan overflow pada kolom tabel dan header biasanya lebih mudah dikendalikan daripada konten tabel. Yang mengatakan, jika Anda menyebabkan header "meluap" jika akan menonjol di sebelah kanan tabel dan terlihat sangat rusak. Anda dapat memperbaikinya dengan menetapkan lebar minimum di atas meja, memaksanya untuk meluap halaman juga ... Tapi ini adalah peretasan sehingga tidak akan pernah sempurna ...
Jonas Schubert Erlandsson

1
Layak menunjukkan bahwa ini membutuhkan desain di mana tabel ketinggian tetap dapat ditentukan.
Cheekysoft

1
@Cheekysoft - Tidak, tabel dan konten baris dapat mengalir dengan bebas. Wadah, dalam contoh saya <section>elemen, perlu dibatasi ketinggian hanya untuk memaksanya meluap dan menunjukkan gulir. Tata letak apa pun yang akan membuat wadah meluap akan berfungsi. Jika Anda menemukan suatu kasus di mana itu tidak silakan memposting tautan ke biola.
Jonas Schubert Erlandsson

Nilai kode keras padding-topjuga berarti bahwa jika teks judul tabel berada di lebih dari satu baris itu akan muncul di atas sel tabel. Kasihan, karena ini berfungsi seperti pesona sebagian besar waktu. Benar-benar baik trick dengan divdi thuntuk berkeliling kolom ukuran isu yang paling solusi lain memiliki.
Bernhard Hofmann

19

Semua upaya untuk menyelesaikan ini dari luar spesifikasi CSS adalah bayangan pucat dari apa yang sebenarnya kita inginkan: Pengiriman pada janji yang tersirat dari THEAD.

Masalah beku-header-untuk-tabel ini telah menjadi luka terbuka dalam HTML / CSS untuk waktu yang lama.

Di dunia yang sempurna, akan ada solusi murni-CSS untuk masalah ini. Sayangnya, sepertinya tidak ada yang bagus.

Standar-diskusi yang relevan tentang topik ini meliputi:

UPDATE : Firefox dikirim position:stickydalam versi 32. Semua orang menang!


Ini akan menjadi luar biasa memiliki kolom rubah dengan cara yang sama
Csaba Toth

4
Kembali. Firefox dan posisi: lengket, tidak berfungsi untuk tajuk tabel: bugzilla.mozilla.org/show_bug.cgi?id=925259#c8 ... Patch untuk bug itu secara eksplisit menyatakan: "Kami saat ini tidak mendukung penentuan posisi relatif elemen tabel bagian dalam, jadi kami mengecualikan mereka dari posisi lengket juga. "
Jonas Schubert Erlandsson

2
Ini bekerja di semua browser sekarang: thead th { position: sticky; top: 0; }. Bisakah kita memperbarui jawaban ini untuk menyatakan ini dengan jelas?
Daniel Waltrip

1
@DanielWaltrip semua browser? stackoverflow.com/a/37646284/3640407 Masih ada lebih banyak MSIE daripada Edges
edc65

Titik adil. Ini didukung untuk 86% pengguna web global, menurut caniuse.com/#search=position%3Asticky
Daniel Waltrip

14

Berikut ini adalah plugin jQuery untuk header tabel tetap. Ini memungkinkan seluruh halaman untuk menggulir, membekukan header ketika mencapai bagian atas. Ini berfungsi baik dengan tabel Bootstrap Twitter .

Repositori GitHub: https://github.com/oma/table-fixed-header

Itu tidak menggulir hanya konten tabel. Lihatlah alat-alat lain untuk itu, sebagai salah satu dari jawaban lain ini. Anda memutuskan yang paling cocok dengan kasus Anda.


1
Nyebelin - tautan contoh sudah mati. "Ups! Denne siden ble ikke funnet ..." Berharap kodenya disisipkan di sini.
JosephK

ya ... maaf soal itu. menghapus tautan. Proyek tidak lagi dipertahankan
oma

Tidak perlu khawatir - saya mencoba beberapa solusi yang sudah dibuat sebelumnya - tidak ada yang bekerja dengan tabel flex-col-width yang melebihi lebar layar. Saya akhirnya menulis solusi saya sendiri.
JosephK

9

Sebagian besar solusi yang diposting di sini memerlukan jQuery. Jika Anda mencari solusi kerangka kerja independen, coba Grid: http://www.matts411.com/post/grid/

Di-host di Github di sini: https://github.com/mmurph211/Grid

Tidak hanya mendukung header tetap, juga mendukung kolom dan footer kiri tetap, antara lain.


Ini sangat rapi jika memenuhi kebutuhan Anda, saya hanya bermain dengannya hari ini. Sayangnya, ini agak kotak persegi panjang (sesuai namanya, sebenarnya) dan bukan tabel sebenarnya dengan tinggi baris disesuaikan dengan konten. Dan mendandani setiap baris tampak sulit. Saya tidak dapat membuat tabel bergaris zebra tetapi tidak berusaha sangat keras karena kebutuhan saya sebenarnya lebih kompleks. Bagaimanapun, kerja bagus.
mplwork

1
Hei aku kenal kamu! Kami sepertinya telah menulis omong kosong yang sangat mirip ( github.com/mkoryak/floatThead ) - Misha
mkoryak

9

Properti CSS position: sticky memiliki dukungan besar di sebagian besar browser modern (Saya memiliki masalah dengan Edge, lihat di bawah).

Ini memungkinkan kami memecahkan masalah header tetap dengan mudah:

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

Safari membutuhkan vendor awalan: -webkit-sticky.

Untuk Firefox, saya harus menambahkan min-height: 0satu elemen induk. Saya lupa persis mengapa ini diperlukan.

Paling disayangkan, implementasi Microsoft Edge tampaknya hanya semi-kerja. Setidaknya, saya memiliki beberapa sel tabel yang berkedip dan tidak sejajar dalam pengujian saya. Tabel itu masih bisa digunakan, tetapi memiliki masalah estetika yang signifikan.


Menggunakan position: sticky;dengan tabel di dalam div yang memiliki overflow: scroll;, overflow-x: scroll;atau overflow-y: scroll;. tampaknya menjadi solusi terbaik dan paling sederhana untuk header dan kolom tabel tetap di browser modern. Jawaban ini perlu dipilih ke atas.
Aberrant

Sederhana tapi efektif. Itu yang saya cari. Terima kasih.
Catbuilts

6

Tabel gulir CSS murni yang lebih halus

Semua solusi CSS murni yang saya lihat sejauh ini - pintar meskipun mungkin - tidak memiliki tingkat poles tertentu, atau tidak berfungsi dengan benar dalam beberapa situasi. Jadi, saya memutuskan untuk membuat ...

Fitur:

  • Ini murni CSS, jadi tidak diperlukan jQuery (atau kode JavaScript apa pun, dalam hal ini)
  • Anda dapat mengatur lebar tabel menjadi persen (alias "cairan") atau nilai tetap, atau membiarkan konten menentukan lebarnya (alias "otomatis")
  • Lebar kolom juga bisa berubah-ubah, tetap, atau otomatis.
  • Kolom tidak akan pernah menjadi tidak selaras dengan tajuk karena pengguliran horizontal (masalah yang terjadi pada setiap solusi berbasis CSS lainnya yang pernah saya lihat yang tidak memerlukan lebar tetap).
  • Kompatibel dengan semua browser desktop populer, termasuk Internet Explorer kembali ke versi 8
  • Bersih, penampilan dipoles; tidak ada celah 1-piksel yang tampak ceroboh atau batas yang tidak selaras; terlihat sama di semua browser

Berikut adalah beberapa biola yang menunjukkan opsi lebar dan cairan:

  • Lebar dan Tinggi Cairan (menyesuaikan dengan ukuran layar): jsFiddle (Perhatikan bahwa bilah gulir hanya muncul bila diperlukan dalam konfigurasi ini, jadi Anda mungkin harus mengecilkan bingkai untuk melihatnya)

  • Lebar Otomatis, Tinggi Tetap (lebih mudah diintegrasikan dengan konten lain): jsFiddle

Lebar Otomatis, Konfigurasi Tinggi Tetap mungkin memiliki lebih banyak kasus penggunaan, jadi saya akan memposting kode di bawah ini.

/* 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]-->

Metode yang saya gunakan untuk membekukan baris tajuk mirip dengan d-Pixie, jadi lihat postingnya untuk penjelasan. Ada banyak bug dan batasan dengan teknik yang hanya bisa diperbaiki dengan tumpukan CSS tambahan dan satu atau dua wadah div tambahan.


Jawaban ini kurang dihargai! Saya menghabiskan waktu berhari-hari untuk mencoba solusi lain untuk kasus saya yang sangat menyebalkan. Setiap satu dari mereka gagal untuk tetap selaras dengan satu atau lain cara. Ini akhirnya berhasil! Kelihatannya terlalu rumit pada awalnya, tetapi begitu Anda terbiasa, luar biasa. Anda dapat menghapus sedikit barang yang tidak Anda butuhkan pada akhirnya, ketika tidak menggunakan lebar cairan, dll.
Justin Sane

1
@JustinSane Senang Anda menyukainya! Saya kira kurangnya penghargaan ini disebabkan oleh fakta bahwa ia berbagi halaman dengan solusi luar biasa Maximilian Hils . Jika Anda tidak menentang untuk menggunakan sedikit JS, Anda harus memeriksanya.
DoctorDestructo

Sialan, itu adalah solusi hampir sempurna memang. Saya menggunakan jQuery, mencoba membuatnya bekerja dengan itu sebelum saya menemukan milik Anda (melalui komentar Anda ke pertanyaan lain). Tidak memikirkan pendengar gulir dan menerjemahkan ... Ya, mereka mengatakan dibutuhkan seorang jenius untuk menghasilkan solusi sederhana ..;) Saya menyelesaikan proyek dan bekerja dengan baik tanpa js, tapi saya akan menyimpan ini dalam pikiran untuk masa depan. Tetap saja, topi untukmu karena luar biasa!
Justin Sane

Masalah kecil tetapi jika Anda menggunakan Warna Sistem yang berbeda, Anda dapat melihat warna teks belum ditetapkan untuk apa pun kecuali header tetapi latar belakang tabel memiliki warna latar belakang yang eksplisit. Saya memiliki teks kuning pada latar belakang putih dan abu-abu untuk tabel ini.
Matt Arnold

1
@MattArnold Diperbaiki. Terima kasih atas tipnya!
DoctorDestructo

5

Plugin jQuery sederhana

Ini adalah variasi pada solusi Mahes. Anda bisa menyebutnya seperti$('table#foo').scrollableTable();

Idenya adalah:

  • Membagi theaddan tbodymenjadi tableelemen yang terpisah
  • Buat lebar sel mereka cocok lagi
  • Bungkus yang kedua tabledalam adiv.scrollable
  • Gunakan CSS untuk div.scrollablebenar - benar menggulir

CSS dapat berupa:

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

Peringatan

  • Jelas, memisahkan tabel-tabel ini membuat markup kurang semantik. Saya tidak yakin apa efeknya terhadap aksesibilitas.
  • Plugin ini tidak berurusan dengan footer, banyak header, dll.
  • Saya hanya mengujinya di Chrome versi 20.

Yang mengatakan, itu berfungsi untuk keperluan saya dan Anda bebas untuk mengambil dan memodifikasinya.

Ini pluginnya:

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
Skrip yang bagus, ini bekerja paling baik di lingkungan saya. Saya memperpanjang skrip Anda dengan dukungan footer tetap, periksa posting saya di bawah ini.
gitaarik

4

:)

Tidak terlalu bersih, tetapi solusi HTML / CSS murni.

table {
    overflow-x:scroll;
}

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

Diperbarui untuk contoh IE8 + JSFiddle


2
Solusi yang bagus, hanya untuk menyebutkan, bahwa sel-sel ini melayang dan sehingga menurut konten dapat memiliki ketinggian yang berbeda, itu terlihat jika Anda menetapkan batasnya: jsfiddle.net/ZdeEH/15
Stano

3

Dukungan untuk footer tetap

Saya memperluas fungsi Nathan untuk juga mendukung footer tetap dan tinggi maksimum. Selain itu, fungsi akan mengatur CSS itu sendiri, dan Anda hanya perlu mendukung lebar.

Pemakaian:

Tinggi tetap:

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

Tinggi maksimum (jika peramban mendukung opsi 'tinggi-tinggi' CSS):

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

Naskah:

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

Entah bagaimana akhirnya saya berhasil dengan Position:Stickybaik dalam kasus saya:

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
Ini adalah solusi terbersih yang saya lihat sejauh ini. caniuse menunjukkan bahwa pada 5/2/2020, posisi yang tidak diperbaiki: sticky menikmati 90,06% dukungan global. Jadi solusi ini bekerja dengan baik di semua browser modern.
AlienKevin

2

Dua div, satu untuk header, satu untuk data. Buat div data dapat digulir, dan gunakan JavaScript untuk mengatur lebar kolom di header menjadi sama dengan lebar dalam data. Saya pikir lebar kolom data harus diperbaiki daripada dinamis.


3
Jika Anda peduli dengan aksesibilitas, ini gagal.
epascarello

1
kembali aksesibilitas, mungkin kita bisa mengganti penggunaan divs dengan gaya di <thead> dan <tbody> ??
Cheekysoft

1

Saya menyadari pertanyaannya memungkinkan JavaScript, tetapi di sini ada solusi CSS murni yang saya upayakan yang juga memungkinkan tabel diperluas secara horizontal. Itu diuji dengan Internet Explorer 10 dan browser Chrome dan Firefox terbaru. Tautan ke jsFiddle ada di bawah.

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>

Dan 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

Bagi mereka yang mencoba solusi bagus yang diberikan oleh Maximilian Hils, dan tidak berhasil membuatnya bekerja dengan Internet Explorer, saya memiliki masalah yang sama (Internet Explorer 11) dan mencari tahu apa masalahnya.

Di Internet Explorer 11 transformasi gaya (setidaknya dengan terjemahan) tidak berfungsi <THEAD>. Saya memecahkan ini dengan menerapkan gaya ke semua <TH>dalam satu lingkaran. Itu berhasil. Kode JavaScript saya terlihat seperti ini:

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;
  }
});

Dalam kasus saya, tabelnya adalah GridView di ASP.NET. Pertama saya pikir itu karena tidak ada <THEAD>, tetapi bahkan ketika saya memaksakan untuk memilikinya, itu tidak berhasil. Kemudian saya menemukan apa yang saya tulis di atas.

Ini adalah solusi yang sangat bagus dan sederhana. Di Chrome itu sempurna, di Firefox sedikit tersentak-sentak, dan di Internet Explorer bahkan lebih tersentak-sentak. Namun semuanya merupakan solusi yang bagus.


0

Saya berharap saya telah menemukan solusi @ Mark sebelumnya, tetapi saya pergi dan menulis sendiri sebelum saya melihat pertanyaan SO ini ...

Mine adalah plugin jQuery yang sangat ringan yang mendukung header tetap, footer, spanning kolom (colspan), pengubahan ukuran, pengguliran horizontal, dan sejumlah baris pilihan untuk ditampilkan sebelum pengguliran dimulai.

jQuery.scrollTableBody (GitHub)

Selama Anda memiliki meja dengan tepat <thead>, <tbody>dan (opsional) <tfoot>, semua yang perlu Anda lakukan adalah ini:

$('table').scrollTableBody();

0

Saya menemukan solusi ini - memindahkan baris tajuk dalam tabel di atas tabel dengan data:

<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>


berfungsi untuk tabel kecil, tetapi jika Anda memiliki pengguliran horizontal solusi ini tidak akan berfungsi.
crh225

Ini juga tidak akan berfungsi dengan baik karena kolom tabel tidak akan sejajar. Di sini Anda memaksakan lebar untuk td tetapi kita tidak boleh melakukan ...
Ziggler

0

Dengan menerapkan plugin jQuery StickyTableHeaders ke tabel, header kolom akan menempel di bagian atas viewport saat Anda menggulir ke bawah.

Contoh:

$(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

Saya suka jawaban Maximillian Hils tetapi saya punya beberapa masalah:

  1. Transformasi tidak bekerja di Edge atau IE kecuali Anda menerapkannya ke th
  2. header berkedip saat bergulir di Edge dan IE
  3. meja saya dimuat menggunakan ajax, jadi saya ingin melampirkan ke acara gulir jendela daripada acara gulir pembungkus itu

Untuk menghilangkan flicker, saya menggunakan batas waktu untuk menunggu sampai pengguna selesai menggulir, kemudian saya menerapkan transformasi - sehingga header tidak terlihat selama pengguliran.

Saya juga menulis ini menggunakan jQuery, salah satu keuntungannya adalah bahwa jQuery harus menangani awalan vendor untuk Anda

    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);

Meja dibungkus dengan kelas table-container-fixed.

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

Saya mengatur border-collapse untuk memisahkan karena jika tidak, kami kehilangan perbatasan selama terjemahan, dan saya menghapus perbatasan di atas meja untuk menghentikan konten yang muncul tepat di atas sel tempat perbatasan itu selama pengguliran.

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

Saya membuat thlatar belakang putih untuk menutupi sel-sel di bawahnya, dan saya menambahkan perbatasan yang cocok dengan perbatasan tabel - yang ditata menggunakan Bootstrap dan digulirkan keluar dari pandangan.

 .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

Gunakan versi terbaru jQuery, dan sertakan kode JavaScript berikut.

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

1
Ini sepertinya tidak berhasil. Mungkin Anda bisa mengklarifikasi apa yang Anda ingin kami lakukan?
Chris

1
Apa div? Kita berbicara tentang tabel di sini
isapir

0

Ini bukan solusi tepat untuk baris tajuk tetap, tapi saya telah membuat metode yang agak cerdik mengulangi baris tajuk di seluruh tabel panjang, namun tetap menjaga kemampuan untuk menyortir.

Opsi kecil yang rapi ini membutuhkan plugin jQuerytablesorter . Begini cara kerjanya:

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>

Jelas, meja saya memiliki lebih banyak baris daripada ini. 193 tepatnya, tetapi Anda bisa melihat di mana baris tajuk berulang. Baris header berulang diatur oleh fungsi ini:

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

Banyak orang sepertinya mencari jawaban ini. Saya menemukannya terkubur dalam jawaban untuk pertanyaan lain di sini: Menyinkronkan lebar kolom antara tabel dalam dua bingkai yang berbeda, dll

Dari lusinan metode yang saya coba ini adalah satu-satunya metode yang saya temukan yang berfungsi andal untuk memungkinkan Anda memiliki tabel di bawah dengan tabel header memiliki lebar yang sama.

Inilah cara saya melakukannya, pertama saya memperbaiki jsfiddle di atas untuk membuat fungsi ini, yang bekerja pada keduanya tddan th(dalam kasus yang membuat orang lain yang menggunakan thuntuk styling baris header mereka).

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());
            });
        }

Selanjutnya, Anda perlu membuat dua tabel, CATATAN tabel header harus memiliki tambahan TDuntuk meninggalkan ruang di tabel atas untuk scrollbar, seperti ini:

 <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>

Kemudian lakukan sesuatu seperti:

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

Ini adalah satu-satunya solusi yang saya temukan di Stack Overflow yang berhasil dari banyak pertanyaan serupa yang telah diposting, yang berfungsi dalam semua kasus saya.

Misalnya, saya mencoba plugin jQuery stickytables yang tidak berfungsi dengan durandal, dan proyek Google Code di sini https://code.google.com/p/js-scroll-table-header/issues/detail?id=2

Solusi lain yang melibatkan kloning tabel, memiliki kinerja yang buruk, atau payah dan tidak berfungsi dalam semua kasus.

Tidak perlu untuk solusi yang terlalu rumit ini. Buat saja dua tabel seperti contoh di bawah ini dan panggil fungsi setHeaderTableWidth seperti dijelaskan di sini dan boom, Anda selesai .

Jika ini tidak berhasil untuk Anda, Anda mungkin bermain dengan properti ukuran kotak CSS Anda dan Anda harus mengaturnya dengan benar. Sangat mudah untuk mengacaukan konten CSS Anda secara tidak sengaja. Ada banyak hal yang bisa salah, jadi berhati-hatilah. Pendekatan ini bekerja untuk saya .


0

Inilah solusi yang akhirnya kami kerjakan (untuk menangani beberapa kasus tepi dan versi Internet Explorer yang lebih lama, kami akhirnya juga memudar bilah judul pada gulir kemudian memudar kembali ketika menggulir berakhir, tetapi di browser Firefox dan WebKit solusi ini hanya berfungsi Dengan asumsi border-collapse: collapse.

Kunci dari solusi ini adalah bahwa sekali Anda menerapkan border-collapse , CSS mengubah pekerjaan pada header, jadi itu hanya masalah mencegat acara gulir dan mengatur transformasi dengan benar. Anda tidak perlu menduplikasi apa pun. Pendek dari perilaku ini diterapkan dengan benar di browser, sulit untuk membayangkan solusi yang lebih ringan.

JSFiddle: http://jsfiddle.net/podperson/tH9VU/2/

Diimplementasikan sebagai plugin jQuery sederhana. Anda cukup membuat lengket thead dengan panggilan seperti $ ('thead'). Sticky (), dan mereka akan berkeliaran. Ini berfungsi untuk beberapa tabel pada halaman dan bagian kepala di tengah meja besar.

$.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();

solusi yang bagus tetapi bagaimana Anda memasukkan batas kolom antara kolom (keduanya dalam tajuk tetap, disejajarkan dengan data td)?
user5249203

Saya tidak yakin saya mengerti masalah Anda. border-collapse tidak mencegah Anda menggunakan perbatasan, margin, dll., itu hanya menghilangkan metrik tabel voodoo dahulu kala.
podperson

1
Tambahkan border: 2px solid red;ke th, gulir, dan Anda akan melihat masalahnya. Saya datang dengan solusi yang lebih mendasar ini sendiri: jsfiddle.net/x6pLcor9/19
calandoa

Tambahkan batas dimensi yang sama ke td dan tidak ada masalah. Saya tidak mengerti maksud Anda. Versi Anda jauh lebih bersih dan tidak menggunakan jQuery jadi saya pasti akan menggunakan sesuatu yang lebih seperti itu hari ini. (Meskipun, terus terang, saya tidak berpikir saya akan menggunakan meja sama sekali hari ini.)
podperson

0

Ini jawaban yang lebih baik untuk jawaban yang diposting oleh Maximilian Hils .

Yang ini bekerja di Internet Explorer 11 tanpa berkedip sama sekali:

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

Saya mengembangkan plug-in jQuery ringan dan sederhana untuk mengubah tabel HTML yang diformat dengan baik menjadi tabel yang dapat digulir dengan header dan kolom tabel tetap.

Plugin berfungsi dengan baik untuk mencocokkan penempatan pixel-ke-pixel bagian tetap dengan bagian yang dapat digulir. Selain itu, Anda juga dapat membekukan jumlah kolom yang akan selalu terlihat saat menggulir secara horizontal.

Demo & Dokumentasi: http://meetselva.github.io/fixed-table-rows-cols/

Repositori GitHub: https://github.com/meetselva/fixed-table-rows-cols

Di bawah ini adalah penggunaan tabel sederhana dengan header tetap,

$(<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'}
              ]
});

Apa itu "tabel HTML dengan baik" ?
Peter Mortensen

@PeterMortensen Seharusnya "HTML terformat dengan baik". Diedit, terima kasih.
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

Tambahan untuk jawaban @Daniel Waltrip. Tabel perlu dilampirkan dengan div position: relativeuntuk bekerja dengannya position:sticky. Jadi saya ingin memposting kode sampel saya di sini.

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>

Demo

masukkan deskripsi gambar di sini

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.