Прокручиваемая таблица с фиксированными столбцами и заголовком, с современным CSS
Как сделать таблицу с таким небольшим количеством JavaScript, насколько это возможно, используя современный CSS?
Особенности, которые я пытаюсь иметь:
- фиксированный столбец (столбцы) (расположение и ширина)
- прокручиваемый по осям X и Y
- реагирует по оси X (для столбцов с фиксированной шириной).
Примечание: я видел и анализировал некоторые из самых популярных / увиденных вопросов и ответов в SO, например здесь и здесь.
Я знаю, что это можно сделать с помощью обработчиков событий JavaScript для прокрутки, чтобы фиксированный столбец можно было перемещать вниз / вверх, чтобы следовать за основным столбцом. Примером функциональности, которую я пытаюсь создать (но с большим количеством сценариев), может быть такой. Мы также можем добавить MutationObserver
в родительском элементе таблицы, чтобы обнаружить изменения размера и снова рассчитать размеры таблицы. Но это дорого по производительности, и, поскольку CSS также развивается и модернизируется, мне интересно, есть ли новые способы...
Есть ли решение 2017/2018 для этого, которое состоит только из CSS или как можно меньше JS?
Я хотел бы избежать необходимости реализовывать такие решения JavaScript, которые так просто ломаются:
Мои идеи:
a)
: использовать position: fixed;
в фиксированных столбцах
Проблемы:
<td>
Высота элементов должна быть определена или рассчитана с помощью JavaScript.- требуется прослушиватель события прокрутки, и нам нужно программно прокрутить фиксированный столбец
b)
: используйте div(s), чтобы "подделать" левый столбец и получить прокручиваемый контент в таблице
Проблемы:
- высота div должна синхронизироваться с высотой строк таблицы
- Семантика HTML потеряна, так как исправленный "поддельный" столбец больше не является синтаксисом таблицы
c)
: использование N таблиц показывает только части каждой из них, поэтому я могу иметь разметку HTML, но сохранить фиксированный заголовок / столбцы.
Проблемы:
- повторный HTML x N
- должны синхронизировать размеры и прокручивать с помощью JavaScript также
Используя прослушиватель события прокрутки и фиксированный левый столбец, мы можем использовать JavaScript следующим образом:
const firstColumn = [...document.querySelectorAll('table tr > *:first-of-type')];
const tableContainer = document.querySelector('.table-container');
tableContainer.addEventListener('scroll', function() {
const currentScrollPosition = this.scrollTop * -1;
firstColumn.forEach(el => el.style.marginTop = currentScrollPosition + 'px');
});
.table-container {
width: 600px;
height: 300px;
overflow-x: scroll;
overflow-y: scroll;
}
.table-scroller {
width: 1000px;
}
table {
width: 100%;
margin-left: -13px;
table-layout: fixed;
border-collapse: collapse;
border: none;
}
table th,
table td {
padding: 0.8em;
border: 1px solid;
background-color: #eeeeef;
}
table th {
background-color: #6699FF;
font-weight: bold;
}
table tr {
height: 60px;
vertical-align: middle;
}
table tr > *:first-of-type {
position: fixed;
width: 50px;
margin-left: 13px;
margin-top: 0;
height: inherit;
}
<div class="table-container">
<div class="table-scroller">
<table>
<tbody>
<tr>
<td>Edrward 0</td>
<td>32</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 1</td>
<td>32</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 2</td>
<td>32</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 3</td>
<td>32</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 4</td>
<td>32</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 5</td>
<td>32</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 6</td>
<td>32</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 7</td>
<td>32</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 8</td>
<td>32</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 9</td>
<td>32</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td><a href="#">action</a></td>
</tr>
</tbody>
</table>
</div>
</div>
Но могу ли я сделать это без JavaScript?
О возможном дублировании предложения:
Этот возможный дубликат упоминается в моем вопросе, и в нем нет того, что я ищу. Этот вопрос требует, чтобы "был заморожен только один левый столбец" - его охват более широк, он касается фиксированного заголовка, фиксированных столбцов и прокручиваемого тела.
Другой вопрос и принятый ответ с 2009 года! Я думаю, что эта тема, с моей конкретной областью применения и примерами, заслуживает повторного рассмотрения. Кроме того: мое "решение JS" является лишь примером того, как JS может сломаться, я ищу современные методы CSS для этого.
2 ответа
Может быть, вы могли бы попытаться использовать последние position:sticky
добиться этого. Или, по крайней мере, начать подход с меньшим количеством javascript.
div{
overflow:auto;
width:100%;
height:200px;
}
td,
th {
border: 1px solid #000;
width: 100px;
}
th {background-color:red;}
table {
table-layout: fixed;
width:100%;
}
td:first-child, th:first-child {
position:sticky;
left:0;
z-index:1;
background-color:grey;
}
td:last-child, th:last-child {
position:sticky;
right:0;
z-index:1;
background-color:blue;
}
thead tr th {
position:sticky;
top:0;
}
th:first-child, th:last-child {z-index:2;background-color:red;}
<div>
<table>
<thead>
<tr>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
</div>
Просто посмотрите на мой код с фиксированным заголовком и исправьте первый столбец.
<style type="text/css">
.table {
font-family: arial, sans-serif;
border-collapse: collapse;
}
.th {
width: 126px;
height: 56px;
padding: 0px 16px;
text-align: left;
background-color: #fafafa;
}
.td {
width: 118px;
min-width: 118px;
max-width: 118px;
height: 56px;
max-height: 56px;
overflow: hidden;
text-align: center;
border-bottom: 2px solid #dddddd;
}
.pink_color {
background-color: pink;
}
.table_wrapper {
position: relative;
}
.table_scroll {
height: 73vh;
overflow: auto;
}
.table_wrapper table {
width: 100%;
}
.table_wrapper table thead th .text {
position: absolute;
z-index: 2;
}
.tableFixHead
{
overflow: auto; height: 63vh;
}
.tableFixHead thead th
{
position: sticky; top: 0; z-index: 1;
}
@media only screen and (min-width: 1440px) {
.table_scroll {
height: 77vh;
overflow: auto;
}
}
</style>
<div style="padding-top: 16px;">
<div class="table_wrapper">
<div class="tableFixHead">
<table class="table">
<thead>
<th style="position: sticky; left: 0; z-index: 3;" class="text th"></th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
</thead>
<tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr>
<tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr>
<tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr><tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr><tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr><tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr><tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr>
</table>
</div>
</div>
</div>