I've had really good luck applying a css transform on scroll in order to have a fixed table header. But now I would like to try the same technique when scrolling horizontally to have pinned columns.
The problem I'm running into is that the pinned columns in the header appear behind instead of on top when scrolling horizontally. The browser is deciding which DOM elements should be on top after doing the transformation. Anything I can do to control this? (yes, I've tried z-index)
Demo
(function() {
var app = angular.module("soDemo", []);
app.controller("soDemoController", SoDemoController);
SoDemoController.$inject = ['$scope', '$document'];
function SoDemoController($scope, $document) {
var vm = {
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
};
$scope.vm = vm;
$('.table-container').on('scroll', onScroll);
return;
/////////// IMPLEMENATION ////////
function onScroll() {
var translate = "translate(0," + this.scrollTop + "px)";
$("table thead th:not(.pinned)").css('transform', translate);
translate = "translate(" + this.scrollLeft + "px,0)";
$("table tbody .pinned").css('transform', translate);
translate = "translate(" + this.scrollLeft + "px," + this.scrollTop + "px)";
$("table thead th.pinned").css('transform', translate);
}
}
})();
.table-container {
overflow: auto;
height: 200px;
width: 300px
}
table {
table-layout: fixed;
border-spacing: 0;
}
td {
padding: 3px;
white-space: nowrap;
border-right: 1px solid #ccc;
}
th {
background: #999;
}
th.pinned {
background: #ccc;
}
td.pinned {
background: #eee;
}
input {
margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<div class="sample" ng-app="soDemo" ng-controller="soDemoController">
<p>When you scroll horizontally, the header row scrolls on top of col0 and col1 instead of behind it.</p>
<p>When you scroll vertically, the tbody cells render over top of Col 0 and Col 1 headers instead of behind it</p>
<div class="table-container">
<table>
<thead>
<tr>
<th class="pinned">Col 0</th>
<th class="pinned">Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
<th>Col 5</th>
<th>Col 6</th>
<th>Col 7</th>
<th>Col 8</th>
<th>Col 9</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in vm.data">
<td class="pinned">Data {{item}}</td>
<td class="pinned">Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
</tr>
</tbody>
</table>
</div>
</div>
I think it is still a z-index issue.
Thanks to @sascha10000 they got me thinking about what was missing. If you add position: relative to the th.pinned class in your css and also add a positive z-index. (i.e. z-index:20) It appears to work.
(function() {
var app = angular.module("soDemo", []);
app.controller("soDemoController", SoDemoController);
SoDemoController.$inject = ['$scope', '$document'];
function SoDemoController($scope, $document) {
var vm = {
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
};
$scope.vm = vm;
$('.table-container').on('scroll', onScroll);
return;
/////////// IMPLEMENATION ////////
function onScroll() {
var translate = "translate(0," + this.scrollTop + "px)";
$("table thead th:not(.pinned)").css('transform', translate);
translate = "translate(" + this.scrollLeft + "px,0)";
$("table tbody .pinned").css('transform', translate);
translate = "translate(" + this.scrollLeft + "px," + this.scrollTop + "px)";
$("table thead th.pinned").css('transform', translate);
}
}
})();
.table-container {
overflow: auto;
height: 200px;
width: 300px
}
table {
table-layout: fixed;
border-width: 0;
border-spacing: 0;
}
td {
padding: 3px;
white-space: nowrap;
border-right: 1px solid #ccc;
}
th {
background: #999;
}
th.pinned {
position: relative; /**** <=== added this ****/
z-index: 20; /**** <=== added this ****/
background: #ccc;
}
td.pinned {
background: #eee;
}
input {
margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<div class="sample" ng-app="soDemo" ng-controller="soDemoController">
<p>When you scroll horizontally, the header row scrolls on top of col0 and col1 instead of behind it.</p>
<p>When you scroll vertically, the tbody cells render over top of Col 0 and Col 1 headers instead of behind it</p>
<div class="table-container">
<table>
<thead>
<tr>
<th class="pinned">Col 0</th>
<th class="pinned">Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
<th>Col 5</th>
<th>Col 6</th>
<th>Col 7</th>
<th>Col 8</th>
<th>Col 9</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in vm.data">
<td class="pinned">Data {{item}}</td>
<td class="pinned">Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
<td>Data {{item}}</td>
</tr>
</tbody>
</table>
</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With