grid-auto-flow: dense 会彻底打乱 DOM 顺序与视觉顺序的一致性,因其执行回填算法将后续项插入前面跨行/跨列留下的空洞,导致屏幕阅读器和键盘焦点按重排后的视觉流而非 HTML 源码顺序运行。

grid-auto-flow: dense 会彻底打乱 DOM 顺序与视觉顺序的一致性
浏览器在启用 grid-auto-flow: dense 后,不是简单“换行更紧凑”,而是执行回填算法:扫描已生成的网格,把后续 DOM 中尺寸合适、尚未落位的项,强行插进前面因跨行/跨列(如 grid-row: span 2)留下的空洞里。结果就是:div:nth-child(3) 可能出现在第 1 行第 2 列,而 div:nth-child(2) 却被挤到第 3 行第 1 列——DOM 顺序和渲染顺序完全脱钩。
屏幕阅读器和键盘焦点都按视觉顺序走,不是按 HTML 源码
Chrome、Firefox、Safari 均将 dense 重排后的视觉布局同步写入 accessibility tree。这意味着:
- 屏幕阅读器(NVDA、VoiceOver)朗读顺序 = dense 插空后的视觉流,不是你写的 HTML 顺序
- Tab 键焦点路径也跟着 dense 走,用户按 Tab 从第 1 行第 1 列跳到第 1 行第 2 列,再突然跳到第 3 行第 1 列,中间跳过第 2 行
- DevTools 的 Accessibility 面板直接显示重排后的节点树,
order: -1元素可能出现在树顶,但 dense 下连order都不参与排序逻辑
显式定位项(grid-row/column)会让 dense 表现更不可预测
只要存在任意一个显式定位项,dense 就可能触发多轮填空,导致后续项位置完全脱离预期:
-
grid-row: 1 / 3占两行 → 第 2 行留下空洞 → 后续高度为 1 行的项可能被塞进第 1 行右侧空列,也可能被塞进第 2 行空位,取决于列宽和剩余空间 - 多个跨行项叠加时,空洞分布复杂,dense 填空路径难以人工推演
- 响应式断点中切换 dense 开关,或混用
grid-template-areas,会进一步掩盖问题根源
真正影响无障碍的不是“dense 本身”,而是它绕过了所有可访问性兜底机制
其他 CSS 排序手段至少有 fallback 路径,但 dense 没有:
立即学习“前端免费学习笔记(深入)”;
-
order至少还能配合grid-row显式定位来规避影响;dense 下显式定位项照常占位,其余项全被自动重排,无法局部控制 -
transform: translate()不动 DOM 和可访问性树;dense 直接改 layout tree,accessibility tree 必须同步 - 没有 ARIA 属性能覆盖 dense 引起的顺序变更(
aria-flowto等只对显式可聚焦元素有效,不干预 auto-placement 流程)
最常被忽略的一点:开发者调试时只看页面是否“长得对”,从不按 Tab 键走一遍,也不开 VoiceOver 听一遍。dense 带来的可访问性断裂,上线后第一波投诉就来自键盘用户和视障用户。


















