Просматриваемая только CSS-таблица с фиксированными заголовками
У меня есть решение, с помощью которого я могу создавать прокручиваемые таблицы с фиксированным заголовком/нижним колонтитулом с помощью младших jQuery и CSS, но я ищу способ сделать это решением только для CSS, совместимым с кросс-браузером.
Чтобы быть ясным, я пытаюсь использовать тег only a table
(и это действительные подтеги, colgroup
, col
, thead
, tbody
, tfoot
, tr
, th
, td
), но принять набор правил CSS, которые будут соответствовать следующим условиям:
- Необходимо поддерживать выравнивание столбцов между строками заголовка/нижнего колонтитула/содержимого
- Должен разрешить заголовок/нижний колонтитул оставаться фиксированным, пока содержимое прокручивается вертикально.
- Не нужно использовать jQuery или другой JavaScript для обеспечения функциональности
- Необходимо использовать только теги, указанные выше
Этот пример кода: http://jsfiddle.net/TroyAlford/SNKfd/ показывает мой текущий подход. Большая часть JS - это просто заполнить таблицу случайными значениями, но последняя часть - это то, что приводит к прокрутке влево/вправо.
$tbody.bind('scroll', function(ev) {
var $css = { 'left': -ev.target.scrollLeft };
$thead.css($css);
$tfoot.css($css);
});
ПРИМЕЧАНИЕ. Приведенный пример не корректно отображается в IE и требует, чтобы jQuery обеспечивал горизонтальную прокрутку. В любом случае, мне не нужна горизонтальная прокрутка, так что это нормально, если решение не делает этого.
Ответы
Ответ 1
Этот ответ будет использоваться в качестве заполнителя для не полностью поддерживаемого position: sticky
и со временем будет обновляться. В настоящее время рекомендуется не использовать собственную реализацию этого в производственной среде.
Смотрите это для текущей поддержки: https://caniuse.com/#feat=css-sticky
Использование position: sticky
Альтернативный ответ будет использовать position: sticky
. Как описано в W3C:
Склейко позиционированный блок позиционируется аналогично относительно позиционированному блоку, но смещение вычисляется со ссылкой на ближайшего предка с блоком прокрутки или в окне просмотра, если ни у одного из предков нет блока прокрутки.
Это точно описывает поведение относительного статического заголовка. Было бы легко присвоить это HTML-тегу <thead>
или первому <tr>
, так как это должно поддерживаться в соответствии с W3C. Однако у Chrome, IE и Edge возникают проблемы с назначением для этих тегов свойства закрепления позиции. Похоже, в данный момент нет приоритета в решении этой проблемы.
То, что действительно работает для элемента таблицы, это присвоение свойства sticky ячейке таблицы. В этом случае ячейки <th>
.
Поскольку таблица не является блочным элементом, который учитывает статический размер, который вы ей назначаете, лучше всего использовать элемент-обертку для определения переполнения прокрутки.
Код
div {
display: inline-block;
height: 150px;
overflow: auto
}
table th {
position: -webkit-sticky;
position: sticky;
top: 0;
}
/* == Just general styling, not relevant :) == */
table {
border-collapse: collapse;
}
th {
background-color: #1976D2;
color: #fff;
}
th,
td {
padding: 1em .5em;
}
table tr {
color: #212121;
}
table tr:nth-child(odd) {
background-color: #BBDEFB;
}
<div>
<table border="0">
<thead>
<tr>
<th>head1</th>
<th>head2</th>
<th>head3</th>
<th>head4</th>
</tr>
</thead>
<tr>
<td>row 1, cell 1</td>
<td>row 1, cell 2</td>
<td>row 1, cell 2</td>
<td>row 1, cell 2</td>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
<td>row 1, cell 2</td>
<td>row 1, cell 2</td>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
<td>row 1, cell 2</td>
<td>row 1, cell 2</td>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
<td>row 1, cell 2</td>
<td>row 1, cell 2</td>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
<td>row 1, cell 2</td>
<td>row 1, cell 2</td>
</tr>
</table>
</div>
Ответ 2
Удивленное решение с использованием flexbox еще не опубликовано.
Здесь мое решение с использованием display: flex
и базового использования :after
(благодаря Luggage) для поддержания выравнивания, даже если полоса прокрутки немного дополняет tbody
. Это было проверено в Chrome 45, Firefox 39 и MS Edge. Его можно изменить с помощью префиксных свойств для работы в IE11, а также в IE10 с помощью CSS-хака и 2012 года синтаксиса flexbox.
Обратите внимание, что ширина таблицы может быть изменена; это даже работает на ширине 100%
.
Единственное предостережение в том, что все ячейки таблицы должны иметь одинаковую ширину. Ниже приведен явно надуманный пример, но он прекрасно работает, когда содержимое ячеек меняется (все ячейки таблицы имеют одинаковую ширину и перенос слов, заставляя flexbox сохранять одинаковую ширину независимо от содержимого). Здесь - пример, где содержимое ячеек отличается.
Просто примените класс .scroll
к таблице, которую вы хотите прокрутить, и убедитесь, что у нее есть thead
:
.scroll {
border: 0;
border-collapse: collapse;
}
.scroll tr {
display: flex;
}
.scroll td {
padding: 3px;
flex: 1 auto;
border: 1px solid #aaa;
width: 1px;
word-wrap: break-word;
}
.scroll thead tr:after {
content: '';
overflow-y: scroll;
visibility: hidden;
height: 0;
}
.scroll thead th {
flex: 1 auto;
display: block;
border: 1px solid #000;
}
.scroll tbody {
display: block;
width: 100%;
overflow-y: auto;
height: 200px;
}
<table class="scroll" width="400px">
<thead>
<tr>
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
</tr>
</thead>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
</table>
Ответ 3
Насколько я знаю, нет стандартного способа достижения этого только с помощью CSS, хотя я думаю, что должно быть. В браузерах Mozilla используются фиксированные заголовки с прокручиваемым телом, но они удалили его за последние несколько лет.
После изучения этого немного, включая поиск этой публикации, друг только что разработал это решение для меня; он использует Javascript, но не имеет консервированных библиотек, и единственным требованием для разметки HTML является то, что таблица имеет идентификатор. Затем, в window.onload, вызывается одна функция Javascript для каждой таблицы с указанием идентификатора, высоты и ширины. Если Javascript отключен в браузере, вся таблица отображается в соответствии с ее исходной разметкой. Если Javascript включен, таблица вписывается в указанную высоту и ширину, а тронные свитки, и если существуют теги и tfoot, они фиксируются сверху и снизу.
Ответ 4
Вдохновленный ответом @Purag, здесь другое решение flexbox:
/* basic settings */
table { display: flex; flex-direction: column; width: 200px; }
tr { display: flex; }
th:nth-child(1), td:nth-child(1) { flex-basis: 35%; }
th:nth-child(2), td:nth-child(2) { flex-basis: 65%; }
thead, tbody { overflow-y: scroll; }
tbody { height: 100px; }
/* color settings*/
table, th, td { border: 1px solid black; }
tr:nth-child(odd) { background: #EEE; }
tr:nth-child(even) { background: #AAA; }
thead tr:first-child { background: #333; }
th:first-child, td:first-child { background: rgba(200,200,0,0.7); }
th:last-child, td:last-child { background: rgba(255,200,0,0.7); }
<table>
<thead>
<tr>
<th>a
<th>bbbb
<tbody>
<tr>
<td>fooo vsync dynamic
<td>bar
<tr>
<td>a
<td>b
<tr>
<td>a
<td>b
<tr>
<td>a
<td>b
<tr>
<td>a
<td>b
<tr>
<td>a
<td>b
<tr>
<td>a
<td>b
</table>
Ответ 5
Ive легко выполнил этот код:
Итак, у вас есть такая структура:
<table>
<thead><tr></tr></thead>
<tbody><tr></tr></tbody>
</table>
просто введите thead с помощью:
<style>
thead{
position: -webkit-sticky;
position: -moz-sticky;
position: -ms-sticky;
position: -o-sticky;
position: sticky;
top: 0px;
}
</style>
Три вещи для рассмотрения:
Во-первых, это свойство является новым. Он не поддерживается вообще, кроме бета-версий браузеров на базе Webkit. Так предостережение. Опять же, если вы действительно хотите, чтобы ваши пользователи пользовались липкими заголовками, перейдите к реализации javascript.
Во-вторых, если вы его используете, вам необходимо включить префиксы поставщиков. Возможно, позиция: липкая будет работать в один прекрасный день. На данный момент вам нужно использовать позицию: -webkit-sticky (и другие, еще раз проверьте блок css в этом сообщении).
В-третьих, в настоящий момент не существует никаких настроек по умолчанию, поэтому вам нужно, по крайней мере, включить top: 0; в той же декларации css, что и позиция: -webkit-sticky. В противном случае itll просто прокручивает экран.
Ответ 6
Если у вас есть возможность задать фиксированную ширину для ячеек таблицы (и фиксированную высоту для заголовка), вы можете использовать опцию position: fixed
:
http://jsfiddle.net/thundercracker/ZxPeh/23/
Вам просто нужно вставить его в iframe
. Вы также можете иметь горизонтальную прокрутку, указав iframe
полосу прокрутки (я думаю).
Изменить 2015
Если вы можете жить с предопределением ширины ваших ячеек таблицы (в процентах), то здесь немного более изящное (только CSS-решение):
http://jsfiddle.net/7UBMD/77/
Ответ 7
Только с CSS:
CSS
tr {
width: 100%;
display: inline-table;
table-layout: fixed;
}
table{
height:300px; // <-- Select the height of the table
display: -moz-groupbox; // Firefox Bad Effect
}
tbody{
overflow-y: scroll;
height: 200px; // <-- Select the height of the body
width: 100%;
position: absolute;
}
Bootply: http://www.bootply.com/AgI8LpDugl
Ответ 8
Я вижу, что этот поток неактивен некоторое время, но этот вопрос интересовал меня и теперь с некоторыми селекторами CSS3, это стало проще (и довольно выполнимо только с CSS).
Это решение зависит от максимальной высоты контейнера таблицы. Но он поддерживается, пока вы можете использовать селектор :first-child
.
Fiddle здесь.
Если кто-то может улучшить этот ответ, сделайте это! Я планирую использовать это решение в коммерческом приложении в ближайшее время!
HTML
<div id="con">
<table>
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
CSS
#con{
max-height:300px;
overflow-y:auto;
}
thead tr:first-child {
background-color:#00f;
color:#fff;
position:absolute;
}
tbody tr:first-child td{
padding-top:28px;
}
Ответ 9
У меня была такая же проблема, и после двухдневного исследования я нашел это решение от Ksesocss, которое подходит для меня и, может быть, хорошо для вас тоже. Он позволяет фиксировать заголовок и динамическую ширину и использует только CSS. Единственная проблема заключается в том, что источник находится на испанском языке, но вы можете найти там код html и css.
Это ссылка:
http://ksesocss.blogspot.com/2014/10/responsive-table-encabezado-fijo-scroll.html
Я надеюсь, что это поможет
Ответ 10
если он становится жестким, когда все упомянутые решения не работают (как это получилось для меня), попробуйте решение с двумя вариантами, как я объяснил в этом ответе
fooobar.com/questions/94159/...
Ответ 11
Как я недавно нуждался в этом, я поделюсь решением, которое использует 3 таблицы, но не требует JavaScript.
Таблица 1 (родительская) содержит две строки. Первая строка содержит таблицу 2 (дочерний элемент 1) для заголовков столбцов. Вторая строка содержит таблицу 3 (дочерний элемент 2) для содержимого прокрутки.
Следует отметить, что childTbl
должен быть 25px
короче, чем parentTbl
, чтобы скроллер отображался правильно.
Это является источником, откуда я получил эту идею. Я сделал HTML5-дружественным без устаревших тегов и встроенного CSS.
.parentTbl table {
border-spacing: 0;
border-collapse: collapse;
border: 0;
width: 690px;
}
.childTbl table {
border-spacing: 0;
border-collapse: collapse;
border: 1px solid #d7d7d7;
width: 665px;
}
.childTbl th,
.childTbl td {
border: 1px solid #d7d7d7;
}
.scrollData {
width: 690;
height: 150px;
overflow-x: hidden;
}
<div class="parentTbl">
<table>
<tr>
<td>
<div class="childTbl">
<table class="childTbl">
<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>
</tr>
</table>
</div>
</td>
</tr>
<tr>
<td>
<div class="scrollData childTbl">
<table>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
<tr>
<td>Table Data 1</td>
<td>Table Data 2</td>
<td>Table Data 3</td>
<td>Table Data 4</td>
<td>Table Data 5</td>
<td>Table Data 6</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</div>
Ответ 12
Я пытался выяснить это сам недавно, и я придумал хорошее решение, которое отлично работает в моем браузере (Chrome 51) и поддерживает динамические ширины столбцов. Я должен упомянуть, что после того, как я самостоятельно получил свой ответ, я также нашел аналогичную технику, описанную в другом месте в Интернете...
Трюк состоит в том, чтобы использовать две идентичные таблицы, расположенные друг над другом. Нижняя таблица видна, а верхняя таблица невидима для заголовка. Верхняя таблица также имеет pointer-events: none
, установленную на теле, поэтому мышиные взаимодействия попадают в нижнюю таблицу. Таким образом, нижняя таблица прокручивается под заголовком верхней таблицы.
Для всего, что нужно для макета и изменения размера (когда пользователь настраивает ширину экрана, например), обе таблицы должны иметь одинаковое поведение прокрутки. Однако верхняя полоса прокрутки таблицы игнорируется благодаря pointer-events: none
и может быть невидимой с помощью:
<style>
.hiddenScrollbar::-webkit-scrollbar {
background-color: transparent;
}
</style>
Вот полный код:
<html>
<head>
<style>
td {
border: 1px solid black;
white-space: nowrap;
}
th {
background-color: gray;
border: 1px solid black;
white-space: nowrap;
}
.hiddenScrollbar::-webkit-scrollbar {
background-color: transparent;
}
</style>
</head>
<body>
Table test. Use mouse wheel to scroll or scroll to the right to see vertical scroll bar. You can also remove the outermost div if you don't want a horizontal scroll bar.
<br/>
<div style="display: inline-block; height: 10em; width: 15em; overflow-x: scroll; overflow-y: hidden">
<div style="position: relative;">
<div style="display: inline-block; position: absolute; left: 0px; top: 0px; height: 10em; overflow-y: scroll">
<table style="border-collapse: collapse;">
<thead>
<tr>
<th>Column 1</th>
<th>Another Column</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 2</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 3</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 4</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 5</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 6</td>
<td>12340921375021342354235 very long...</td>
</tr>
<tr>
<td>Data 7</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 8</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 9</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 10</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 11</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 12</td>
<td>123409213750213</td>
</tr>
</tbody>
</table>
</div>
<div class="hiddenScrollbar" style="display: inline-block; pointer-events: none; position: relative; left: 0px; top: 0px; height: 10em; overflow-y: scroll">
<table style="border-collapse: collapse;">
<thead style="pointer-events: auto">
<tr>
<th>Column 1</th>
<th>Another Column</th>
</tr>
</thead>
<tbody style="visibility: hidden">
<tr>
<tr>
<td>Data 1</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 2</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 3</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 4</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 5</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 6</td>
<td>12340921375021342354235 very long...</td>
</tr>
<tr>
<td>Data 7</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 8</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 9</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 10</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 11</td>
<td>123409213750213</td>
</tr>
<tr>
<td>Data 12</td>
<td>123409213750213</td>
</tr>
</tr>
</tbody>
</table>
</div>
</div>
</div><br/>
Stuff after table.
</body>
</html>
Ответ 13
Другая реализация, но без переполнения на tbody
и динамических столбцах. Требуется JavaScript. Контейнер div
используется для размещения заголовков столбцов. Когда таблица прокручивается мимо порта представления, в верхней части отображается фиксированный заголовок. Если таблица прокручивается по горизонтали, фиксированный заголовок также прокручивается.
Заголовки столбцов создаются с использованием элементов span
с display: inline-block
, а отрицательный запас используется для прокрутки заголовка по горизонтали. Также оптимизируется с помощью RequestAnimationFrame
, чтобы избежать использования jank.
function rAF(scrollLeft) {
var offsetLeft = 0 - scrollLeft;
$('.hdr__inner span:first-child').css('margin-left', offsetLeft);
}
https://codepen.io/lloydleo/pen/NRpqEE