CSS Grid Layout in Chrome seems not to work properly with more than 1000 rows
Asked Answered
L

4

16

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?

Lime answered 10/11, 2017 at 8:16 Comment(0)
L
15

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

Lime answered 17/11, 2017 at 7:49 Comment(0)
O
5

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>
Oliy answered 3/7, 2019 at 19:11 Comment(0)
M
0

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.

Meeting answered 8/4, 2021 at 12:59 Comment(0)
H
0

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>
Harv answered 6/10, 2021 at 7:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.