Reputation: 547
I have created an example of a sliding grid with fixed headers, using the "CSS Grid Layout" and "sticky position" technologies. For convenience, the content of the grid is generated by a script, which I think works well.
function fillGrid(selector, rows) {
let cols = 3;
let grid = $(selector);
grid.empty();
//cr header
grid.append($('<div>').addClass('hcr').text('#'));
//col headers
for (let c = 1; c <= cols; c++) {
grid.append($('<div>').addClass('hc').text(`Column ${c}`));
}
for (let r = 1; r <= rows; r++) {
//row header
grid.append($('<div>').addClass('hr').text(r));
//cells
for (let c = 1; c <= cols; c++) {
grid.append($('<div>').addClass('c').text(`Cell ${r}-${c}`));
}
}
}
$('#reload').click(e => {
var rows = Number.parseInt($('#rows').val());
fillGrid('#grid1', rows);
})
$(document).ready(function() {
fillGrid('#grid1', 10);
});
body {
font-family: 'Segoe UI', sans-serif;
font-size: 12px;
}
.grid {
display: grid;
width: 600px;
height: 300px;
grid-template-columns: 40px 200px 100px 500px;
grid-auto-rows: min-content;
border: 1px solid #ccc;
overflow: scroll;
margin-top: 20px;
background-color: #aaa;
margin-right: 10px;
}
.hcr, .hc, .hr {
background-color: #ddd;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
padding: 2px;
position: sticky;
}
.hcr {
top: 0;
left: 0;
z-index: 1;
text-align: center;
}
.hc {
top: 0;
white-space: nowrap;
}
.hr {
left: 0;
text-align: center;
}
.c {
padding: 2px;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background-color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<input type="text" id="rows" value="10" />
<input type="button" id="reload" value="Reload" />
</div>
<div class="grid" id="grid1"></div>
Up to 999 rows the grid works perfectly. When more than 999 rows are loaded, only the cells up to row 999 are displayed, while the following cells are incorrectly positioned on the left above the header of row 999.
The same example works correctly in Firefox 56 and Edge 16 (version 16299).
Where am I wrong?
Upvotes: 16
Views: 4922
Reputation: 547
Ok, the 1000 rows (and also 1000 columns) limit has been intentionally introduced into the Chrome engine for reasons of stability and RAM consumption. A new version of the Grid functionality seems to be in progress and should solve the problem.
Sources:
UPD: from Chrome version 96.0.4642 items amount extended to 100,000 rows/columns
Upvotes: 15
Reputation: 41
Yoav Kadosh's answer is a good approach, but I used two scroll areas so I wouldn't have to deal with the scroll debouncer.
<style>
#cnt {
position: relative;
width: fit-content;
}
#main {
position: relative;
}
#scroll,
#sp {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: auto;
width: auto;
max-width: fit-content;
}
.grid_cnt {
display: grid;
width: fit-content;
}
</style>
<div id="main" style="height: 1130.54px;">
<div id="sp">
<div id="cnt">
<div class="grid_cnt" style="grid-template-columns: auto auto auto auto auto auto;">
<div id="top_gap" style="height: 2507px; width: 1px; grid-column: 1 / 7;"></div>
<!-- grid cells -->
<div id="bottom_gap" style="height: 828px; width: 1px; grid-column: 1 / 7;"></div>
</div>
</div>
</div>
<div id="scroll">
<div id="scroll_sheet" style="height: 4624px; width: 574px;"></div>
</div>
</div>
Upvotes: 0
Reputation: 5155
I've made a pen that implements a possible workaround to this issue: 10K Rows CSS Grid Table
In short - the solution is to only render the visible rows based on the scroll position. The non-visible rows should be replaced with a single "gap-filling" row that receives their total height. This technique is known as virtualization or windowing.
To make it "optimistic", that gap-filling row should also receive a gradient background that simulates the horizontal row lines to make it look as if the lines are there (since this row will be briefly visible as the user scrolls and we don't want it to be blank).
In terms of performance, a table of 100 rows will perform exactly the same as a table with 10K rows when applying this solution.
For example:
<div class="table">
<div class="gap-before"
style="height: {{total height of rows before the visible rows}}">
<!-- visible rows go here -->
<div class="gap-after"
style="height: {{total height of rows after the visible rows}}">
</div>
Upvotes: 5
Reputation: 2707
Depending on your layout you can also replace display: grid
with display: block
.
If you have multiple columns in your table, then you might have to wrap the elements for each row but it worked perfectly fine for me.
The grid gap can be reproduced using margin-top.
Upvotes: 0