2017-02-02 2 views
28

Я искал в Интернете способ создания таблицы с фиксированными (замороженными) столбцами и заголовком. Похоже, я наконец нашел решение и внедрил его в соответствии с моими потребностями.HTML-таблица с фиксированными (замороженными) столбцами и заголовками

Оригинальная скрипка here.

Here - мое модифицированное решение. Я протестировал его в Chrome (версия: 55.0.2883.87 м) и Firefox (версия: 51.0.1).

Проблема в том, что она работает не полностью в IE (версия: 11.0.9600.18427). Во время горизонтальной прокрутки прокручивается и замороженная часть заголовка. Может ли кто-нибудь помочь мне заставить его работать в IE? И еще один вопрос: безопасен ли подход? Я имею в виду, если он использует какое-то неуказанное поведение, то некоторые из будущих браузеров или даже некоторых современных браузеров могут неправильно отображать мою таблицу, и лучше использовать безопасное решение с несколькими разными таблицами и синхронизировать положение и строки прокрутки высота. UPD: еще один вопрос: как сделать эту работу стабильной на мобильных устройствах?

Вот код, который демонстрирует подход:

$(document).ready(function() { 
 
    $('tbody').scroll(function(e) { //detect a scroll event on the tbody 
 
    \t /* 
 
    Setting the thead left value to the negative valule of tbody.scrollLeft will make it track the movement 
 
    of the tbody element. Setting an elements left value to that of the tbody.scrollLeft left makes it maintain \t \t \t it's relative position at the left of the table.  
 
    */ 
 
    $('thead').css("left", -$("tbody").scrollLeft()); //fix the thead relative to the body scrolling 
 
    $('thead th:nth-child(1)').css("left", $("tbody").scrollLeft()); //fix the first cell of the header 
 
    $('tbody td:nth-child(1)').css("left", $("tbody").scrollLeft()); //fix the first column of tdbody 
 
    }); 
 
});
.container { 
 
    height:200px; 
 
    width:400px; 
 
    overflow: hidden; 
 
} 
 

 
table { 
 
    position: relative; 
 
    background-color: #aaa; 
 
    border-collapse: collapse; 
 
table-layout: fixed; 
 
display: flex; 
 
flex-direction: column; 
 
height: 100%; 
 
width: 100%; 
 
} 
 

 

 
/*thead*/ 
 
thead { 
 
    position: relative; 
 
    display: block; /*seperates the header from the body allowing it to be positioned*/ 
 
} 
 

 
thead th { 
 
    background-color: #99a; 
 
    min-width: 120px; 
 
    border: 1px solid #222; 
 
} 
 

 
thead th:nth-child(1) {/*first cell in the header*/ 
 
    position: relative; 
 
    background-color: #88b; 
 
} 
 

 

 
/*tbody*/ 
 
tbody { 
 
    flex: 1; 
 
    position: relative; 
 
    display: block; /*seperates the tbody from the header*/ 
 
    overflow: auto; 
 
} 
 

 
tbody td { 
 
    background-color: #bbc; 
 
    min-width: 120px; 
 
    border: 1px solid #222; 
 
} 
 

 
tbody tr td:nth-child(1) { /*the first cell in each tr*/ 
 
    position: relative; 
 
    background-color: #99a; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<body> 
 
<div class="container"> 
 

 
    <table> 
 
    <thead> 
 
     <tr> 
 
     <th>Name<br/>123</th> 
 
     <th>Town</th> 
 
     <th>County</th> 
 
     <th>Age</th> 
 
     <th>Profession</th> 
 
     <th>Anual Income</th> 
 
     <th>Matital Status</th> 
 
     <th>Children</th> 
 
     </tr> 
 
     <tr> 
 
     <th>Name</th> 
 
     <th>Town</th> 
 
     <th>County</th> 
 
     <th>Age<br/>123<br/>321</th> 
 
     <th>Profession</th> 
 
     <th>Anual Income</th> 
 
     <th>Matital Status</th> 
 
     <th>Children</th> 
 
     </tr> 
 
    </thead> 
 
    <tbody> 
 
     <tr> 
 
     <td>John Smith</td> 
 
     <td>Macelsfield</td> 
 
     <td>Cheshire<br/>123</td> 
 
     <td>52</td> 
 
     <td>Brewer</td> 
 
     <td>£47,000</td> 
 
     <td>Married</td> 
 
     <td>2</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Jenny Jones<br/>123<br/>312</td> 
 
     <td>Threlkeld</td> 
 
     <td>Cumbria</td> 
 
     <td>34</td> 
 
     <td>Shepherdess</td> 
 
     <td>£28,000</td> 
 
     <td>Single</td> 
 
     <td>0</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Peter Frampton</td> 
 
     <td>Avebury</td> 
 
     <td>Wiltshire</td> 
 
     <td>57</td> 
 
     <td>Musician</td> 
 
     <td>£124,000</td> 
 
     <td>Married</td> 
 
     <td>4</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Simon King</td> 
 
     <td>Malvern</td> 
 
     <td>Worchestershire</td> 
 
     <td>48</td> 
 
     <td>Naturalist</td> 
 
     <td>£65,000</td> 
 
     <td>Married</td> 
 
     <td>2</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Lucy Diamond</td> 
 
     <td>St Albans</td> 
 
     <td>Hertfordshire</td> 
 
     <td>67</td> 
 
     <td>Pharmasist</td> 
 
     <td>Retired</td> 
 
     <td>Married</td> 
 
     <td>3</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Austin Stevenson</td> 
 
     <td>Edinburgh</td> 
 
     <td>Lothian </td> 
 
     <td>36</td> 
 
     <td>Vigilante</td> 
 
     <td>£86,000</td> 
 
     <td>Single</td> 
 
     <td>Unknown</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Wilma Rubble</td> 
 
     <td>Bedford</td> 
 
     <td>Bedfordshire</td> 
 
     <td>43</td> 
 
     <td>Housewife</td> 
 
     <td>N/A</td> 
 
     <td>Married</td> 
 
     <td>1</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Kat Dibble</td> 
 
     <td>Manhattan</td> 
 
     <td>New York</td> 
 
     <td>55</td> 
 
     <td>Policewoman</td> 
 
     <td>$36,000</td> 
 
     <td>Single</td> 
 
     <td>1</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Henry Bolingbroke</td> 
 
     <td>Bolingbroke</td> 
 
     <td>Lincolnshire</td> 
 
     <td>45</td> 
 
     <td>Landowner</td> 
 
     <td>Lots</td> 
 
     <td>Married</td> 
 
     <td>6</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Alan Brisingamen</td> 
 
     <td>Alderley</td> 
 
     <td>Cheshire</td> 
 
     <td>352</td> 
 
     <td>Arcanist</td> 
 
     <td>A pile of gems</td> 
 
     <td>Single</td> 
 
     <td>0</td> 
 
     </tr> 
 
    </tbody> 
 
    </table> 
 
    
 
</div> 
 
</body>

+0

попробуйте это thead th: nth-child (1) {/ * первая ячейка в заголовке */ позиция: относительная; background-color: # 88b; дисплей: блок; } – Singh87

+0

@ Singh87, это помогает ячейке оставаться на месте во время прокрутки, но клетки теряют способность автоматически регулировать ее высоту. –

+0

Я бы предложил рассмотреть DataTables - https://datatables.net/extensions/fixedcolumns/examples/initialisation/left_right_columns.html. Он поддерживает замораживание строк. –

ответ

8

Это очень странно. Оказывается, что проблематично код этой строки:

$('thead').css("left", -$("tbody").scrollLeft()); //fix the thead relative to the body scrolling 

Похоже, IE11 обрабатывает относительное расположение вложенных элементов по-разному (чем Chrome и другие браузеры). В этом случае вы позиционируете thead с относительным позиционированием со смещением. Вы также позиционируете thead th (это дети) со смещением и относительным позиционированием. Хром, как представляется, позиционирует thead относительно table, а затем позиционирует th относительно thead. IE11, с другой стороны, позиционирует thead относительно table, а затем th просто наследует это же позиционирование независимо от его собственного позиционирования.

Исправление для этого было бы следующим: на IE11 обрабатывать позиционирование по-разному для thead. Вместо того, чтобы устанавливать позиционирование на родительском thead, установите позиционирование на элементах thead th. Таким образом, ваш первый столбец не будет «принудительным» наследовать позиционирование thead (в IE).

$(document).ready(function() { 
    var isIE11 = !!navigator.userAgent.match(/Trident.*rv\:11\./); 
    var customScroller; 
    if (isIE11) 
    customScroller = function() { 
     $('thead th').css("left", -$("tbody").scrollLeft()); //if using IE11, fix the th element 
    }; 
    else 
    customScroller = function() { 
     $('thead').css("left", -$("tbody").scrollLeft()); //if not using IE11, fix the thead element 
    }; 

    $('tbody').scroll(function(e) { //detect a scroll event on the tbody 
    /* 
    Setting the thead left value to the negative valule of tbody.scrollLeft will make it track the movement 
    of the tbody element. Setting an elements left value to that of the tbody.scrollLeft left makes it maintain    it's relative position at the left of the table.  
    */ 
    customScroller(); //fix the thead relative to the body scrolling 
    $('thead th:nth-child(1)').css("left", $("tbody").scrollLeft()); 
//fix the first cell of the header 
    $('tbody td:nth-child(1)').css("left", $("tbody").scrollLeft()); //fix the first column of tdbody 
    }); 
}); 

Вот полный пример с вашим кодом, показывая различные расправы на основе браузера:

https://jsfiddle.net/8tx4xfhx/5/

Alsol, было бы неплохо, чтобы увидеть, если кто заметил это поведение раньше. Похоже, что IE11 обрабатывает вложенное относительное позиционирование по-другому, чем другие браузеры. Есть ли спецификация где-то, что определяет, какой должен быть стандарт? Должно ли относительное позиционирование быть унаследованным, как IE? Или должно относительное позиционирование всегда относиться к родительскому? Я бы подумал, что последний. Однако необходимо учитывать соображения производительности.

+0

Спасибо, Мэтт. Можете ли вы сказать что-нибудь о второй части вопроса: безопасно ли использовать такое решение? Он использует 'display: flex' для'

'и так далее. Я боюсь, что он содержит некоторое неуказанное поведение, и решение не будет работать в некоторых браузерах. –

+0

Hi Artem. На самом деле, я оставил «display: flex» там, потому что думал, что вы можете использовать это для чего-то другого. Это можно сделать без этого атрибута. Здесь проверьте это: https://jsfiddle.net/mspinks/wLren00o/2/. Это использует внешний скроллер контейнера. Я думаю, что это лучшее, более надежное решение. И он не использует «flex». –

+0

Спасибо. Как насчет 'display: block' для' thead' и 'tbody'? Я попробовал решение, и он работает достаточно хорошо, даже в IE. Но в мобильном браузере прокрутка не так гладко, можно видеть, что замороженная часть на самом деле не остается все время на одном месте. Что-то с этим связано? –

6

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

Я попытался воспроизвести ваш код здесь с помощью только css-решения.

Я работаю над маком, поэтому не имею доступа к IE. Пожалуйста, проверьте, работает ли он на одном уровне.

Обновлено скрипку: https://jsfiddle.net/nashcheez/bzuasLcz/81/

см Код:

table { 
 
    position: relative; 
 
    width: 700px; 
 
    background-color: #aaa; 
 
    overflow: hidden; 
 
    border-collapse: collapse; 
 
} 
 
/*thead*/ 
 

 
thead { 
 
    position: relative; 
 
    display: block; 
 
    /*seperates the header from the body allowing it to be positioned*/ 
 
    width: 700px; 
 
    overflow: visible; 
 
} 
 
thead th { 
 
    background-color: #99a; 
 
    min-width: 120px; 
 
    height: 36px; 
 
    min-height: 36px; 
 
    border: 1px solid #222; 
 
} 
 
thead th:nth-child(1) { 
 
    /*first cell in the header*/ 
 
    position: relative; 
 
    display: block; 
 
    background-color: #88b; 
 
} 
 
tbody tr td:nth-child(2) { 
 
    margin-left: 124px; 
 
    display: block; 
 
} 
 
/*tbody*/ 
 

 
tbody { 
 
    display: block; 
 
    width: 700px; 
 
    height: 239px; 
 
    overflow-y: auto; 
 
} 
 
tbody td { 
 
    background-color: #bbc; 
 
    min-width: 120px; 
 
    border: 1px solid #222; 
 
    height: 36px; 
 
    min-height: 36px; 
 
} 
 
tbody tr td:nth-child(1) { 
 
    /*the first cell in each tr*/ 
 
    position: absolute; 
 
    display: inline-block; 
 
    background-color: #99a; 
 
}
<body> 
 
    <table> 
 
    <thead> 
 
     <tr> 
 
     <th>Name</th> 
 
     <th>Town</th> 
 
     <th>County</th> 
 
     <th>Age</th> 
 
     <th>Profession</th> 
 
     <th>Anual Income</th> 
 
     <th>Matital Status</th> 
 
     <th>Children</th> 
 
     </tr> 
 
    </thead> 
 
    <tbody> 
 
     <tr> 
 
     <td>John Smith</td> 
 
     <td>Macelsfield</td> 
 
     <td>Cheshire</td> 
 
     <td>52</td> 
 
     <td>Brewer</td> 
 
     <td>£47,000</td> 
 
     <td>Married</td> 
 
     <td>2</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Jenny Jones</td> 
 
     <td>Threlkeld</td> 
 
     <td>Cumbria</td> 
 
     <td>34</td> 
 
     <td>Shepherdess</td> 
 
     <td>£28,000</td> 
 
     <td>Single</td> 
 
     <td>0</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Peter Frampton</td> 
 
     <td>Avebury</td> 
 
     <td>Wiltshire</td> 
 
     <td>57</td> 
 
     <td>Musician</td> 
 
     <td>£124,000</td> 
 
     <td>Married</td> 
 
     <td>4</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Simon King</td> 
 
     <td>Malvern</td> 
 
     <td>Worchestershire</td> 
 
     <td>48</td> 
 
     <td>Naturalist</td> 
 
     <td>£65,000</td> 
 
     <td>Married</td> 
 
     <td>2</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Lucy Diamond</td> 
 
     <td>St Albans</td> 
 
     <td>Hertfordshire</td> 
 
     <td>67</td> 
 
     <td>Pharmasist</td> 
 
     <td>Retired</td> 
 
     <td>Married</td> 
 
     <td>3</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Austin Stevenson</td> 
 
     <td>Edinburgh</td> 
 
     <td>Lothian</td> 
 
     <td>36</td> 
 
     <td>Vigilante</td> 
 
     <td>£86,000</td> 
 
     <td>Single</td> 
 
     <td>Unknown</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Wilma Rubble</td> 
 
     <td>Bedford</td> 
 
     <td>Bedfordshire</td> 
 
     <td>43</td> 
 
     <td>Housewife</td> 
 
     <td>N/A</td> 
 
     <td>Married</td> 
 
     <td>1</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Kat Dibble</td> 
 
     <td>Manhattan</td> 
 
     <td>New York</td> 
 
     <td>55</td> 
 
     <td>Policewoman</td> 
 
     <td>$36,000</td> 
 
     <td>Single</td> 
 
     <td>1</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Henry Bolingbroke</td> 
 
     <td>Bolingbroke</td> 
 
     <td>Lincolnshire</td> 
 
     <td>45</td> 
 
     <td>Landowner</td> 
 
     <td>Lots</td> 
 
     <td>Married</td> 
 
     <td>6</td> 
 
     </tr> 
 
     <tr> 
 
     <td>Alan Brisingamen</td> 
 
     <td>Alderley</td> 
 
     <td>Cheshire</td> 
 
     <td>352</td> 
 
     <td>Arcanist</td> 
 
     <td>A pile of gems</td> 
 
     <td>Single</td> 
 
     <td>0</td> 
 
     </tr> 
 
    </tbody> 
 
    </table> 
 
</body>

+0

Благодарим вас за ответ. Я также хотел бы использовать только css-решение, но есть проблема: высота строк в замороженной части и основная часть должны быть синхронизированы программно тогда. См. Здесь: https://www.dropbox.com/s/3kg3cjfhrryolfj/2017-02-16_9-48-43.png?dl=0 –

7

Вы должны попробовать ниже пример кода со ссылкой на jquery.floatThead.js.

    var $demoTable = $("div.table-responsive table"); 
        $demoTable.floatThead({ 
         top: 200, 
         scrollContainer: function ($table) {         
          return $table.closest('.table-responsive'); 
         }, 
         position: 'absolute' 
        }); 

вам нужно получить ссылку на jquery.floatThead.js файла и попытаться применить это на столе.

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

+0

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

+0

Он не клонирует заголовок, он перемещает его в другую таблицу (и обратно в зависимости от опции позиционирования). Но да, он ничего не делает с замораживанием колонны – mkoryak

1

Проблема заключается в том, что IE не позволяет настраивать атрибут left ячейки в строке, независимой от строки в целом. Мы можем это увидеть, отредактировав DOM напрямую, используя окно разработчика в IE и окно разработчика в Chrome.

В Chrome, когда вы прокручиваете влево и вправо, вы можете видеть в средстве просмотра элементов, что атрибут left изменен на самом элементе, который переопределяет все CSS. Мы можем перезагрузить страницу и установить атрибут элемента вручную на этом же экране: style:'left:300px', и мы увидим, что ячейка заголовка перемещается вправо 300 пикселей и наводится на остальные ячейки заголовка. Это хорошее поведение и поведение, которое заставляет этот метод работать.

Если мы сделаем то же самое в IE и добавим 0-й элемент style: 'left:300px' в элемент th, мы увидим, что ячейка не перемещается. Ничто, что мы делаем с атрибутами стиля этой ячейки, не заставит ее покинуть свое место в таблице. Именно эта функция IE приводит к сбою метода. IE настаивает на поддержании порядка ячеек независимо от того, какие атрибуты применяются к элементам внутри строки.

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

Используя две таблицы, IE больше не связывает заголовок, который вы пытаетесь заморозить, с перемещаемым заголовком. Тщательный CSS замаскирует ваш хак и сделает таблицу одной таблицей.

Удачи и счастливой кодировки!

+1

Спасибо, Джаред. Фактически я использую метод, который вы описали. Но проблема в том, что нужно синхронизировать высоту строк в фиксированной таблице и таблице прокрутки. И это может раздражать, если таблица очень динамична: если вы загружаете записи по запросу, если пользователь может редактировать содержимое ячеек, если данные могут быть изменены динамически и так далее. Я помещаю заголовок в отдельный div тоже, поэтому в javascript мне нужно выполнить несколько задач: синхронизировать горизонтальную прокрутку, вертикальную прокрутку, высоту строк. Мои мечты - сделать все 1 стол. –

+0

Это понятный и хороший сон. Жаль, что IE делает жизнь такой сложной для всех. Возможно, вам удастся создать креативную альтернативу. Например, возможно, вместо прокрутки div, события прокрутки могут быть переведены на разные данные, отображаемые в таблицах. Javascript можно использовать для динамического изменения значений ячеек, чтобы заставить его выглядеть так, как действие прокрутки происходит в дискретных измерениях, но на самом деле данные в ячейках меняются. –