grid卡顿主因是二维重排而非写法本身:子项尺寸变化触发整行高+整列宽递归重算,1000项重排耗时28.9ms(超掉帧阈值3ms),是flex的3.3倍;应设容器height/max-height、用contain隔离、禁用dense、启用虚拟滚动。

不是 Grid 写法本身慢,是浏览器在二维布局约束下被迫反复重排 —— 每次子项尺寸变化,都得重新算整行高度 + 整列宽度,1000 个 Grid Item 触发的 Layout 耗时可达 28.9ms,远超掉帧阈值(3ms)。
Grid 为什么比 Flex 布局更易卡顿?
Flex 是一维伸缩,Grid 是二维拓扑:一个卡片高度变,浏览器必须回溯它所在行的所有列宽、再校验所有列中该行的基准高度,形成递归式重排。实测 1000 个节点下,Grid 重排耗时是 Flex 的 3.3 倍,内存开销高近 3 倍。
-
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr))这类写法在滚动中会持续触发轨道重计算,尤其当容器宽度动态变化时 - 子项没设固定高度(如
h-48或min-height: 192px),导致浏览器无法预估布局范围,滚动时频繁 reflow - 嵌套超过 2 层
display: grid后,隐式轨道生成 +grid-template-areas解析 + 行列映射三重开销叠加,Android 5.1 WebView 单次getComputedStyle就达 8ms+
DOM 节点多 ≠ Grid 卡,但渲染方式错了就真卡
卡顿根源不在 Grid,而在你把几百个 <div> 全塞进 DOM 并一次性挂载 —— Tailwind 的 <code>repeat(200, ...) 只生成 CSS 规则,不产生节点;真正压垮主线程的是 JS 的 map() 渲染全量列表。
- 用虚拟滚动(如
react-window或IntersectionObserver)只挂载可视区域 ±2 行,其余用占位<div style="height: 192px"></div> - Grid 容器必须设明确
height或max-height,否则子项撑开后持续触发布局,滚动越快卡越狠 - 禁用
grid-auto-flow: dense—— 它会让浏览器反复扫描空隙并回填,布局开销指数级上升
怎么让 Grid 布局不拖慢滚动?
关键不是“少用 Grid”,而是切断重排链路:用 contain: layout style paint 明确告诉浏览器“这个卡片的布局、样式、绘制不会影响外面”,把重排限制在局部。
- 每个复杂子项(如带头像+标题+操作按钮的卡片)加
contain: layout style paint,Chrome/Firefox/Safari 15.4+ 均支持 - 旧版 Safari 降级用
will-change: transform(仅提示,不推荐长期启用) - 避免在
:hover或@keyframes中修改grid-row-start、grid-column等定位属性 —— 这类变更强制同步 layout - 不用
display: contents包裹无语义的中间层(比如只为对齐而套的<div class="grid">),既砍掉一层布局开销,又保留 DOM 结构和 JS 可访问性 <p>最容易被忽略的点:Grid 容器自身没设高度约束,子项靠内容撑开,滚动时每帧都在重排 —— 卡顿往往从这里开始,而不是 Grid 写法本身。</p> </div>











