blob: 294535b0037c29feab924a2e74269f4da0b33ca5 [file] [log] [blame] [view]
Dominic Mazzonib64f0fb32021-08-18 04:49:001# How Chrome Accessibility Works
2
3This document explains the technical details behind Chrome accessibility
4code by starting at a high level and progressively adding more levels of
5detail.
6
David Tseng7f8ddfb2021-11-01 19:32:597Please read the accessibility [overview](../overview.md) first.
Dominic Mazzonib64f0fb32021-08-18 04:49:008
9[TOC]
10
11## Accessibility for a simple (non-browser) application
12
David Tseng7f8ddfb2021-11-01 19:32:5913As described in the [overview](../overview.md), every platform has its own
Dominic Mazzonib64f0fb32021-08-18 04:49:0014accessibility APIs that are used by both assistive technology and sometimes
15by automation software. To better understand the challenges of accessibility
16support in Chromium, let's first explore what it's like to build an
17accessible application using a standard UI toolkit.
18
19Examples of standard toolkits would be Win32 UI controls or .NET components
20on Windows, or Cocoa NSViews on macOS, or Android Views via Java or Kotlin.
21When you use such a toolkit to build an application, a lot of accessibility
22comes for free.
23
24Typically every UI element - including containers and grouping elements - gets
25its own corresponding accessibility element, implementing that platform's
26accessibility API. So if you add a button, checkbox, scroll container, or
27text field to your application, you don't need to do any work to make it
28accessible - the built-in UI toolkit has provided all of that already.
29
30![Simple accessibility tree](figures/ax_tree.png)
31
32### Changing accessibility properties
33
34There are some cases where a bit of extra information may be required on the
35part of the app author. If you add an image button, you may need to ensure
36you provide an accessible label ("alt text"). Other common simple modifications
37might include hiding UI elements from accessibility because they're primarily
38decorative, or marking a UI element as an alert to ensure it's announced
39to screen reader users when it appears. However, none of these require
40writing more than a few lines of code.
41
42#### Windows
43
44The [dynamic annotation API](https://docs.microsoft.com/en-us/windows/win32/winauto/dynamic-annotation-api)
45lets you change any accessibility property of a UI element represented by an HWND. Here's a tiny code
46snippet showing how you could override the accessible name property (PROPID_ACC_NAME) to be the
47text "Accessible Name":
48
49```C++
50CComPtr<IAccPropServices> pAccPropSrv;
51pAccPropSrv.CoCreateInstance(CLSID_AccPropServices);
52COleVariant varName("Accessible Name");
53pAccPropSrv->SetHwndProp(hwnd, OBJID_CLIENT, 0, PROPID_ACC_NAME, varName);
54```
55
56#### Android
57
58On Android, if you don't want to subclass a View you can just set its accessibility delegate
59as an easy way to override one or more accessibility attributes. In this case we override
60the content description to say "Accessible Name".
61
62```Java
63view.setAccessibilityDelegate(new AccessibilityDelegate() {
64 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
65 super.onInitializeAccessibilityNodeInfo(host, info);
66 info.setContentDescription("Accessible Name");
67 }
68});
69```
70
71### Custom controls and subclassing
72
73When building a custom control, more work is often required. As an example,
74suppose an application is implementing a "cover flow" image picker, such as the
75one found in the original iTunes album picker. Conceptually the user is picking
76one album from a large list, but visually it's shown as a horizontally scrolling
77list of album cover images that fly by in three dimensions.
78
79![Screenshot of a cover flow image picker](images/cover_flow.jpg)
80
81While this control may be implemented as a single UI element, from the
82perspective of accessibility APIs it would typically be represented as
83a parent element with a "list box" role and children with "option" roles.
84This can't be done using the code snippets above, which are only sufficient
85for overriding some simple accessibility properties. A more complex custom
86control like this requires subclassing.
87
88To make the CoverFlow accessible, we would need to first need to subclass the
89appropriate accessibility interface, such as IAccessible on Windows or
90AccessibilityDelegate on Android. In addition to setting properties such as the
91name and role (like ComboBox on Windows, or Choice on Android), we'd want to
92override any methods that are used to walk the tree, in order to give this
93object accessible children - one for each option the user can pick.
94
95![Figure showing a single CoverFlow control in the UI object tree, and a tree of
96controls in the accessibility tree]( figures/cover_flow.png)
97
98Each option would be another instance of our subclass of an accessibility
99interface. Each one might need to implement a role, name, and very
100importantly, a bounding box representing the position of that option
101within the view's bounds.
102
103## A single-process browser for basic HTML only
104
105Let's next discuss what's needed in order to make a single-process web
106browser accessible. At the time Chrome was first released, this is
107more or less how other browsers such as Safari and Firefox worked.
108However, let's start with the simplifying assumption that we're dealing
109with basic HTML only, and no CSS or ARIA.
110
111From the perspective of accessibility APIs, the web contents is one
112big custom control. Modern web browsers do not build their UI using
113platform UI elements.
114
115*** note
116Years ago, some browsers may have rendered web pages using
117platform UI elements, but this doesn't scale well as most UI frameworks
118get bogged down after thousands of UI elements, whereas many web pages
119have hundreds of thousands of elements.
120
121In addition, note that web form controls support CSS effects
122including unusual ones like 3-D transformations, whereas most
123platform UI controls don't support, e.g. a 45-degree rotated
124text box.
125***
126
127The web contents can be represented as a tree of elements.
128For the moment let's ignore details between the DOM and the
129final rendered layout, and let's just assume that every DOM node
130corresponds perfectly to one node in the accessibility tree.
131
132Essentially the web browser needs to create one accessible
133object for every DOM node. The accessible object subclasses
134that platform's accessibility interface, and its accessible
135role, name, and other properties can all be computed by
136querying the corresponding DOM node. When DOM nodes are created
137or destroyed, the corresponding accessible objects need to
138be updated accordingly.
139
140Here's an example of a DOM tree and a corresponding accessibility
141tree. There's a 1:1 correspondence in this example.
142
143![Figure showing a tree of DOM nodes for a web page and a corresponding
144tree of accessibility nodes](
145figures/single_process.png)
146
147Objects in the accessibility tree are sometimes called "wrappers" in this
148design. Each accessible object "wraps" its corresponding DOM element. The DOM
149element contains all of the state, and the accessible object just implements the
150accessibility API based on the DOM element. This design avoids the need for DOM
151code to need to be tightly bound to accessibility code.
152
153For efficiency, these accessible objects are sometimes built
154lazily. Initially there could just be one accessible object
155for the root of the web contents. If that object is ever
156queried and asked for its children, the accessible objects
157corresponding to the children of the root DOM element could
158be created on-demand, and so on. This is useful because
159many users don't have any features enabled that use
160accessibility APIs, so very little work would be done
161unless they're utilized.
162
163The overall system so far is pretty simple - the DOM tree is used to
164build the accessibility tree, which is used to communicate with the
165platform accessibility APIs.
166
167![System diagram showing a browser consisting of a DOM tree that's used
168to build an accessibility tree, which is used to communicate with
169assistive technology using platform accessibility APIs.](
170figures/single_process_system.png)
171
172## A single-process browser with CSS and ARIA
173
174In the previous example we assumed that there was a 1:1 correspondence
175between a DOM node and an accessible node. Unfortunately that doesn't
176hold true. Here are some examples of where that assumption doesn't work.
177
178* CSS can have generated content, like list item markers (bullets or numbers)
179 or text inserted before or after an element with pseudoselectors
180 like ::before and ::after.
181* Some DOM subtrees are never displayed (like &lt;head&gt;) or are hidden using
182 display:none
183* Some DOM nodes are hidden using visibility:hidden, but it's possible for
184 some of their descendant nodes to be visible
185* aria-hidden can hide a subtree from the accessibility tree even if it's
186 displayed visually
187* ARIA role=none or role=presentation hides a node but not its subtree
188* aria-owns can be used to reparent a node within the accessibility tree
189
190So in practice, the accessibility tree is similar to the DOM tree, but with
191important differences. Objects in the accessibility tree usually wrap DOM
192nodes, but occasionally they wrap pseudoelements (like list markers or CSS
193generated content) or other layout objects with no corresponding node (such as
194images that are children of pseudoelements).
195
196Here's an example where the DOM tree has list items and the corresponding
197accessibility tree has nodes for the list item markers:
198
199![Figure showing a DOM tree with an ordered list of two items and the
200accessibility tree containing extra nodes for the generated list items](
201figures/generated_content.png)
202
203Here's a different example where some of the content is excluded from the
204accessibility tree using aria-hidden:
205
206![Figure showing a DOM tree with a sidebar with aria-hidden=true on it
207and the corresponding accessibility tree where the sidebar isn't present
208at all](
209figures/hidden_content.png)
210
211This new system diagram reflects the complexity of the system when
212you consider both HTML, CSS, and ARIA all affecting the accessibility
213tree.
214
215![System diagram showing a browser consisting of a DOM tree that along
216with CSS is used to build a Layout tree, then together the DOM and Layout
217trees build an accessibility tree, which is used to communicate with
218assistive technology using platform accessibility APIs.](
219figures/single_process_css_system.png)
220
221## A multi-process browser
222
223In the next section we'll explore how the system diagram needs to change
224in order to support a multi-process browser.
225
226See [How Chrome Accessibility Works, Part 2](how_a11y_works_2.md)