Заголовок таблицы остается фиксированным сверху, когда пользователь прокручивает его вне поля зрения с помощью jQuery - PullRequest
134 голосов
/ 17 января 2011

Я пытаюсь создать HTML-таблицу, в которой верхний колонтитул будет оставаться наверху страницы, когда И ТОЛЬКО, когда пользователь прокручивает его вне поля зрения.Например, таблица может быть на 500 пикселей ниже страницы, как мне сделать так, чтобы, если пользователь прокручивает заголовок вне поля зрения (браузер как-то обнаруживает, что его больше нет в окне Windows), он останется наверху?Кто-нибудь может дать мне решение Javascript для этого?

<table>
  <thead>
    <tr>
      <th>Col1</th>
      <th>Col2</th>
      <th>Col3</th>
    </tr>
  </thead>
  <tbody>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
  </tbody>
</table>

Так что в приведенном выше примере я хочу, чтобы <thead> прокручивал страницу, если она выходит из поля зрения.

ВАЖНО: Я НЕ ищу решение, в котором <tbody> будет иметь полосу прокрутки (переполнение: авто).

Ответы [ 24 ]

128 голосов
/ 17 января 2011

Вы могли бы сделать что-то подобное, нажав на обработчик событий scroll на window и используя другой table с фиксированной позицией для отображения заголовка вверху страницы.

HTML:

<table id="header-fixed"></table>

CSS:

#header-fixed {
    position: fixed;
    top: 0px; display:none;
    background-color:white;
}

JavaScript:

var tableOffset = $("#table-1").offset().top;
var $header = $("#table-1 > thead").clone();
var $fixedHeader = $("#header-fixed").append($header);

$(window).bind("scroll", function() {
    var offset = $(this).scrollTop();

    if (offset >= tableOffset && $fixedHeader.is(":hidden")) {
        $fixedHeader.show();
    }
    else if (offset < tableOffset) {
        $fixedHeader.hide();
    }
});

Показывает заголовок стола, когда пользователь прокручивает его достаточно далеко, чтобы скрыть исходный заголовок стола. Он снова будет скрыт, когда пользователь снова прокрутит страницу вверх.

Рабочий пример: http://jsfiddle.net/andrewwhitaker/fj8wM/

43 голосов
/ 02 мая 2011

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

Решение, которое я придумал, - взломать. Он состоит из дублирования всей таблицы, затем скрытия всего, кроме заголовка, и создания фиксированной позиции.

HTML

<div id="table-container">
<table id="maintable">
    <thead>
        <tr>
            <th>Col1</th>
            <th>Col2</th>
            <th>Col3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
        <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
        <tr>
            <td>info</td>
            <td>some really long line here instead</td>
            <td>info</td>
        </tr>
        <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
                <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
                <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
        <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
    </tbody>
</table>
<div id="bottom_anchor"></div>
</div>

CSS

body { height: 1000px; }
thead{
    background-color:white;
}

1011 * Javascript * function moveScroll(){ var scroll = $(window).scrollTop(); var anchor_top = $("#maintable").offset().top; var anchor_bottom = $("#bottom_anchor").offset().top; if (scroll>anchor_top && scroll<anchor_bottom) { clone_table = $("#clone"); if(clone_table.length == 0){ clone_table = $("#maintable").clone(); clone_table.attr('id', 'clone'); clone_table.css({position:'fixed', 'pointer-events': 'none', top:0}); clone_table.width($("#maintable").width()); $("#table-container").append(clone_table); $("#clone").css({visibility:'hidden'}); $("#clone thead").css({'visibility':'visible','pointer-events':'auto'}); } } else { $("#clone").remove(); } } $(window).scroll(moveScroll); Смотрите здесь: http://jsfiddle.net/QHQGF/7/ Редактировать: обновлен код, чтобы thead мог получать события указателя (чтобы кнопки и ссылки в заголовке все еще работали). Это исправляет проблему, о которой сообщили luhfluh и Joe M. Новый jsfiddle здесь: http://jsfiddle.net/cjKEx/

30 голосов
/ 04 мая 2017

Чистый CSS (без поддержки IE11):

table th {
    position: -webkit-sticky; // this is for all Safari (Desktop & iOS), not for Chrome
    position: sticky;
    top: 0;
    z-index: 5;
    background: #fff;
}
25 голосов
/ 18 марта 2012

Мне удалось исправить проблему с изменением ширины столбца. Я начал с решения Эндрю выше (большое спасибо!), А затем добавил один маленький цикл, чтобы установить ширину клонированных ТД:

$("#header-fixed td").each(function(index){
    var index2 = index;
    $(this).width(function(index2){
        return $("#table-1 td").eq(index).width();
    });
});

Это решает проблему без клонирования всей таблицы и скрытия тела. Я новичок в JavaScript и jQuery (и для переполнения стека), поэтому любые комментарии приветствуются.

23 голосов
/ 06 сентября 2013

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

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

Вот несколько примеров / документов:
http://mkoryak.github.io/floatThead/

15 голосов
/ 10 апреля 2014

На сегодняшний день это лучшее решение, которое я нашел для фиксированного заголовка таблицы.

ОБНОВЛЕНИЕ 5/11: Исправлена ​​ошибка горизонтальной прокрутки, как указано Керри Джонсон

Codepen: https://codepen.io/josephting/pen/demELL

;(function($) {
   $.fn.fixMe = function() {
      return this.each(function() {
         var $this = $(this),
            $t_fixed;
         function init() {
            $this.wrap('<div class="container" />');
            $t_fixed = $this.clone();
            $t_fixed.find("tbody").remove().end().addClass("fixed").insertBefore($this);
            resizeFixed();
         }
         function resizeFixed() {
           $t_fixed.width($this.outerWidth());
            $t_fixed.find("th").each(function(index) {
               $(this).css("width",$this.find("th").eq(index).outerWidth()+"px");
            });
         }
         function scrollFixed() {
            var offsetY = $(this).scrollTop(),
            offsetX = $(this).scrollLeft(),
            tableOffsetTop = $this.offset().top,
            tableOffsetBottom = tableOffsetTop + $this.height() - $this.find("thead").height(),
            tableOffsetLeft = $this.offset().left;
            if(offsetY < tableOffsetTop || offsetY > tableOffsetBottom)
               $t_fixed.hide();
            else if(offsetY >= tableOffsetTop && offsetY <= tableOffsetBottom && $t_fixed.is(":hidden"))
               $t_fixed.show();
            $t_fixed.css("left", tableOffsetLeft - offsetX + "px");
         }
         $(window).resize(resizeFixed);
         $(window).scroll(scrollFixed);
         init();
      });
   };
})(jQuery);

$(document).ready(function(){
   $("table").fixMe();
   $(".up").click(function() {
      $('html, body').animate({
      scrollTop: 0
   }, 2000);
 });
});
body{
  font:1.2em normal Arial,sans-serif;
  color:#34495E;
}

h1{
  text-align:center;
  text-transform:uppercase;
  letter-spacing:-2px;
  font-size:2.5em;
  margin:20px 0;
}

.container{
  width:90%;
  margin:auto;
}

table{
  border-collapse:collapse;
  width:100%;
}

.blue{
  border:2px solid #1ABC9C;
}

.blue thead{
  background:#1ABC9C;
}

.purple{
  border:2px solid #9B59B6;
}

.purple thead{
  background:#9B59B6;
}

thead{
  color:white;
}

th,td{
  text-align:center;
  padding:5px 0;
}

tbody tr:nth-child(even){
  background:#ECF0F1;
}

tbody tr:hover{
background:#BDC3C7;
  color:#FFFFFF;
}

.fixed{
  top:0;
  position:fixed;
  width:auto;
  display:none;
  border:none;
}

.scrollMore{
  margin-top:600px;
}

.up{
  cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>&darr; SCROLL &darr;</h1>
<table class="blue">
  <thead>
    <tr>
      <th>Colonne 1</th>
      <th>Colonne 2</th>
      <th>Colonne 3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Non</td>
      <td>MaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
       <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
  </tbody>
</table>

<h1 class="scrollMore">&darr; SCROLL MORE &darr;</h1>
<table class="purple">
  <thead>
    <tr>
      <th>Colonne 1</th>
      <th>Colonne 2</th>
      <th>Colonne 3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
       <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
       <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
  </tbody>
</table>
<h1 class="up scrollMore">&uarr; UP &uarr;</h1>
7 голосов
/ 11 сентября 2013

Лучшее решение - использовать этот плагин jquery:

https://github.com/jmosbech/StickyTableHeaders

Этот плагин отлично сработал для нас, и мы попробовали много других решений. Мы протестировали его в IE, Chrome и Firefox

4 голосов
/ 07 ноября 2013

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

http://plugins.jquery.com/StickyTableHeaders/

Информация об использовании здесь: https://github.com/jmosbech/StickyTableHeaders

4 голосов
/ 04 февраля 2019

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

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

table thead tr th {
  /* Important */
  background-color: red;
  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>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
  </tbody>
</table>

Поскольку не требуется JavaScript, это значительно упрощает ситуацию.По сути, вам нужно сосредоточиться на втором CSS-правиле, которое содержит условия для обеспечения того, чтобы заголовок таблицы оставался верхним независимо от места прокрутки.правила в деталях.position предназначено для указания браузеру, что объект head, его строка и его ячейки должны придерживаться вершины.Это обязательно должно сопровождаться top, которое указывает браузеру, что голова будет придерживаться верхней части страницы или области просмотра.Кроме того, вы можете добавить z-index, чтобы содержимое заголовка всегда оставалось сверху.

Цвет фона служит просто для иллюстрации сути.Вам не нужно использовать какой-либо дополнительный JavaScript, чтобы получить этот эффект.Это поддерживается в большинстве основных браузеров после 2016 года.

3 голосов
/ 17 февраля 2014

Ну, после просмотра всех доступных решений я написал плагин, который может заморозить любую строку (не только th) вверху страницы или контейнера.Это очень просто и очень быстро.Не стесняйтесь использовать его.http://maslianok.github.io/stickyRows/

...