HTML-таблица с фиксированными заголовками?
Существует ли кросс-браузерный метод CSS/JavaScript для отображения длинной таблицы HTML, так что заголовки столбцов остаются фиксированными на экране и не прокручиваются с телом таблицы. Подумайте о эффекте "замораживания окон" в Microsoft Excel.
Я хочу иметь возможность прокручивать содержимое таблицы, но всегда иметь возможность видеть заголовки столбцов вверху.
Ответы
Ответ 1
Некоторое время я искал решение для этого и обнаружил, что большинство ответов не работают или не подходят для моей ситуации, поэтому я написал простое решение с помощью jQuery.
Вот схема решения:
- Клонируйте таблицу, которая должна иметь фиксированный заголовок, и поместите
клонированная копия поверх оригинала.
- Снимите тело стола с верхнего стола.
- Удалить заголовок таблицы из нижней таблицы.
- Отрегулируйте ширину столбцов. (Мы отслеживаем исходную ширину столбцов)
Ниже приведен код в работающей демоверсии.
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>
Ответ 2
Это можно решить в четыре строки кода.
Если вы заботитесь только о современных браузерах, то с помощью 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-.
Вот полный пример для справки:
document.getElementById("wrap").addEventListener("scroll",function(){
var translate = "translate(0,"+this.scrollTop+"px)";
this.querySelector("thead").style.transform = translate;
});
/* Your existing container */
#wrap {
overflow: auto;
height: 400px;
}
/* CSS for demo */
td {
background-color: green;
width: 200px;
height: 100px;
}
<div id="wrap">
<table>
<thead>
<tr>
<th>Foo</th>
<th>Bar</th>
</tr>
</thead>
<tbody>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td><td></td></tr>
</tbody>
</table>
</div>
Ответ 3
Я только что завершил сборку плагина jQuery, который будет принимать действительную единую таблицу, используя действительный HTML (должен иметь aad и tbody), и выведет таблицу с фиксированными заголовками, необязательный фиксированный нижний колонтитул, который может быть либо клонированным заголовок или любой контент, который вы выбрали (разбивка на страницы и т.д.). Если вы хотите использовать более крупные мониторы, это также изменит размер таблицы при изменении размера браузера. Еще одна добавленная функция - это возможность прокрутки в сторону, если столбцы таблицы не могут полностью соответствовать.
http://fixedheadertable.com/
в github: http://markmalek.github.com/Fixed-Header-Table/
Он очень прост в настройке, и вы можете создать для него свои собственные стили. Он также использует закругленные углы во всех браузерах. Имейте в виду, я только что выпустил его, так что он по-прежнему технически бета-версии и есть очень мало мелких проблем, которые я сглаживаю.
Он работает в Internet Explorer 7, Internet Explorer 8, Safari, Firefox и Chrome.
Ответ 4
Я также создал плагин для решения этой проблемы. Мой проект - jQuery.floatThead существует уже более 4 лет и является очень зрелым.
Он не требует внешних стилей и не предполагает, что ваша таблица будет стилизована каким-либо конкретным способом. Он поддерживает Интернет Explorer9+ и Firefox/Chrome.
В настоящее время (2018-05) он имеет:
405 коммитов и 998 звезд на GitHub
Многие (не все) ответы здесь являются быстрыми взломами, которые, возможно, решили проблему, с которой столкнулся один человек, но будут работать не для каждой таблицы.
Некоторые из других плагинов старые и, вероятно, отлично работают с Internet Explorer, но будут работать с Firefox и Chrome.
Ответ 5
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>
Ответ 6
Все попытки решить эту проблему вне спецификации CSS являются бледной тенью того, что мы действительно хотим: поставка под подразумеваемым обещанием THEAD.
Эта проблема "замороженные заголовки для таблицы" уже давно является открытой раной в HTML/CSS.
В идеальном мире было бы чисто CSS-решение для этой проблемы. К сожалению, там, похоже, нет хорошего.
Соответствующие обсуждения стандартов на эту тему:
ОБНОВЛЕНИЕ: Firefox поставляется position:sticky
в версии 32. Все выигрывают!
Ответ 7
Вот плагин jQuery для фиксированных заголовков таблиц. Это позволяет прокручивать всю страницу, замораживая заголовок, когда он достигает вершины. Хорошо работает с таблицами Twitter.
Репозиторий GitHub: https://github.com/oma/table-fixed-header
Он не прокручивает только содержимое таблицы. Посмотрите на другие инструменты для этого, как один из этих других ответов. Вы сами решаете, что подходит вашему делу лучше всего.
Ответ 8
В большинстве решений, размещенных здесь, требуется jQuery. Если вы ищете независимое от структуры решение, попробуйте Grid: http://www.matts411.com/post/grid/
Он размещен на Github здесь: https://github.com/mmurph211/Grid
Он поддерживает не только фиксированные заголовки, но также поддерживает фиксированные левые столбцы и нижние колонтитулы, среди прочего.
Ответ 9
Более совершенная таблица прокрутки чистого CSS
Все чистые CSS-решения, которые я видел, настолько far-- умные, хотя они могут be-- испытывать недостаток в определенном уровне полировки или просто не работать должным образом в некоторых ситуациях. Итак, я решил создать свой собственный...
Особенности:
- Это чистый CSS, поэтому не требуется jQuery (или вообще никакого кода JavaScript, для этого
материя)
- Вы можете установить ширину таблицы в процентах (a.k.a. "жидкость") или фиксированном значении, или позволить содержимому определять его ширину (a.k.a. "auto")
- Ширина столбцов также может быть плавной, фиксированной или автоматической.
- Столбцы никогда не будут смещены с заголовками из-за горизонтальной прокрутки (проблема, которая возникает в любом другом решении на основе CSS, которое я видел, которое не требует фиксированной ширины).
- Совместим со всеми популярными настольными браузерами, включая Internet Explorer до версии 8
- Чистый, полированный внешний вид; нет неаккуратных зазоров в 1 пиксель или смещенных границ; выглядит одинаково во всех браузерах
Вот несколько скрипок, которые показывают параметры жидкости и автоматической ширины:
Ширина и высота жидкости (адаптируется к размеру экрана): jsFiddle (обратите внимание, что полоса прокрутки отображается только при необходимости в этой конфигурации, поэтому вам может потребоваться уменьшить рамку, чтобы увидеть ее)
Автоматическая ширина, фиксированная высота (проще интегрировать с другим контентом): jsFiddle
Конфигурация с автоматической шириной и фиксированной высотой, вероятно, имеет больше вариантов использования, поэтому я опубликую код ниже.
/* 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]-->
Ответ 10
Простой плагин 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);
};
Ответ 11
Свойство CSS position: sticky
прекрасно поддерживается в большинстве современных браузеров (у меня были проблемы с Edge, см. ниже).
Это позволяет нам легко решить проблему с фиксированными заголовками:
thead th { position: sticky; top: 0; }
Safari нужен префикс поставщика: -webkit-sticky
.
Для Firefox мне пришлось добавить min-height: 0
к одному из родительских элементов. Я точно забыл, зачем это было нужно.
К сожалению, реализация Microsoft Edge кажется только полуработающей. По крайней мере, у меня были некоторые мерцающие и смещенные ячейки таблицы в моем тестировании. Стол был еще пригоден для использования, но имел значительные эстетические проблемы.
Ответ 12
:)
Не-чистое, но чистое решение HTML/CSS.
table {
overflow-x:scroll;
}
tbody {
max-height: /*your desired max height*/
overflow-y:scroll;
display:block;
}
Обновлен для IE8 +
Пример JSFiddle
Ответ 13
Поддержка фиксированного нижнего колонтитула
Я расширил функцию Натана, чтобы также поддерживать фиксированный нижний колонтитул и максимальную высоту.
Кроме того, функция сама устанавливает CSS, и вам нужно только поддерживать ширину.
Использование:
Фиксированная высота:
$('table').scrollableTable({ height: 100 });
Максимальная высота (если браузер поддерживает опцию CSS 'max-height'):
$('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();
};
Ответ 14
Два divs, один для заголовка, один для данных. Сделайте прокрутку данных div и используйте JavaScript, чтобы установить ширину столбцов в заголовке, чтобы они были такими же, как ширина в данных. Я думаю, что ширина столбцов данных должна быть фиксированной, а не динамической.
Ответ 15
Каким-то образом я закончил тем, что 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>
Ответ 16
Я понимаю, что вопрос разрешает 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/
Ответ 17
Для тех, кто попробовал хорошее решение, данное Максимилианом Хилсом, и не смог заставить его работать с 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 - еще более вялен. Но в целом хорошее решение.
Ответ 18
Используйте последнюю версию jQuery и включите следующий код JavaScript.
$(window).scroll(function(){
$("id of the div element").offset({top:$(window).scrollTop()});
});
Ответ 19
Это не точное решение для строки с фиксированным заголовком, но я создал довольно оригинальный метод повторения строки заголовка по всей длинной таблице, но при этом сохраняю возможность сортировки.
Для этого аккуратного маленького варианта требуется плагин jQuery tablesorter
. Вот как это работает:
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);
});
Ответ 20
Хотелось бы, чтобы раньше я нашел решение @Mark, но я пошел и написал свой собственный, прежде чем увидел этот вопрос SO...
Mine - очень легкий плагин jQuery, который поддерживает фиксированный заголовок, нижний колонтитул, разбиение столбцов (colspan), изменение размера, горизонтальную прокрутку и необязательное количество строк для отображения до начала прокрутки.
jQuery.scrollTableBody(GitHub)
Пока у вас есть таблица с соответствующими <thead>
, <tbody>
и (необязательно) <tfoot>
, все, что вам нужно сделать, это:
$('table').scrollTableBody();
Ответ 21
Я разработал простой легкий плагин 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'}
]
});
Ответ 22
Многие люди, кажется, ищут этот ответ. Я нашел это скрытым в ответе на другой вопрос здесь: Синхронизация ширины столбца между таблицами в двух разных кадрах и т.д.
Из десятков методов, которые я попробовал, это единственный метод, который я нашел, который надежно работает, чтобы позволить вам иметь прокручиваемую нижнюю таблицу с таблицей заголовков, имеющей одинаковую ширину.
Вот как я это сделал, сначала я улучшил 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');
});
Это единственное решение, которое я нашел на Qaru, которое работает на основе множества похожих вопросов и работает во всех моих случаях.
Например, я попробовал плагин jQuery stickytables, который не работает с durandal, и проект Google Code здесь https://code.google.com/p/js-scroll-table-header/issues/detail?id=2
Другие решения, связанные с клонированием таблиц, имеют низкую производительность или отстой и работают не во всех случаях.
Нет необходимости в этих слишком сложных решениях. Просто создайте две таблицы, как в примерах ниже, и вызовите функцию setHeaderTableWidth, как описано здесь, и boom, все готово.
Если это не работает для вас, вы, вероятно, играете со своим свойством CSS для определения размера блока, и вам нужно установить его правильно. Это легко испортить ваш CSS-контент случайно. Есть много вещей, которые могут пойти не так, так что будьте осторожны. Этот подход работает для меня.
Ответ 23
Это решение, с которым мы в конечном итоге работали (для того, чтобы справиться с некоторыми крайними случаями и более старыми версиями Internet Explorer, мы в конечном итоге также исчезли в строке заголовка при прокрутке, а затем вернули ее обратно, когда прокрутка заканчивается, но в браузерах Firefox и WebKit это решение просто работает. Предполагается, что граница-коллапс: коллапс.
Ключом к этому решению является то, что как только вы примените border-collapse, CSS-преобразования работают с заголовком, так что это просто вопрос перехвата событий прокрутки и правильной настройки преобразования. Вам не нужно ничего дублировать. За исключением того, что это поведение правильно реализовано в браузере, трудно представить более легкое решение.
JSFiddle: http://jsfiddle.net/podperson/tH9VU/2/
Это реализовано как простой плагин jQuery. Вы просто делаете свою thead липкой с помощью вызова типа $ ('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();
Ответ 24
Я нашел это обходное решение - перемещение строки заголовка в таблице выше таблицы с данными:
<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>
Ответ 25
Применяя плагин 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 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 & 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>
Ответ 26
Вот улучшенный ответ на ответ Максимилиана Хилса.
Этот работает в 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;
}
});
Ответ 27
Мне нравится Maximillian Hils, но у меня были некоторые проблемы:
- преобразование не работает в Edge или IE, если вы не примените его к th
- заголовок загорается во время прокрутки в Edge и IE
- моя таблица загружается с помощью 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);
Таблица заключена в div с классом table-container-fixed
.
.table-container-fixed{
overflow: auto;
height: 400px;
}
Я устанавливаю border-collapse для разделения, потому что в противном случае мы теряем границы во время трансляции, и я удаляю границу в таблице, чтобы остановить контент, появляющийся чуть выше ячейки, где была граница во время прокрутки.
.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;
}
Ответ 28
<html>
<head>
<script src="//cdn.jsdelivr.net/npm/[email protected]/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>