Подтвердить что ты не робот

Просматриваемая только 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 обеспечивал горизонтальную прокрутку. В любом случае, мне не нужна горизонтальная прокрутка, так что это нормально, если решение не делает этого.

4b9b3361

Ответ 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