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

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

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

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

11 ответов

Решение

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

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

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

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

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

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

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

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

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

Если вы ориентируетесь на современные браузеры (в настоящее время все, кроме IE), вы можете использовать position:sticky, который не требует JS и не сломает макет таблицы. Также не требуется фиксированная ширина столбца для правильной работы.

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

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

Для нескольких строк заголовка вы можете использовать что-то вроде этого:

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 */
}

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

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

Поддержка браузера: https://caniuse.com/

Самый простой ответ только с использованием 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>

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

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

http://code.google.com/p/js-floating-table-headers/ (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');

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

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

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

Это действительно сложно иметь липкий заголовок на вашем столе. У меня было такое же требование, но с 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

Если вы используете полноэкранную таблицу, возможно, вас заинтересует настройка 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> 

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

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

Расстраивает то, что то, что прекрасно работает в одном браузере, не работает в других. Следующее работает в 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>

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

Другие вопросы по тегам