HTML-таблиця з фіксованими заголовками?


231

Чи існує метод перехресного браузера CSS / JavaScript для відображення довгої таблиці HTML таким чином, щоб заголовки стовпців залишалися нерухомими на екрані і не прокручувались з тілом таблиці. Подумайте про ефект «заморожування панелей» у Microsoft Excel.

Я хочу мати можливість прокручувати вміст таблиці, але завжди мати можливість бачити заголовки стовпців у верхній частині.


3
Спробуйте це: Чиста таблиця прокрутки CSS з фіксованим заголовком EDIT : ця повинна працювати в Internet Explorer 7, як видно з прикладу : Прокрутка HTML таблиці з фіксованим заголовком EDIT 2: Я знайшов пару додаткових посилань, які можуть бути корисні: - Дурне фіксований заголовок - плагін jQuery з деякими обмеженнями. - [Заголовки виправлених таблиць] ( cross-browser.com/x/examp
gcores

Я зіткнувся з багатьма рішеннями, які, як правило, працюють, але жодне з них не працювало прокручуючи діл. Я маю на увазі, ваша таблиця знаходиться в розділюваному розділювальному розділі, і ви все ще хочете, щоб заголовок таблиці все ще знаходився в ньому. Я це вирішив і поділюсь тут рішенням .
Йоге

9
У 2018 році, всі браузери можуть використовувати наступне просте рішення: thead th { position: sticky; top: 0; }. Сафарі потребує приставки постачальника:-webkit-sticky
Даніель Уолтріп

1
@DanielWaltrip вам слід додати цю відповідь, щоб вона змогла підняти голосування на перше місце - всі інші відповіді зайві з позиції: липкі краще підтримують сьогодні
Пітер Керр

Відповіді:


88

Я деякий час шукав рішення для цього і виявив, що більшість відповідей не працюють або не підходять для моєї ситуації, тому я написав просте рішення з jQuery.

Це контур рішення:

  1. Клоніруйте таблицю, яка повинна мати фіксований заголовок, і кладіть клоновану копію поверх оригіналу.
  2. Вийміть корпус столу з верхнього столу.
  3. Видаліть заголовок таблиці з нижньої таблиці.
  4. Відрегулюйте ширину стовпчика. (Ми відстежуємо початкові ширини стовпців)

Нижче наведено код демо-версії.

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>

Це рішення працює в Chrome та IE. Оскільки він заснований на jQuery, це також має працювати в інших підтримуваних jQuery браузерах.


4
і як ми можемо вирішити проблему, коли вміст більший за ширину?
Maertz

1
@tetra td {max-width: 30px; } це дозволить розробнику контролювати спосіб відображення рядків.
Любен Тодоров

Але що робити, якщо вміст у комірці заголовка довший, ніж у клітинках td? Я спробував це в IE7, а width () все ламає. IE8 та IE9 добре працюють, хоча ...
JustAMartin

4
На жаль, якщо вам потрібне ідеальне вирівнювання пікселів стовпців, це не працює: jsbin.com/elekiq/1 ( вихідний код ). Видно, що деякі заголовки зміщені з місця, де вони повинні бути, лише незначно. Ефект є більш очевидним, якщо ви використовуєте фони: jsbin.com/elekiq/2 ( вихідний код ). (Я працював по цих же лініях, наткнувся на це в своєму коді, знайшов свій і подумав "О, мені цікаво, чи він вирішив це для мене!". На жаль, ні. ширина клітин…
TJ Crowder

Здається, це не працює з горизонтальною прокруткою - це створює заголовок, але він виходить за межі області прокрутки (помітно) і не прокручується зі змістом.
Crash

183

Це можна чітко вирішити в чотирьох рядках коду.

Якщо ви дбаєте лише про сучасні браузери, виправити заголовок можна досягти набагато простіше за допомогою перетворень CSS. Звучить дивно, але чудово працює:

  • HTML і CSS залишаються такими, які є.
  • Відсутність зовнішніх залежностей JavaScript.
  • Чотири рядки коду.
  • Працює для всіх конфігурацій (макет таблиці: фіксований тощо).
document.getElementById("wrap").addEventListener("scroll", function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

Підтримка перетворень CSS широко доступна за винятком Internet Explorer 8-

Ось повний приклад для довідки:


8
Треба сказати, що, незважаючи на попередній коментар, це найбільш близьке до ідеального рішення, яке я бачив. Навіть горизонтальна прокрутка ідеальна (краще, ніж моє власне рішення). Ось приклад із межами (ви не можете використовувати границю-згортання) та смугою
DoctorDestructo,

11
З'ясувалося, він працює, але повинен застосувати перетворення до th / td, а не thead.
рудоволосий

5
@AlexAlexeev, ваше рішення дивовижне. Дякую. Я помітив, що в отриманому фіксованому заголовку немає граничних ліній, які відрізняють стовпці. Стиль CSS за замовчуванням втрачено. Навіть коли я включаю це ... $(this).addClass('border')змінює решту таблиці, містить шрифти, розмір, колір, які я передаю в клас кордону. Але, не додає рядки до фіксованого заголовка.
Вдячний

5
@ user5249203 Я знаю, що ви запитували кілька місяців тому, але у мене була така ж проблема, і це було пов’язано з крахом кордону: див. це: stackoverflow.com/questions/33777751/… .
archz

6
Це не працює ні в одній версії IE, ні в Edge. Ось версія, яка базується на коментарі @ redhead jsfiddle.net/n6o8ocwb/2
пограбувати

58

Я щойно завершив збирання плагіна jQuery, який візьме дійсну єдину таблицю з використанням дійсного HTML (повинні мати thead та tbody) і виведе таблицю з фіксованими заголовками, необов’язковий фіксований колонтитул, який може бути клонованим заголовком або будь-яким вміст, який ви вибрали (пагинація тощо). Якщо ви хочете скористатися більшими моніторами, він також змінить розмір таблиці при зміні розміру браузера. Ще одна додана функція - це можливість прокручувати бік, якщо стовпці таблиць не можуть усі вміститись у вигляд.

http://fixedheadertable.com/

на github: http://markmalek.github.com/Fixed-Header-Table/

Налаштувати це надзвичайно просто, і ви можете створити для нього свої власні стилі. Він також використовує закруглені кути у всіх браузерах. Майте на увазі, що я щойно випустив це, тому технічно це все ще бета-версія, і є дуже мало незначних проблем, які я прасую.

Він працює в Internet Explorer 7, Internet Explorer 8, Safari, Firefox та Chrome.


Дякую! Новий випуск я додаю пізніше сьогодні, коли повертаюся з роботи додому. Ось посилання на мій запис у щоденнику з тим, що я додаю: fixheadertable.mmalek.com/2009/10/07/…
Марк

Дякую за це. Мені відомо, що це питання вже понад рік, але навіть ризикуючи розпалити осілий мул, я хотів би сказати вам, що ваша робота цінується
сова

У вашій демонстрації ширини вимкнено в ie6 :-( заголовок таблиці та тіло не вирівняні.
Cheekysoft

4
Остання версія не працює в IE6. Я більше не підтримую IE6.
Марк

чудова робота Марк - на жаль, є деякі проблеми з прокруткою фіксованого заголовка та стовпця на мобільних пристроях (iPad, планшет Android) - коли я прокручую вміст, то ті фіксовані частини не прокручуються - коли я перестаю прокручувати та натискаю один раз таблицю , нерухомі частини «стрибають» у потрібні положення - чи є простий спосіб це виправити?
Окізб

23

Я також створив плагін, який вирішує цю проблему. Мій проект - jQuery.floatThead існує вже більше 4 років і дуже зрілий.

Він не вимагає зовнішніх стилів і не очікує, що ваш стіл буде стилізований певним чином. Він підтримує Internet Explorer9 + та Firefox / Chrome.

Наразі (2018-05) він має:

405 комітетів і 998 зірок на GitHub


Багато (не всі) відповідей тут - це швидкі хаки, які, можливо, вирішили проблему, яку мала одна людина, але працюватимуть не для кожної таблиці.

Деякі з інших плагінів є старими і, ймовірно, чудово працюють із Internet Explorer, але вони працюватимуть на Firefox та Chrome.


1
Відмінний плагін, підтримує вкладені таблиці та компенсації.
Михай Алекс

2
Чудово. Дуже дякую. Плагін добре працював у Firefox 45.2, Chromium 51 та IE 11. Крім того, він не заважає багатьом кодам JS та jQuery, побудованим на одній сторінці.
Aldo Paradiso

Дякую. Я радий повідомити, що проект отримує близько 1 повідомлення про помилку кожні 4 місяці. Я не вношу багато переломних змін. Це досить солідно і працює.
mkoryak

20

TL; DR

Якщо ви орієнтовані на сучасні веб-переглядачі та не маєте екстравагантних стильових потреб: http://jsfiddle.net/dPixie/byB9d/3/ ... Хоча велика чотири версія є дуже солодкою, але ця версія обробляє ширину рідини набагато краще.

Гарні новини всім!

З розвитком HTML5 та CSS3 це стає можливим, принаймні, для сучасних браузерів. Трохи хакітську реалізацію, яку я придумав, можна знайти тут: http://jsfiddle.net/dPixie/byB9d/3/ . Я перевірив його в FX 25, Chrome 31 і IE 10 ...

Відповідний HTML (хоча вставте HTML5-тип вгорі документа):

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>

Але як?!

Простіше кажучи, у вас є заголовок таблиці, який ви візуально приховуєте, зробивши його 0px високим, який також містить знаки, що використовуються як фіксований заголовок. Контейнер таблиці залишає достатньо місця у верхній частині, щоб забезпечити абсолютно розміщений заголовок, а таблиця з смугами прокрутки з’явиться так, як ви очікували.

У наведеному вище коді клас позиціонування використовується для абсолютного розміщення таблиці (я використовую її в діалоговому вікні стилю спливаючого вікна), але ви можете використовувати її і в потоці документа, також видаляючи positionedклас з контейнера.

Але ...

Це не ідеально. Firefox відмовляється складати заголовок ряду 0px (принаймні, я не знайшов жодного способу), але вперто тримає його як мінімум 4px ... Це не величезна проблема, але залежно від вашої стилістики він зіпсується з вашими межами тощо.

У таблиці також використовується підхід зі штучним стовпцем, де колір фону самого контейнера використовується як фон для прозорих заголовків, які прозорі.

Підсумок

Загалом можуть виникнути проблеми стилізації залежно від ваших вимог, особливо рамки або складні фони. Можуть також виникнути проблеми з обчислюваністю, я ще не перевіряв її в широкому спектрі браузерів (будь ласка, прокоментуйте свої враження, якщо ви спробуйте), але я не знайшов нічого подібного, тому я подумав, що варто опублікувати все одно ...


Якщо ви зменшите ширину вікна, поки не запуститься горизонтальна прокрутка, то заголовок не прокручується горизонтально тілом. Дарн.
dlaliberte

@dlaliberte - Ну, оскільки заголовок і таблиця насправді є двома різними елементами, ти, звичайно, можеш потрапити в дивовижність. Але мій приклад не дозволяє переповнювати стовпці таблиці, а заголовки, як правило, простіше контролювати, ніж вміст таблиці. Це означає, що якщо ви змусите заголовок "переповнювати", якщо він буде стирчати праворуч від таблиці і виглядати сильно розбитим. Ви можете це виправити, встановивши на столі мінімальну ширину, змусивши її також переповнювати сторінку ... Але це злом, так що він ніколи не буде ідеальним ...
Йонас Шуберт Ерландссон

1
Варто зазначити, що для цього потрібна конструкція, де можна вказати таблицю з фіксованою висотою.
Cheekysoft

1
@Cheekysoft - Ні, вміст таблиці та рядків може вільно перетікати. У моєму прикладі <section>елемент повинен бути обмежений по висоті, щоб змусити його переповнюватись і показувати прокрутку. Будь-який макет, який зробить контейнер переповненим, спрацює. Якщо ви знайдете випадок, коли він не надсилає посилання на загадку.
Йонас Шуберт Ерландссон

Значення із твердим кодом padding-topтакож означає, що якщо текст заголовка таблиці міститься у кількох рядках, він з’явиться вгорі комірок таблиці. Шкода, адже це працює як шарм більшість часу. Дійсно хороший трюк з divв thобійти питання колонка проклейки більшості інших рішень є.
Бернхард Хофманн

19

Усі спроби вирішити це за межами специфікації CSS - це бліді тіні того, що ми насправді хочемо: Постачання за прихованою обіцянкою THEAD.

Ця проблема із замороженими заголовками для столу вже давно є відкритою раною в HTML / CSS.

У ідеальному світі для цієї проблеми було б вирішення чистого CSS. На жаль, здається, що це не є гарним.

Відповідні стандарти-дискусії на цю тему включають:

ОНОВЛЕННЯ : Firefox поставляється position:stickyу версії 32. Усі виграють!


Було б чудово, щоб так само, як у фольгованих стовпчиках, стовпчики
Csaba Toth,

4
Re. Firefox та позиція: липкий, він не працює для заголовків таблиць: bugzilla.mozilla.org/show_bug.cgi?id=925259#c8 ... Патч для цієї помилки прямо говорить: "Наразі ми не підтримуємо відносне позиціонування внутрішніх елементів таблиці, тому ми також виключаємо їх із липкого розміщення ".
Йонас Шуберт Ерландссон

2
Це працює у всіх браузерах прямо зараз: thead th { position: sticky; top: 0; }. Чи можемо ми оновити цю відповідь, щоб чітко сказати про це?
Даніель Уолтріп

1
@DanielWaltrip усі браузери? stackoverflow.com/a/37646284/3640407 Є ще більше MSIE, ніж Edges
edc65

Справедливий пункт. Він підтримується для 86% глобальних користувачів Інтернету, згідно з даними caniuse.com/#search=position%3Asticky
Daniel Waltrip

14

Ось плагін jQuery для фіксованих заголовків таблиць. Це дозволяє прокручувати всю сторінку, заморожуючи заголовок, коли він досягне вершини. Він добре працює з таблицями Bootstrap Twitter .

Репозиторій GitHub: https://github.com/oma/table-fixed-header

Це робить не прокручує лише вміст таблиці. Подивіться на інші інструменти для цього, як на одну з цих інших відповідей. Ви вирішуєте, що найкраще відповідає вашій справі.


1
Баммер - приклад посилання мертвий. "На жаль! Denne siden ble ikke funnet ..." Бажаний тут код був вставлений.
JosephK

так ... вибачте з цього приводу. видалено посилання. Проект більше не підтримується
ома

Не хвилюйтесь - я спробував декілька цих заздалегідь створених рішень - жоден не працював із таблицею ширини flex-col, що перевищувала ширину екрана. Я завершив написання власного рішення.
ДжозефК

9

Більшість розміщених тут рішень потребують jQuery. Якщо ви шукаєте рамкове незалежне рішення, спробуйте Grid: http://www.matts411.com/post/grid/

Він розміщений на Github тут: https://github.com/mmurph211/Grid

Він не тільки підтримує фіксовані заголовки, але також підтримує фіксовані ліві стовпці та колонтитули, серед іншого.


Це дійсно акуратно, якщо воно відповідає вашим потребам, я просто сьогодні з ним грав. На жаль, це скоріше прямокутна сітка (як випливає з назви насправді), а не справжня таблиця з висотою рядків, відрегульованою вмістом. І стилізація окремих рядів здавалася важкою. Мені не вдалося створити таблицю з смугастою зеброю, але не дуже намагався, оскільки мої потреби були насправді складнішими. У всякому разі, приємна робота.
mplwork

1
Гей, я тебе знаю! Ми, здавалося, написали дуже схоже лайно ( github.com/mkoryak/floatThead ) - Misha
mkoryak

9

Властивість CSS position: stickyмає велику підтримку в більшості сучасних браузерів (у мене були проблеми з Edge, див. Нижче).

Це дозволяє вирішити проблему фіксованих заголовків досить легко:

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

Safari необхідний префікс постачальника: -webkit-sticky.

Для Firefox мені довелося додати min-height: 0до одного батьківських елементів. Я точно забуваю, для чого це було потрібно.

На жаль, реалізація Microsoft Edge здається лише напівпрацюючою. Принаймні, у мене на тестуванні були деякі мерехтливі та нерівні комірки таблиці. Стіл все ще використовувався, але мав значні естетичні проблеми.


Використання position: sticky;з таблицею всередині DIV , який має overflow: scroll;, overflow-x: scroll;або overflow-y: scroll;. представляється найкращим і найпростішим рішенням для фіксованих заголовків та стовпців у сучасних браузерах. За цю відповідь потрібно проголосувати вгорі.
Ненормальна

Це просто, але ефективно. Це те, що я шукаю. Дякую.
Catbuilts

6

Більш вдосконалена чиста таблиця прокрутки CSS

У всіх чистих CSS-рішеннях, які я бачив дотепер - розумні, хоча вони можуть бути - не вистачає певного рівня полірування або просто не справляються нормально в деяких ситуаціях. Отже, я вирішив створити свою власну ...

Особливості:

  • Це чистий CSS, тому jQuery не потрібен (або взагалі будь-який код JavaScript)
  • Ви можете встановити ширину таблиці у відсотках (aka "fluid") або фіксованому значенні, або дозволити вмісту визначати його ширину (він же "auto")
  • Ширина стовпців також може бути текучою, фіксованою або автоматичною.
  • Стовпці ніколи не стануть нерівними з заголовками через горизонтальну прокрутку (проблема, яка виникає у будь-якому іншому базі CSS рішення, яке я бачив, і не потребує фіксованої ширини).
  • Сумісний з усіма популярними браузерами настільних ПК, включаючи Internet Explorer назад до версії 8
  • Чистий, відшліфований зовнішній вигляд; відсутні неохайні 1-піксельні прогалини або нерівні рамки; виглядає однаково у всіх браузерах

Ось пара загадок, які показують параметри рідини та ширини авто:

  • Ширина і висота рідини (адаптується до розміру екрана): jsFiddle (Зверніть увагу, що панель прокрутки відображається лише в разі необхідності в цій конфігурації, тому вам, можливо, доведеться зменшити рамку, щоб побачити її)

  • Автоматична ширина, фіксована висота (простіше інтегруватися з іншим вмістом): jsFiddle

Конфігурація Auto Width, Fixed Height, ймовірно, має більше випадків використання, тому я опублікую код нижче.

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

Метод, який я використовував для заморожування рядка заголовка, схожий на d-Pixie, тому для пояснення зверніться до його публікації. Існувала велика кількість помилок та обмежень із цією технікою, яку можна було виправити лише набором додаткових CSS та додатковим контейнером Div або двома.


Ця відповідь є недооціненою! Я витрачав дні, намагаючись знайти інші рішення, щоб працювати для мого особливо прикрого випадку. Кожен з них так чи інакше не зміг вирівнятися. Нарешті це і вдалося! Спочатку здається надмірно складним, але як тільки ви отримаєте повісити його, дивним. Ви можете видалити зовсім небагато речей, які вам не знадобляться, зрештою, не використовуючи ширину рідини тощо.
Джастін Сане

1
@JustinSane Радий, що вам це подобається! Я б здогадався, що недооцінка пов'язана з тим, що вона ділиться сторінкою з дивовижним рішенням Максиміліана Хілса . Якщо ви не проти використання крихітного шматочка JS, вам обов'язково слід це перевірити.
DoctorDestructo

Чорт, що це майже ідеальне рішення дійсно. Я все-таки використовував jQuery, намагався змусити його працювати з цим, перш ніж я знайшов ваш (через ваш коментар до іншого питання). Не думав прослуховувача прокрутки та перекладу ... Ну, вони кажуть, що геній повинен придумати прості рішення ..;) Я закінчив проект, і він ідеально працює без js, але я продовжуватиму це розум на майбутнє. Тим не менш, капелюхи для вас за те, що вони приголомшливі!
Джастін Сане

Невелика проблема, але якщо ви використовуєте різні системні кольори, ви можете бачити, що колір тексту не встановлений ні для чого, крім заголовків, але фон таблиці має явний колір фону. У мене є жовтий текст на білому та сірому тлі для цієї таблиці.
Метт Арнольд

1
@MattArnold Виправлено. Thx для підказки!
DoctorDestructo

5

Простий плагін jQuery

Це варіація рішення Махеса. Ви можете назвати це як$('table#foo').scrollableTable();

Ідея така:

  • Розділіть theadі tbodyна окремі tableелементи
  • Зробіть їх ширина комірок знову збігатися
  • Загорніть другу tableв аdiv.scrollable
  • Використовуйте CSS для div.scrollableфактичного прокручування

CSS може бути:

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

Коваджі

  • Очевидно, розбиття цих таблиць робить розмітку менш семантичною. Я не впевнений, що це впливає на доступність.
  • Цей плагін не стосується колонтитулів, декількох заголовків тощо.
  • Я протестував його лише у версії Chrome 20.

Однак, це працює для моїх цілей, і ви вільні взяти та змінити його.

Ось плагін:

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
Гарний сценарій, цей найкращий працював у моєму середовищі. Я розширив ваш сценарій із підтримкою фіксованого колонтитулу, перевірте свою публікацію нижче.
gitaarik

4

:)

Не дуже чисте, але чисте HTML / CSS рішення.

table {
    overflow-x:scroll;
}

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

Оновлено для прикладу IE8 + JSFiddle


2
Хороше рішення, тільки згадати, що ці клітини плавали і так за змістом може мати різну висоту, це видно , якщо встановити їх межі: jsfiddle.net/ZdeEH/15
Stano

3

Підтримка фіксованого колонтитула

Я розширив функцію Натана, щоб підтримувати фіксований колонтитул і максимальну висоту. Також функція встановить сам CSS, і вам потрібно лише підтримувати ширину.

Використання:

Фіксована висота:

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

Максимальна висота (якщо браузер підтримує CSS опцію "максимальна висота"):

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

Сценарій:

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

Я якось закінчився з Position:Stickyхорошою роботою над моєю справою:

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
Це найчистіше рішення, яке я бачив досі. Канюза показує, що станом на 5/20/2020 нефіксований статус: липкий користується глобальною підтримкою 90,06%. Тож це рішення добре працює у всіх сучасних браузерах.
AlienKevin

2

Два діви, один для заголовка, один для даних. Зробіть поділ даних прокручуваним та використовуйте JavaScript, щоб встановити ширину стовпців у заголовку таким самим, як ширина даних. Я думаю, що ширину стовпців даних потрібно виправити, а не динамічно.


3
Якщо ви дбаєте про доступність, це невдача.
epascarello

1
знову доступність, можливо, ми можемо замінити використання divs стилями на <thead> і <tbody> ??
Cheekysoft

1

Я розумію, що питання дозволяє JavaScript, але ось чисте рішення CSS, яке я розробив, яке також дозволяє розширювати таблицю по горизонталі. Він був протестований за допомогою Internet Explorer 10 та останніх браузерів Chrome і Firefox. Посилання на jsFiddle знаходиться внизу.

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>

І 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

Для тих, хто спробував приємне рішення, надане Максиміліаном Хілсом, і йому не вдалося змусити його працювати з Internet Explorer, у мене була та сама проблема (Internet Explorer 11) і з'ясувала, в чому проблема.

В Internet Explorer 11 перетворення стилів (принаймні з перекладом) не працює <THEAD>. Я вирішив це, замість цього застосувавши стиль до всіх <TH>циклів. Це спрацювало. Мій JavaScript-код виглядає так:

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

У моєму випадку таблиця була GridView в ASP.NET. Спочатку я подумав, що це тому, що його немає <THEAD>, але навіть коли я змусив його мати, він не працював. Тоді я дізнався, що я написав вище.

Це дуже приємне і просте рішення. У Chrome це ідеально, на Firefox трохи похмуро, а в Internet Explorer ще більше ривком. Але загалом гарне рішення.


0

Я б хотів, щоб я знайшов рішення @ Марка раніше, але я пішов і написав своє, перш ніж побачив це питання ТАК ...

Шахта - це дуже легкий плагін jQuery, який підтримує фіксований заголовок, колонтитул, проміжок стовпців (colspan), зміну розміру, горизонтальну прокрутку та необов'язкове число рядків для відображення до початку прокрутки.

jQuery.scrollTableBody (GitHub)

Поки у вас є таблиця з належними <thead>, <tbody>і (необов’язково) <tfoot>, все, що вам потрібно зробити, це:

$('table').scrollTableBody();

0

Я знайшов таке вирішення - переміщення рядка заголовка в таблиці над таблицею з даними:

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


працює для невеликих таблиць, але якщо у вас горизонтальна прокрутка, це рішення не буде працювати.
crh225

Він також не працюватиме належним чином, оскільки стовпці таблиці не будуть вирівнюватись. Ось ви примушуєте ширину для td, але ми не повинні цього робити
Ziggler

0

Застосовуючи плагін StickyTableHeaders jQuery до таблиці, заголовки стовпців будуть триматися у верхній частині вікна перегляду під час прокрутки вниз.

Приклад:

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

Мені подобається відповідь Максиміліана Хілса, але у мене виникли деякі питання:

  1. трансформація не працює в Edge або IE, якщо ви не застосуєте її до th
  2. заголовок мерехтить під час прокрутки в Edge та IE
  3. моя таблиця завантажується за допомогою ajax, тому я хотів приєднати до події прокрутки вікна, а не події прокрутки обгортки

Щоб позбутися від мерехтіння, я використовую тайм-аут, щоб дочекатися, коли користувач закінчить прокрутку, потім застосую перетворення - щоб заголовок під час прокрутки не було видно.

Я також писав це за допомогою jQuery, одна з переваг того, що jQuery повинен обробляти префікси постачальників для вас

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

Таблиця загорнута в діву з класом table-container-fixed.

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

Я встановив розділення кордону, щоб розділитись, оскільки в іншому випадку ми втрачаємо межі під час перекладу, і я видаляю межу на столі, щоб зупинити показ вмісту трохи вище клітинки, де межа була під час прокрутки.

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

Я роблю thфон білим, щоб покрити клітинки під ним, і додаю рамку, яка відповідає межі таблиці - яка стилізована за допомогою Bootstrap і прокручується з поля зору.

 .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

Використовуйте останню версію jQuery і включайте наступний код JavaScript.

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

1
Це, здається, не працює. Може, ти зможеш уточнити, що ти хочеш від нас?
Кріс

1
Який дів? Ми говоримо про столи тут
isapir

0

Це не точне рішення для фіксованого рядка заголовка, але я створив досить геніальний метод повторення рядка заголовка протягом усієї довгої таблиці, але все ще зберігаючи можливість сортування.

Цей акуратний маленький варіант вимагає додатка jQuerytablesorter . Ось як це працює:

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>

Очевидно, у моєї таблиці є набагато більше рядків, ніж у цієї. Точністю 193, але ви можете бачити, де повторюється рядок заголовка. Повторний рядок заголовка встановлюється за допомогою цієї функції:

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

Дуже багато людей, схоже, шукають цю відповідь. Я виявив, що це поховано у відповіді на інше запитання тут: Синхронізація ширини стовпців між таблицями у двох різних кадрах тощо

З десятків методів, які я спробував, це єдиний метод, який я виявив, що працює надійно, щоб ви могли мати прокручувану нижню таблицю, коли таблиця заголовків має однакові ширини.

Ось як я це зробив, спершу я вдосконалювався на jsfiddle вище, щоб створити цю функцію, яка працює і на обох, tdі thна випадок (у випадку, якщо відключає інших, які використовують thдля стилізації своїх рядків заголовків).

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

Далі вам потрібно створити дві таблиці, ПРИМІТКА. У таблиці заголовка повинна бути додаткова, TDщоб залишити місце у верхній таблиці для панелі прокрутки, як це:

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

Тоді зробіть щось на кшталт:

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

Це єдине рішення, яке я знайшов у Stack Overflow, який працює з багатьох подібних питань, які були опубліковані, що працює у всіх моїх випадках.

Наприклад, я спробував плагін jQuery stickytables, який не працює з дурандалом, і проект Google Code тут https://code.google.com/p/js-scroll-table-header/isissue/detail?id=2

Інші рішення, пов’язані з клонуванням столів, мають низьку продуктивність або смокчуть, і працюють не у всіх випадках.

Немає потреби в цих надмірно складних рішеннях. Просто складіть дві таблиці, як наведені нижче приклади, і викличте функцію setHeaderTableWidth, як описано тут, і бум, ви закінчили .

Якщо це не працює для вас, ви, ймовірно, грали зі своїм властивістю розміщення коробки CSS, і вам потрібно його правильно встановити. Викрутити вміст CSS легко випадково. Є багато речей, які можуть піти не так, тому просто будьте в курсі / обережно. Такий підхід працює для мене .


0

Ось рішення, над яким ми закінчили роботу (щоб розібратися з деякими кращими справами та старішими версіями Internet Explorer, ми врешті-решт також вимкнули рядок заголовка в прокрутці, потім зникли назад, коли прокрутка закінчується, але в браузерах Firefox та WebKit це рішення просто працює, воно передбачає руйнування кордону: колапс.

Ключовим у цьому рішенні є те, що після подання заявки крапку кордону , CSS перетворюється працює над заголовком, тому це лише питання перехоплення подій прокрутки та правильного налаштування перетворення. Вам не потрібно нічого дублювати. Якщо ця поведінка не реалізується належним чином у браузері, важко уявити більш легке рішення.

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

Він реалізований як простий плагін jQuery. Ви просто зробите клей свого теда з викликом, як $ ('thead'). Sticky (), і вони будуть зависати. Він працює для декількох таблиць на сторінці та головних розділах на півдорозі великих таблиць.

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

гарне рішення, але як ви включаєте межі стовпців між стовпцями (обидва у фіксованому заголовку, вирівняному до даних td)?
user5249203

Я не впевнений, що розумію вашу проблему. Збіг кордону не заважає вам використовувати межі, поля тощо, він просто видаляє показники таблиці вуду давніших часів.
підперсон

1
Додати border: 2px solid red;до th, сувою, і ви побачите цю проблему. Я сам придумав це більш базове рішення: jsfiddle.net/x6pLcor9/19
calandoa

Додайте ту саму розмірну рамку до td, і немає жодної проблеми. Я не бачу вашої суті. Ваша версія набагато чистіша і не використовує jQuery, тому я сьогодні неодмінно працюю з чимось подібним. (Хоча, чесно кажучи, я не думаю, що сьогодні я взагалі використовую таблицю.)
podperson

0

Ось вдосконалена відповідь на ту, яку опублікував Максиміліан Хілс .

Цей працює в Internet Explorer 11, не маючи мерехтіння:

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

Я розробив простий плагін jQuery з легкою вагою для перетворення добре відформатованої таблиці HTML у таблицю, яку можна прокручувати, з фіксованим заголовком та стовпцями таблиці.

Плагін добре працює, щоб відповідати розташуванню фіксованої секції фіксованому ділянці з секцією, що прокручується. Крім того, ви також можете заморозити кількість стовпців, які завжди будуть переглянуті при горизонтальній прокрутці.

Демонстрація та документація: http://meetselva.github.io/fixed-table-rows-cols/

Репозиторій GitHub: https://github.com/meetselva/fixed-table-rows-cols

Нижче наведено використання для простої таблиці з фіксованим заголовком,

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

Що таке "добре HTML-таблиця" ?
Пітер Мортенсен

@PeterMortensen Мав бути "добре відформатований HTML". Відредаговано, спасибі
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

Додатково до відповіді @Daniel Waltrip. position: relativeЩоб працювати з ними, таблицю потрібно додати з дівом position:sticky. Тому я хотів би розмістити свій зразок коду тут.

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>

Демо

введіть тут опис зображення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.