1.3.2 Meaningful Sequence (A): When the sequence in which content is presented affects its meaning, a correct reading sequence can be programmatically determined. (Level A)
Requirements
Requirements for both native and web
- When users navigate the page using a keyboard’s ‘tab’ key, or cursor arrows (when a screen reader is on), elements receive the keyboard focus and screen reader cursor following a predictable, natural reading order.
- A natural reading order is from left to right and top to bottom in most cases in Western countries.
- The easiest way to avoid focus order issues is to make sure that elements are displayed on screen in the same order as they appear in the Document Object Model (Web) / View Hierarchy (iOS and Android).
- Tabular data is presented using proper HTML markup (
<table>
,<tr>
,<th>
, and<td>
elements)
Why is it important?
The order in which elements appear in code matters
- Screen readers go through elements on a page/screen in the order in which they appear in the Document Object Model (Web) / View Hierarchy (iOS and Android), which is a tree-like structure that contains all the elements on the page.
- The order in which elements appear in that Document Object Model / View Hierarchy might be different from the order in which they’re laid out visually on screen.
- This can happen for example if certain CSS techniques are used to change the relative positioning of elements on the page.
- The order in which elements appear in that Document Object Model / View Hierarchy matters to user experience.
- When people use a screen reader, the keyboard or a Switch control, they interact with elements on the page in the order in which they appear in that Document Object Model / View Hierarchy.
- So make sure that elements appear in the Document Object Model / View Hierarchy in a reading order that’s natural and makes sense.
Summary
- Make sure that elements appear in a logical reading order in code, so that they are presented in a meaningful order to screen reader users.
- Content on the page needs to be announced by screen readers following a logical reading order.
Common Mistakes
- The DOM order does not match the visual order because CSS properties like flexbox and grid-layout have been used to alter the visual presentation;
- The DOM order does not match the visual order because tabindex has been used with a value other than -1 or 0.
- A ‘Agree to cookies’ dialog that’s positioned last in the DOM but appears at the top of the screen, without being implemented as modal (with the inert attribute)
- When CSS styles are disabled, the content order is meaningless;
- Using dialogs or menus that are not adjacent to their trigger control in the sequential navigation order.
- Tabular data is displayed using CSS to present the appearance of a table, but the proper HTML markup has not been used;
- The tabindex attribute has been used to force a tab order through the content.
- The order of interactive elements is not consistent across designs for different screen sizes.
- For example, imagine that you’ve designed a modal dialog with two buttons: ‘Cancel’ and ‘OK’:
- On the design for large screens, the ‘Cancel’ button is positioned to the left of the ‘OK’ button. (‘Cancel’ comes before ‘OK’ in the reading order).
- But on the design for small screens, the ‘Cancel’ button is positioned to the bottom of the ‘OK’ button. (‘Cancel’ now comes after ‘OK’ in the reading order).
- For example, imagine that you’ve designed a modal dialog with two buttons: ‘Cancel’ and ‘OK’:
Design Guide
- When you provide different designs for different screen sizes (e.g. desktop and mobile, or for different break points), make sure that elements appear in the same order across on the different designs.
- If you can’t do that, call it out to developers as they’re likely to need to create different structures for the different designs.
Meaningful Sequence Example for IOS
Setting a custom order for child elements
containerView.isAccessibilityElement = false
containerView.accessibilityElements = [firstLabel, secondLabel, button]
How to test whether elements appear in a logical reading order in the View Hierarchy
You can use the Visual Debugger in Xcode to see all elements within a View / View Controller, and check that they are listed in a reading order that makes sense.
Meaningful Sequence Example for Android
- By default all focusable views will be read from the screen reader from the top down. But there is a way to set a custom order for child elements.
- It is essentially providing next focused target for keyboard input. (The container doesn’t need any special flags for it to work).
- When using this technique, make sure that elements appear in a the same natural reading, visually and in code. The best way to do that is often to keep the default order in which views are read might.
<RelativeLayout ...>
<Button
android:id="@+id/button1"
android:nextFocusForward="@+id/editText1"
... />
<Button
android:id="@+id/button2"
android:nextFocusForward="@+id/button1"
... />
<EditText
android:id="@id/editText1"
android:nextFocusForward="@+id/button2"
... />
...
</RelativeLayout>
Alternative from API 22 is to specify the traversal order android:accessibilityTraversalAfter="@id"
.
This is the recommended way but there is the API 22 restriction.
<RelativeLayout ...>
<Button
android:id="@+id/button1"
android:accessibilityTraversalAfter="@+id/editText1"
... />
<Button
android:id="@+id/button2"
android:accessibilityTraversalAfter="@+id/button1"
... />
<EditText
android:id="@id/editText1"
android:accessibilityTraversalAfter="@+id/button2"
... />
...
</RelativeLayout>
The best practices for grouping and ordering elements in an accessible manner can be summarized as follows:
- The view hierarchy order and on-screen positioning determine grouping and ordering of text in spoken feedback.
- You should group non-focusable items in a focusable container to have them read as a single item.
- To logically group related items, it is sometimes necessary to create nested ViewGroup elements (eg: a wrapping RelativeLayout for a label and its value)
Meaningful Sequence Example for Flutter
Flutter deals with assistive technologies like screen readers using the Semantics() widget.
- By default all focusable widgets will be read out in the order that they are drawn on the screen from top down.
There are ways of affecting the order for custom navigation of elements with a screen reader. By passing a SemanticSortKey to the sortKey property of Semantics() the element with the lower key value will be read first.
Column(
children: <Widget>[
Semantics(
sortKey: OrdinalSortKey(1), // will be read/focused second by the screen reader
child: SecondWidget()
),
Semantics(
sortKey: OrdinalSortKey(0), // will be read/focused first by the screen reader
child: FirstWidget()
),
]
),
Meaningful Sequence Example for Web
Screen reader software renders content in the order in which it appears in the Document Object Model (DOM). Place content in the DOM in a correct reading order either through source code or inserting nodes via JavaScript.
Do not use positive values with tabindex
Example
<h1 tabindex="-1">I'm the heading for a modal dialog</h1>
...
<div tab-index="0" class="fake_button" aria-role="button">Button Label</div>
Failure example
<div tab-index="3" class="fake_button" aria-role="button">Button Label</div>
Be careful when using CSS Float, Flexbox, Grid and position
- With CSS Flexbox, don’t use the order property or flex-direction: reverse;;
- With CSS Grid, be careful with manual placement of items on the grid;
- When using position absolute, fixed or sticky, be careful to not detach the visual order of elements from the order in which they appear in the DOM;
Example
<main>
<div style="float:left;">
<h1>Article header</h1>
<div>Article content</div>
</div>
<aside style="float:right;">Supplementary info</aside>
</main>
Failure example
<main>
<h1>Article header</h1>
<aside style="position:relative; left:50%;top:-50%;">Supplementary info</aside>
<div>Article content</div>
</main>
Make new content appear in the DOM right after the element that triggers it
If a button triggers extra content to appear (like a menu), make sure that that extra content appears next to the button in both the DOM order and visual order.
How to test whether elements appear in a logical reading order in the DOM
Turn off CSS on the page to see elements laid out on screen in the order in which they appear in the Document Object Model.
References
- UIAccessibilityContainer developer reference on apple.com
- Support keyboard navigation developer reference on developer.android.com
- FlexBox and the keyboard navigation disconnect
- Writing CSS with Accessibility in Mind: Taking care of order by Manuel Matuzovic
- The Dark Side of the Grid: Changing visual order by Manuel Matuzovic
- Using the tabindex attribute
- Accessibility Guidelines- Github.io