CSS Chrome 中的网格布局似乎无法在超过 1000 行的情况下正常工作
CSS Grid Layout in Chrome seems not to work properly with more than 1000 rows
我使用 "CSS Grid Layout" 和 "sticky position" 技术创建了一个固定 headers 的滑动网格示例。为了方便,grid的内容是用脚本生成的,我觉得效果不错
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>
最多 999 行网格可以完美运行。当加载超过 999 行时,仅显示第 999 行之前的单元格,而以下单元格错误地位于第 999 行 header 上方的左侧。
同一示例在 Firefox 56 和 Edge 16(版本 16299)中正常运行。
我哪里错了?
好的,出于稳定性和 RAM 消耗的原因,Chrome 引擎有意引入了 1000 行(以及 1000 列)限制。新版本的网格功能似乎正在开发中,应该可以解决问题。
来源:
- https://bugs.chromium.org/p/chromium/issues/detail?id=688640
- https://github.com/w3c/csswg-drafts/issues/1009
更新: 从 Chrome 版本 96.0.4642 项目数量扩展到 100,000 rows/columns
我制作了一支笔来解决这个问题:10K Rows CSS Grid Table
简而言之 - 解决方案是仅根据滚动位置呈现可见行。
non-visible 行应替换为接收到的单个“gap-filling”行
他们的总身高。此技术称为 虚拟化 或 窗口化。
为了使其“乐观”,gap-filling 行还应接收模拟水平行线的渐变背景,使其看起来好像线就在那里(因为该行将短暂显示为用户滚动,我们不希望它是空白的)。
就性能而言,应用此解决方案时,100 行的 table 与 10K 行的 table 的性能完全相同。
例如:
<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>
根据您的布局,您还可以将 display: grid
替换为 display: block
。
如果您的 table 中有多个列,那么您可能必须将每一行的元素换行,但它对我来说效果很好。
可以使用 margin-top 重现网格间隙。
Yoav Kadosh 的回答是一个很好的方法,但我使用了两个滚动区域,所以我不必处理滚动去抖动器。
<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>
我使用 "CSS Grid Layout" 和 "sticky position" 技术创建了一个固定 headers 的滑动网格示例。为了方便,grid的内容是用脚本生成的,我觉得效果不错
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>
最多 999 行网格可以完美运行。当加载超过 999 行时,仅显示第 999 行之前的单元格,而以下单元格错误地位于第 999 行 header 上方的左侧。
同一示例在 Firefox 56 和 Edge 16(版本 16299)中正常运行。
我哪里错了?
好的,出于稳定性和 RAM 消耗的原因,Chrome 引擎有意引入了 1000 行(以及 1000 列)限制。新版本的网格功能似乎正在开发中,应该可以解决问题。
来源:
- https://bugs.chromium.org/p/chromium/issues/detail?id=688640
- https://github.com/w3c/csswg-drafts/issues/1009
更新: 从 Chrome 版本 96.0.4642 项目数量扩展到 100,000 rows/columns
我制作了一支笔来解决这个问题:10K Rows CSS Grid Table
简而言之 - 解决方案是仅根据滚动位置呈现可见行。 non-visible 行应替换为接收到的单个“gap-filling”行 他们的总身高。此技术称为 虚拟化 或 窗口化。
为了使其“乐观”,gap-filling 行还应接收模拟水平行线的渐变背景,使其看起来好像线就在那里(因为该行将短暂显示为用户滚动,我们不希望它是空白的)。
就性能而言,应用此解决方案时,100 行的 table 与 10K 行的 table 的性能完全相同。
例如:
<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>
根据您的布局,您还可以将 display: grid
替换为 display: block
。
如果您的 table 中有多个列,那么您可能必须将每一行的元素换行,但它对我来说效果很好。
可以使用 margin-top 重现网格间隙。
Yoav Kadosh 的回答是一个很好的方法,但我使用了两个滚动区域,所以我不必处理滚动去抖动器。
<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>