Buffer order follows document structure, not CSS visual position
Aliases: document order · CSS order · accessibility tree order
What it is
What order the virtual buffer lists nodes in is not “who sits to the left on screen.” The reader walks a depth-first flattening of the accessibility tree, and that tree comes from document structure: DOM order, aria-owns reparenting, shadow flattening. flex-direction: row-reverse, order, grid-area, position: absolute, and transform can swap boxes visually and still never enter that serialization — used values from layout and the tree walk are two different computations.
This is not the product rule “reading order should match visual reading.” That is a separate claim. This card only answers the machine: how the buffer is built, and that CSS coordinates are not an input.
Why it happens
Flattening the accessibility tree is a tree walk. Sequence is parent/child/sibling structure, occasionally rewritten by aria-owns. CSS visual formatting is a different computation: containing blocks, flex axes, grid tracks, stacking contexts. The two share almost no inputs. “400px from the left” is not a parameter of “speak this first.”
The second layer is therefore blunt: visual reordering is free; structural reordering is what enters the buffer. Pull a sidebar left with order: -1 and sighted reading starts there; the buffer still walks the main column that sits earlier in the DOM. Pin a button to a viewport corner with absolute positioning and speech still meets it near the paragraph where it lives in source. The reader did not misread the layout. It never subscribed to layout.
Studying it
Build a matched pair: visual order reversed versus DOM order reversed, copy otherwise identical. Cover the display, record the spoken sequence with arrow keys, and compare it to left-to-right, top-to-bottom on a screenshot. Add a third cell that reparents with aria-owns and leaves CSS alone, to see whether the buffer follows. Use NVDA+Firefox on Windows; use VoiceOver+Safari on WebKit, because some engines have started mapping limited CSS order into the tree and results fork.
Independent variables: reordering method (flex reverse / order / absolute positioning / DOM swap / aria-owns), engine.
Dependent variables: spoken sequence, inspector tree order, whether those match the visual reading path.
Where it stops holding
Specs and engines still argue whether CSS visual order should affect the accessibility tree; some browsers’ mapping of flex order is already not a pure DOM-order identity, so the claim is not an equation across engines. display: contents removes a box but keeps descendants, and the walk skips that layer. Multicolumn, tables, and SVG each flatten by their own rules, not as one left-to-right article. Maps, canvases, and infinite boards have no stable document order; the buffer is empty or follows off-axis nodes the author stuffed in — that is not “CSS mismatch,” it is no structure to copy.
Applying it
- Put content the user should meet first earlier in the source structure; do not “visually promote” it with flex reverse,
order, or absolute positioning. - When visual reordering is required, change the DOM in step or reparent with
aria-ownsso the walk matches visual reading. - Decide the insertion point of sidebars, toolbars, and floating actions in the structure before writing positioning.
- How to check: print the page greyscale and mark the visual reading path, then cover the screen and walk with arrows; compare the two sequences item by item. Every mismatch is structure that did not follow vision. Repeat in a second engine so one vendor’s
ordermapping is not treated as universal.
Related
- Same group: J5.09.1 Screen readers speak from a virtual buffer, not from pixels · J5.09.2 Browse mode and focus mode bind the same keys to different jobs · J5.09.4 After dynamic updates the buffer must be rebuilt or speech is stale
- Nearby: J2.08 Reading order · J2.09 Semantic structure
- Search terms:
source order·visual order·CSS order