Мне нравится Maximillian Hils ' ответ, но у меня возникли некоторые проблемы:
- преобразование не работает в Edge или IE, если вы не примените его к th
- заголовок мигает при прокрутке в Edge и IE
- моя таблица загружается с использованием ajax, поэтому я хотел прикрепить к событию прокрутки окна, а не к событию прокрутки оболочки
Чтобы избавиться от мерцания, я использую тайм-аут, чтобы подождать, пока пользователь не закончит прокрутку, затем я применяю преобразование - таким образом, заголовок не виден во время прокрутки.
Я также написал это, используя jQuery, одним из преимуществ которого является то, что jQuery должен обрабатывать префиксы вендоров для вас
var isScrolling, lastTop, lastLeft, isLeftHidden, isTopHidden;
//Scroll events don't bubble https://stackoverflow.com/a/19375645/150342
//so can't use $(document).on("scroll", ".table-container-fixed", function (e) {
document.addEventListener('scroll', function (event) {
var $container = $(event.target);
if (!$container.hasClass("table-container-fixed"))
return;
//transform needs to be applied to th for Edge and IE
//in this example I am also fixing the leftmost column
var $topLeftCell = $container.find('table:first > thead > tr > th:first');
var $headerCells = $topLeftCell.siblings();
var $columnCells = $container
.find('table:first > tbody > tr > td:first-child, ' +
'table:first > tfoot > tr > td:first-child');
//hide the cells while returning otherwise they show on top of the data
if (!isLeftHidden) {
var currentLeft = $container.scrollLeft();
if (currentLeft < lastLeft) {
//scrolling left
isLeftHidden = true;
$topLeftCell.css('visibility', 'hidden');
$columnCells.css('visibility', 'hidden');
}
lastLeft = currentLeft;
}
if (!isTopHidden) {
var currentTop = $container.scrollTop();
if (currentTop < lastTop) {
//scrolling up
isTopHidden = true;
$topLeftCell.css('visibility', 'hidden');
$headerCells.css('visibility', 'hidden');
}
lastTop = currentTop;
}
// Using timeout to delay transform until user stops scrolling
// Clear timeout while scrolling
window.clearTimeout(isScrolling);
// Set a timeout to run after scrolling ends
isScrolling = setTimeout(function () {
//move the table cells.
var x = $container.scrollLeft();
var y = $container.scrollTop();
$topLeftCell.css('transform', 'translate(' + x + 'px, ' + y + 'px)');
$headerCells.css('transform', 'translateY(' + y + 'px)');
$columnCells.css('transform', 'translateX(' + x + 'px)');
isTopHidden = isLeftHidden = false;
$topLeftCell.css('visibility', 'inherit');
$headerCells.css('visibility', 'inherit');
$columnCells.css('visibility', 'inherit');
}, 100);
}, true);
Таблица завернута в div с классом table-container-fixed
.
.table-container-fixed{
overflow: auto;
height: 400px;
}
Я установил border-collapse для разделения, потому что в противном случае мы теряем границы во время перевода, и я удаляю границу на таблице, чтобы содержимое не появлялось чуть выше ячейки, где была граница при прокрутке.
.table-container-fixed > table {
border-collapse: separate;
border:none;
}
Я делаю фон th
белым, чтобы покрыть ячейки внизу, и добавляю границу, которая соответствует границе таблицы - которая оформляется с помощью Bootstrap и прокручивается вне поля зрения.
.table-container-fixed > table > thead > tr > th {
border-top: 1px solid #ddd !important;
background-color: white;
z-index: 10;
position: relative;/*to make z-index work*/
}
.table-container-fixed > table > thead > tr > th:first-child {
z-index: 20;
}
.table-container-fixed > table > tbody > tr > td:first-child,
.table-container-fixed > table > tfoot > tr > td:first-child {
background-color: white;
z-index: 10;
position: relative;
}