Заголовки таблиц HTML всегда видны в верхней части окна при просмотре большой таблицы

169

Я хотел бы иметь возможность «настроить» презентацию HTML-таблицы, чтобы добавить одну функцию: при прокрутке страницы вниз, чтобы таблица находилась на экране, но строки заголовков находились вне экрана, я бы хотел, чтобы заголовки оставались видимый в верхней части области просмотра.

Концептуально это будет похоже на функцию «стоп-панели» в Excel. Однако HTML-страница может содержать несколько таблиц, и я хотел бы, чтобы это происходило только для той таблицы, которая просматривается в данный момент, только пока она находится в поле зрения.

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

Крейг МакКуин
источник
ваша страница разработана с использованием таблиц? Разве нельзя сначала преобразовать его в div и оставить табличные данные одними для таблиц?
блокировка
6
я недавно написал плагин , который делает это: programmingdrunk.com/floatThead
mkoryak
1
В дополнение к популярному решению и производным от него ниже, плагин @mkoryak выше также неплох. Обязательно посмотрите на это тоже, прежде чем закончить "покупки".
DanO
Спасибо, Дэн :) У меня есть кое-какие
отличные
Я второй плагин @mkoryak floatThead - я смог быстро интегрировать его. Большое спасибо за плагин!
w5m

Ответы:

67

Посмотрите jQuery.floatThead ( доступны демоверсии ), который очень классный, может работать и с DataTables , и даже может работать внутри overflow: autoконтейнера.

Хенди ираван
источник
да, это работает с горизонтальной прокруткой, прокруткой окна, внутренней прокруткой и изменением размеров окна.
mkoryak
Не могли бы вы добавить скрипку с рабочим кодом? (Я знаю, что есть на сайте ...)
Мишель Айрес
12
Я построил огромную демо / документацию. Зачем тебе скрипка?
Мкоряк
5
@MustModify stackoverflow - не лучшее место, чтобы задавать мне вопросы. сообщить о проблеме на GitHub, даже если это просто вопрос о том, как заставить его работать. Я отвечу там обычно в течение дня. Вот заболеть наверно ответят чуть меньше года :)
mkoryak
1
@MustModify, чего бы ни стоило, ни один из классов в таблицах в примерах не уместен. Плагину не нужны никакие CSS или классы для работы, как говорят мои документы.
Мкоряк
135

Я сделал пробное решение, используя jQuery .

Посмотреть образец здесь.

Теперь я получил этот код в репозитории Mercurial Bitbucket . Основной файл есть tables.html.

Мне известна одна проблема с этим: если таблица содержит якоря и если вы открываете URL-адрес с указанным якорем в браузере, при загрузке страницы строка с якорем, вероятно, будет скрыта плавающим заголовком.

Обновление 2017-12-11: я вижу, что это не работает с текущими Firefox (57) и Chrome (63). Не уверен, когда и почему это перестало работать, или как это исправить. Но теперь я думаю, что принятый ответ Хенди Ираван выше.

Крейг МакКуин
источник
Мне это нужно для того, что я делаю. Отличная помощь, спасибо. С моим я не использовал окно, поскольку панель прокрутки была div внутри html. Так что мне пришлось изменить , floatingHeaderRow.css("top", Math.min(scrollTop - offset.top, $(this).height() - floatingHeaderRow.height()) + "px");чтобы , floatingHeaderRow.css("top", scrollTop + "px");как с кодом вы имели заголовок таблицы прыгал дальше вниз страницы , чтобы в конце концов исчезнуть со страницы.
Налум,
1
Я пытаюсь реализовать это в моей таблице. У меня проблема с шириной заголовка. Данные в строках являются значениями, взятыми из БД, так как они имеют произвольную длину. Перед прокруткой заголовки имеют свой автоматически наследуемый размер, но после прокрутки он изменяет размеры заголовков, чтобы обернуть вокруг имен заголовков, и, следовательно, имеет гораздо меньшую ширину, чтобы заголовки фактически не отслеживались поверх их соответствующих. колонка. Как я могу исправить эту проблему?
JonYork
Хм, я не уверен, основываясь на вашем описании. Я предлагаю 1) если возможно, показать пример в Интернете; 2) задать это как вопрос на StackOverflow.
Крейг МакКуин
@JonYork У меня была точно такая же проблема. Моя проблема заключалась в использовании <td> в заголовке вместо <th>, поэтому он не мог применить ширину каждого столбца к несуществующему <th> (см. // Copy cell widths from original headerЧасть кода). @Craig McQueen, пожалуйста, отредактируйте свой ответ, чтобы никто больше не делал эту ошибку.
aexl
@CraigMcQueen Когда я использую ваш потрясающий код (спасибо), он разбивается на вторую мою таблицу, которая находится за другой вкладкой (плагин вкладки jQuery). Есть предположения? Заголовок помещается в крайнее левое положение вместо столбцов местоположения. Но отлично работает на столе в первой вкладке jQuery.
Ричард Чак
68

Крейг, я немного усовершенствовал ваш код (среди прочего, он теперь использует position: fixed) и обернул его как плагин jQuery.

Попробуйте это здесь: http://jsfiddle.net/jmosbech/stFcx/

И получите источник здесь: https://github.com/jmosbech/StickyTableHeaders

jmosbech
источник
1
Хорошая идея сделать плагин jQuery. Пара вопросов: (1) Хорошо ли работает с горизонтальной прокруткой? (2) Как ведет себя, когда вы прокручиваете вниз, чтобы нижняя часть таблицы прокручивалась за верхнюю часть окна? Пример не позволяет тестировать эти случаи.
Крейг МакКуин,
Ваш пример jsfiddle отлично работает с tableorter, а код на github - нет. Вы должны были изменить код TableSorter?
ericslaw
Крейг, горизонтальная прокрутка не должна быть проблемой, так как заголовок перемещается как горизонтально, так и вертикально при прокрутке и изменении размера. Что касается вашего второго вопроса: заголовок скрыт, когда таблица покидает область просмотра.
Jmosbech
Эрик, это странно. Вы пытались открыть /demo/tablesorter.htm из Github? Я не модифицировал код TableSorter, но чтобы он работал, вам нужно применить плагин StickyTableHeader перед TableSorter.
Jmosbech
2
Горизонтальная прокрутка не совсем работает, после прокрутки на довольно большое расстояние жаба позиционируется дальше влево при прокрутке вне экрана, чем когда она обычно располагается как часть стола.
Натан Филлипс
16

Если вы ориентируетесь на современные css3-совместимые браузеры ( поддержка браузера: https://caniuse.com/#feat=css-sticky ), вы можете использовать его position:sticky, который не требует JS и не нарушит неправильное выравнивание таблицы. и тд того же столбца. Также не требуется фиксированная ширина столбца для правильной работы.

Пример для отдельной строки заголовка:

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

Для theads с 1 или 2 рядами вы можете использовать что-то вроде этого:

thead > :last-child th
{
    position: sticky;
    top: 30px; /* This is for all the the "th" elements in the second row, (in this casa is the last child element into the thead) */
}

thead > :first-child th
{
    position: sticky;
    top: 0px; /* This is for all the the "th" elements in the first child row */
}

Возможно, вам придется немного поиграть со свойством top последнего потомка, изменив количество пикселей в соответствии с высотой первой строки (+ поле + граница + отступы, если есть), поэтому вторая строка придерживается только вниз ниже первый.

Кроме того, оба решения работают, даже если у вас есть более одной таблицы на одной странице: thэлемент каждого из них становится липким, когда его верхняя позиция совпадает с указанным в определении css, и просто исчезает, когда вся таблица прокручивается вниз. Так что, если есть больше таблиц, все прекрасно работают одинаково.

Зачем использовать последний ребенок до и first-child после в css?

Поскольку правила CSS отображаются браузером в том же порядке, в каком вы их записываете в файл CSS, и из-за этого, если у вас есть только 1 строка в элементе thead, первая строка одновременно является последней строкой, а правило first-child необходимо переопределить последний ребенок. Если нет, у вас будет смещение строки в 30 пикселей от верхнего поля, которое, я полагаю, вам не нужно.

Известная проблема position: sticky состоит в том, что она не работает с элементами thead или строками таблицы: вы должны использовать th-элементы. Эта проблема будет решена в будущих версиях браузера.

Вилли Вонка
источник
Первый пример не работает в Firefox (61). Однако, если позиция закреплена на thead, это делает.
EH
1
Вы могли бы сделать, thead tr+tr thчтобы предназначаться для второго ряда.
Teepeemm
5

Возможные альтернативы

JS-плавающей таблицы-заголовки

JS-плавающей таблицы-заголовки (Google Code)

В Друпале

У меня есть сайт Drupal 6. Я был на странице администратора "Модули", и заметил, что таблицы имеют именно эту функцию!

Глядя на код, кажется, что он реализован с помощью файла с именем tableheader.js. Это применяет функцию на всех таблицах с классом sticky-enabled.

Для сайта Drupal я бы хотел использовать этот tableheader.jsмодуль как есть для пользовательского контента. tableheader.jsкажется, не присутствует на страницах контента пользователя в Drupal. Я опубликовал сообщение на форуме, чтобы спросить, как изменить тему Drupal, чтобы она была доступна. Согласно ответу, tableheader.jsможет быть добавлен в тему Drupal, используя следующие drupal_add_js()темы template.php:

drupal_add_js('misc/tableheader.js', 'core');
Крейг МакКуин
источник
Ваша ссылка на Google Code была очень полезна для меня, спасибо.
Вилюс Гайделис
5

Я столкнулся с этой проблемой совсем недавно. К сожалению, мне пришлось сделать 2 таблицы, одну для заголовка и одну для тела. Это, вероятно, не самый лучший подход, но здесь идет:

<html>
<head>
    <title>oh hai</title>
</head>
<body>
    <table id="tableHeader">
        <tr>
            <th style="width:100px; background-color:#CCCCCC">col header</th>
            <th style="width:100px; background-color:#CCCCCC">col header</th>
        </tr>
    </table>
    <div style="height:50px; overflow:auto; width:250px">
        <table>
            <tr>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data1</td>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data1</td>
            </tr>
            <tr>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data2</td>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data2</td>
            </tr>
        </table>
    </div>
</body>
</html>

Это сработало для меня, это, вероятно, не элегантный способ, но это работает. Я буду исследовать, чтобы увидеть, могу ли я сделать что-то лучше, но это позволяет использовать несколько таблиц.

Перейдите к разделу « Переполнение», чтобы узнать, подходит ли он вам.

Габ Ройер
источник
Хм не работает, я постараюсь это исправить, но подход остается, вы должны использовать переполнение: auto proprety
Габ Ройер
Я ценю ваше решение и его простоту, однако в своем вопросе я сказал: «Примечание: я видел одно решение, в котором область данных таблицы сделана прокручиваемой, а заголовки не прокручиваются. Это не то решение, которое я ищу».
Крейг МакКуин
@GabRoyer Страница w3school, на которую вы ссылались, не существует.
Фархан
Кажется, они это перенесли. Исправлено
Габ Ройер
Другая проблема этого подхода заключается в том, что если вам нужно адаптировать некоторые столбцы к другому контенту, вы рискуете нарушить их выравнивание с соответствующим заголовком столбца. ИМХО, лучше столкнуться с этой проблемой с подходом, который позволяет своего рода динамическое управление контентом, который сохраняет идеальное выравнивание столбцов и относительных заголовков. Так что ИМХО позиция = липкий путь.
Вилли Вонка
3

Это действительно сложная вещь - иметь липкий заголовок на столе. У меня было такое же требование, но с asp: GridView а затем я обнаружил, что действительно думал, что у gridview есть липкий заголовок. Есть много доступных решений, и мне потребовалось 3 дня, чтобы попробовать все решения, но ни одно из них не могло удовлетворить.

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

С некоторыми решениями у меня также возникла проблема перекрытия заголовка с первыми несколькими строками тела, из-за чего строки тела скрывались за плавающим заголовком.

Так что теперь мне пришлось реализовать свою собственную логику, чтобы достичь этого, хотя я также не считаю это идеальным решением, но это также может быть полезно для кого-то,

Ниже приведен пример таблицы.

<div class="table-holder">
        <table id="MyTable" cellpadding="4" cellspacing="0" border="1px" class="customerTable">
            <thead>
                <tr><th>ID</th><th>First Name</th><th>Last Name</th><th>DOB</th><th>Place</th></tr>
            </thead>
            <tbody>
                <tr><td>1</td><td>Customer1</td><td>LastName</td><td>1-1-1</td><td>SUN</td></tr>
                <tr><td>2</td><td>Customer2</td><td>LastName</td><td>2-2-2</td><td>Earth</td></tr>
                <tr><td>3</td><td>Customer3</td><td>LastName</td><td>3-3-3</td><td>Mars</td></tr>
                <tr><td>4</td><td>Customer4</td><td>LastName</td><td>4-4-4</td><td>Venus</td></tr>
                <tr><td>5</td><td>Customer5</td><td>LastName</td><td>5-5-5</td><td>Saturn</td></tr>
                <tr><td>6</td><td>Customer6</td><td>LastName</td><td>6-6-6</td><td>Jupitor</td></tr>
                <tr><td>7</td><td>Customer7</td><td>LastName</td><td>7-7-7</td><td>Mercury</td></tr>
                <tr><td>8</td><td>Customer8</td><td>LastName</td><td>8-8-8</td><td>Moon</td></tr>
                <tr><td>9</td><td>Customer9</td><td>LastName</td><td>9-9-9</td><td>Uranus</td></tr>
                <tr><td>10</td><td>Customer10</td><td>LastName</td><td>10-10-10</td><td>Neptune</td></tr>
            </tbody>
        </table>
    </div>

Примечание . Таблица помещается в DIV с атрибутом класса, равным «table-holder».

Ниже приведен скрипт JQuery, который я добавил в заголовок своей HTML-страницы.

<script src="../Scripts/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="../Scripts/jquery-ui.min.js" type="text/javascript"></script>
<script type="text/javascript">
    $(document).ready(function () {
        //create var for table holder
        var originalTableHolder = $(".table-holder");
        // set the table holder's with
        originalTableHolder.width($('table', originalTableHolder).width() + 17);
        // Create a clone of table holder DIV
        var clonedtableHolder = originalTableHolder.clone();

        // Calculate height of all header rows.
        var headerHeight = 0;
        $('thead', originalTableHolder).each(function (index, element) {
            headerHeight = headerHeight + $(element).height();
        });

        // Set the position of cloned table so that cloned table overlapped the original
        clonedtableHolder.css('position', 'relative');
        clonedtableHolder.css('top', headerHeight + 'px');

        // Set the height of cloned header equal to header height only so that body is not visible of cloned header
        clonedtableHolder.height(headerHeight);
        clonedtableHolder.css('overflow', 'hidden');

        // reset the ID attribute of each element in cloned table
        $('*', clonedtableHolder).each(function (index, element) {
            if ($(element).attr('id')) {
                $(element).attr('id', $(element).attr('id') + '_Cloned');
            }
        });

        originalTableHolder.css('border-bottom', '1px solid #aaa');

        // Place the cloned table holder before original one
        originalTableHolder.before(clonedtableHolder);
    });
</script>

и, наконец, ниже класс CSS для немного раскраски.

.table-holder
{
    height:200px;
    overflow:auto;
    border-width:0px;    
}

.customerTable thead
{
    background: #4b6c9e;        
    color:White;
}

Таким образом, вся идея этой логики состоит в том, чтобы поместить таблицу в div держателя таблицы и создать клон этого держателя на стороне клиента при загрузке страницы. Теперь скройте тело таблицы внутри держателя клона и поместите оставшуюся часть заголовка в исходный заголовок.

То же решение также работает для asp: gridview, вам нужно добавить еще два шага для достижения этого в gridview,

  1. В событии OnPrerender объекта gridview на веб-странице установите для раздела таблицы строки заголовка значение TableHeader.

    if (this.HeaderRow != null)
    {
        this.HeaderRow.TableSection = TableRowSection.TableHeader;
    }
  2. И заверните свою сетку в <div class="table-holder"></div>.

Примечание : если ваш заголовок имеет интерактивные элементы управления, вам может понадобиться добавить еще несколько сценариев jQuery для передачи событий, вызванных в клонированном заголовке, в исходный заголовок. Этот код уже доступен в плагине jQuery sticky-header, созданном jmosbech

pgcan
источник
+1 за хорошее усилие, но для больших таблиц с большим количеством данных, довольно плохо клонировать все это ... Я представляю, что это
удвоило
2

Использование display: fixedв theadразделе должно работать, но для того, чтобы оно работало только с текущей таблицей, вам понадобится помощь JavaScript. И это будет непросто, потому что нужно будет определить места прокрутки и расположение элементов относительно области просмотра, что является одной из основных областей несовместимости браузера.

Посмотрите на популярные JavaScript-фреймворки (jQuery, MooTools, YUI и т. Д.), Чтобы узнать, могут ли они либо делать то, что вы хотите, либо облегчать выполнение того, что вы хотите.

staticsan
источник
1
Спасибо за совет. Я сделал решение, используя jQuery - см. Мой ответ.
Крейг МакКуин
Я попробовал это и думаю, что вы имели в виду положение, а не показ, но ни тот, ни другой не сработали.
ericslaw
@ericslaw Ack - да, я имел в виду position: fixed. Извините, это не сработало в Chrome.
staticsan
испортил мой заголовок, игнорируя стили ширины
pavel_kazlou
2

Если вы используете полноэкранную таблицу, вас может заинтересовать настройка отображения th: исправлено; и сверху: 0; или попробуйте очень похожий подход через CSS.

Обновить

Просто быстро создайте рабочее решение с помощью iframes (html4.0). Этот пример НЕ соответствует стандарту, однако вы легко сможете это исправить:

outer.html

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">   
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">     
    <head>      
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
        <title>Outer</title>
  <body>
    <iframe src="test.html" width="200" height="100"></iframe>
    </body>
</html> 

test.html

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">   
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">     
    <head>      
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
        <title>Floating</title>
    <style type="text/css">
      .content{
        position:relative; 
      }

      thead{
        background-color:red;
        position:fixed; 
        top:0;
      }
    </style>
  <body>
    <div class="content">      
      <table>
        <thead>
          <tr class="top"><td>Title</td></tr>
        </head>
        <tbody>
          <tr><td>a</td></tr>
          <tr><td>b</td></tr>
          <tr><td>c</td></tr>
          <tr><td>d</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
        </tbody>
      </table>
    </div>
    </body>
</html> 
merkuro
источник
@ a_m0d, правда ... но запрос звучит очень запутанно. Либо мы неправильно это понимаем, либо спрашивающий не совсем понимает, чего он хочет.
Сэмпсон
Вот еще одно решение с использованием некоторого javascript imaputz.com/cssStuff/bigFourVersion.html
merkuro
2

Самый простой ответ только с использованием CSS: D !!!

table {
  /* Not required only for visualizing */
  border-collapse: collapse;
  width: 100%;
}

table thead tr th {
  /* you could also change td instead th depending your html code */
  background-color: green;
  position: sticky;
  z-index: 100;
  top: 0;
}

td {
  /* Not required only for visualizing */
  padding: 1em;
}
<table>
  <thead>
    <tr>
      <th>Col1</th>
      <th>Col2</th>
      <th>Col3</th>
    </tr>
  </thead>
  <tbody>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>david</td>
       <td>castro</td>
       <td>rocks!</td>
     </tr>
  </tbody>
</table>

Дэвид Кастро
источник
1
Спасибо Дэвид, это самый хороший подход, который я нашел в этом вопросе
Томаш Смыковски
0

То подтверждение концепции, которое вы сделали, было великолепно! Однако я также нашел этот плагин jQuery, который, кажется, работает очень хорошо. Надеюсь, поможет!

Marco
источник
Похоже, что он реализует другую функцию . Как я сказал в своем первоначальном вопросе: «Примечание: я видел одно решение, в котором область данных таблицы сделана прокручиваемой, а заголовки не прокручиваются. Это не то решение, которое я ищу».
Крейг МакКуин
2
Попробованный вами плагин только что испортил мой заголовок таблицы. Не смог его использовать.
pavel_kazlou
0

Расстраивает то, что то, что прекрасно работает в одном браузере, не работает в других. Следующее работает в Firefox, но не в Chrome или IE:

<table width="80%">

 <thead>

 <tr>
  <th>Column 1</th>
  <th>Column 2</th>
  <th>Column 3</th>
 </tr>

 </thead>

 <tbody style="height:50px; overflow:auto">

  <tr>
    <td>Cell A1</td>
    <td>Cell B1</td>
    <td>Cell C1</td>
  </tr>

  <tr>
    <td>Cell A2</td>
    <td>Cell B2</td>
    <td>Cell C2</td>
  </tr>

  <tr>
    <td>Cell A3</td>
    <td>Cell B3</td>
    <td>Cell C3</td>
  </tr>

 </tbody>

</table>
Питер Доу
источник
4
Я пробую это в Firefox 8.0, и это, похоже, ничего не делает. Что оно делает?
Крейг МакКуин
Что такое px? Является ли это тем устаревшим устройством, которое использовалось людьми 90-х годов, когда использовалось устройство отображения с разрешением 72 dpi?
ceving
Я согласен: это очень расстраивает, к сожалению, разработчики браузеров не соблюдают стандарты в каждой ситуации ... а несколько лет назад было еще хуже! Теперь некоторые проблемы были решены, и все больше браузеров ведут себя более стандартизированным образом, но еще многое предстоит сделать: будем надеяться и молиться :-)
willy wonka