Main content appears here...
Test reading order
When the sequence of content affects meaning, the correct reading sequence must be programmatically determinable. Visual order should match DOM order.
DOM vs visual order
Main content appears here...
✕ CSS flex-direction: column-reverse and order properties break reading sequence.
What users hear
flex-direction: row-reverseflex-direction: column-reverseorder: -1 to reorder itemsposition: absolute with visual reorderingfloat: right for sidebar-first layoutsCSS Grid reordering issues
<!-- DOM order -->
<div class="grid">
<aside>Sidebar</aside> <!-- DOM: 1st -->
<main>Main Content</main> <!-- DOM: 2nd -->
</div>
/* CSS reorders visually */
aside { grid-column: 2; }
main { grid-column: 1; }
/* Screen reader reads:
1. Sidebar
2. Main Content
But visually: Main | Sidebar */<!-- DOM matches visual order --> <div class="grid grid-cols-[1fr_300px]"> <main>Main Content</main> <!-- DOM: 1st --> <aside>Sidebar</aside> <!-- DOM: 2nd --> </div> /* No CSS reordering needed */ /* Screen reader reads: 1. Main Content 2. Sidebar Visual order matches! ✓ */
Testing hints
// Get DOM order vs visual order using $$eval
const elements = await page.$$eval(
'[data-testid="accessible-layout"] *',
els => els.map(el => ({
tag: el.tagName,
text: el.textContent?.slice(0, 30),
// Get visual position
rect: el.getBoundingClientRect()
}))
);
// Sort by visual position (top to bottom)
const visualOrder = [...elements].sort(
(a, b) => a.rect.top - b.rect.top ||
a.rect.left - b.rect.left
);
// Compare DOM order to visual order
for (let i = 0; i < elements.length; i++) {
if (elements[i].text !== visualOrder[i].text) {
console.log('Order mismatch at position', i);
console.log('DOM:', elements[i].text);
console.log('Visual:', visualOrder[i].text);
}
}import AxeBuilder from '@axe-core/playwright';
// Note: axe-core has limited ability to detect
// CSS reordering issues automatically
// Manual check: Tab through and verify order
const tabOrder = [];
let prevFocused = null;
for (let i = 0; i < 20; i++) {
await page.keyboard.press('Tab');
const focused = await page.$eval(
':focus', el => el.textContent
);
if (focused !== prevFocused) {
tabOrder.push(focused);
prevFocused = focused;
}
}
console.log('Tab order:', tabOrder);
// Check for CSS properties that break order
const reorderingCSS = await page.$$eval('*', els =>
els.filter(el => {
const style = getComputedStyle(el);
return style.order !== '0' ||
style.flexDirection.includes('reverse');
}).map(el => el.outerHTML.slice(0, 100))
);Automation hints