J5.09.3source order vs visual order设计研究

缓冲区的内容顺序基于文档结构而非样式表定义的视觉位置

别名: 源顺序 · 文档顺序 · CSS order · 视觉顺序

概念解释

虚拟缓冲区按什么次序排列节点,问的不是「屏幕上谁在谁左边」。阅读器走的是无障碍树的深度优先展开,而那棵树来自文档结构:DOM 顺序、aria-owns 改挂、影子树拍平。flex-direction: row-reverseordergrid-areaposition: absolutetransform 可以让盒子在视觉上对调,却进不了这份序列化——布局引擎的 used value 和树的遍历是两套计算。

这不是在说「阅读顺序应当跟视觉阅读一致」那条产品判据。那是另一件事。这里只回答机器:缓冲区怎么被建出来,CSS 的坐标根本没有被读进去。

机制

无障碍树的扁平化是一次树遍历。节点的先后由父子与兄弟关系决定,偶尔被 aria-owns 改写归属。CSS 视觉格式化是另一次计算:包含块、flex 主轴、grid 轨道、层叠上下文。两次计算的输入几乎不共享。「距左边 400 像素」从来不是「先念谁」的参数。

第二层因此很硬:视觉重排是免费的,结构重排才进缓冲区。把侧栏用 order: -1 挪到主列左边,看见的人先读侧栏,缓冲区仍先走 DOM 里靠前的主列。绝对定位把按钮钉在视口角落,语音还在它在源码里的那个段落附近出现。阅读器不是读错了布局,它从未订阅布局。

怎么研究

做一对材料:视觉顺序相反、DOM 顺序相反,其余文案相同。遮住显示器,用阅读器方向键记下语音序列,再对照截图上的从左到右、从上到下。再加一档:只用 aria-owns 改挂,不改 CSS,看缓冲区是否跟着改。Windows 用 NVDA+Firefox;WebKit 用 VoiceOver+Safari,因为个别引擎开始把有限的 CSS order 映进无障碍树,结果会分叉。

自变量:重排手段(flex 反向 / order / 绝对定位 / DOM 对调 / aria-owns)、引擎。 因变量:语音序列、检查器树序、与视觉阅读路径是否同构。

边界

规格和引擎正在争论 CSS 视觉顺序该不该影响无障碍树;部分浏览器对 flex order 的映射已经和「纯 DOM 序」不完全相同,结论不能当成所有引擎的恒等式。display: contents 会拆掉盒子但仍留子孙,遍历会跳过那一层。多栏、表格、SVG 阅读顺序各有自己的拍平规则,不是一篇从左到右的文章。地图、画布、无限画板没有稳定的文档序,缓冲区要么空,要么按作者塞进去的离轴节点走——那已经不是「CSS 对不上」,是根本没有结构可拷。

怎么落地

  • 用户应当先遇到的内容,写在源结构的前面;不要用 flex 反向、order、绝对定位去「视觉上提前」。
  • 必须视觉重排时,同步改 DOM 或用 aria-owns 把树挂对,让遍历与视觉阅读同构。
  • 侧栏、工具条、浮动操作按钮先在结构里想清楚插入点,再写定位。
  • 验证:把页面打印成灰度并从左到右标阅读路径,再遮屏用方向键走一遍,两条序列逐项对照。错位的每一处都是结构没跟着视觉走。换一个引擎再走一次,避免把某一家对 order 的映射当成普遍事实。

延伸

  • 同组J5.09.1 阅读器维护一份独立于视觉渲染的虚拟内容缓冲区 · J5.09.2 浏览模式与焦点模式的切换决定按键的行为方式 · J5.09.4 动态更新内容后缓冲区需要重建,否则播报的是过时内容
  • 相邻J2.08 阅读顺序 · J2.09 语义结构
  • 站内检索source order · visual order · CSS order

同组卡片

快捷操作

分享

分享当前页面

ios_share

https://hci.top/zh/handbook/J5.09.3