blob: 8658c7f687ae4678a9bda84f777536e0b81cfb89 [file] [log] [blame] [view]
Katie Dektarea84ef82017-12-04 17:17:331# Offscreen, Invisible and Size
2
3This document explains how Chrome interprets the guidelines to apply the labels
4Offscreen and Invisible to nodes, and how the bounding box is calculated.
5
6## Background
7
8In general, screen reading tools may be interested in all nodes regardless of
9whether they are presented to sighted users, but other Accessibility tools may
10care what is visible to sighted users.
11
12Specifically, tools like Select-to-Speak and Switch Access should not look at
13nodes which are offscreen”, invisible”, or size=(0,0), as these are not
14visible on the screen for mouse interactions. On the other hand, ChromeVox and
15other screen readers may care about some of those nodes, which allow developers
16to insert buttons visible only to users with a screen reader, or to navigate
17below the fold.
18
19## Offscreen
20In Chrome, we define Offscreen as:
21
22>Any object is offscreen if it is fully clipped or scrolled out of view by any
23of its ancestors so that it is not rendered on the screen.
24
25For example, the staticText node here is offscreen:
26```html
27<div style="width:0; height; 0; overflow: hidden">
28 This text should be marked "offscreen", although its parent is not.
29</div>
30```
31
32As background, [MSDN](https://msdn.microsoft.com/en-us/library/dd373609(VS.85).aspx)
33defines Offscreen as an object is not rendered, but not because it was
34programatically hidden:
35
36>The object is clipped or has scrolled out of view, but it is not
37programmatically hidden. If the user makes the viewport larger, more of the
38object will be visible on the computer screen.
39
40In Chrome, we interpret this to mean that an object is fully clipped or
41scrolled out of view by its parent or ancestors. The main difference is that
42we are being explicit that any ancestor clipping a node can make it offscreen,
43not just a rootWebArea or scrollable ancestor.
44
45### Technical Implementation
46Offscreen is calculated in [AXTree::RelativeToTreeBounds](https://cs.chromium.org/chromium/src/ui/accessibility/ax_tree.cc).
47In this function, we walk up the accessibility tree adjusting a node's bounding
48box to the frame of its ancestors. If the box is clipped because it lies
49outside an ancestor's bounds, and that ancestor clips its children (i.e.
50overflow:hidden, overflow:scroll, or it is a rootWebArea), offscreen is set to
51true.
52
53## Invisible
54A node is marked Invisible in Chrome if it is hidden programatically. In some
55cases, invisible nodes are simply excluded from the accessibility tree. Chrome
56defines invisible as:
57
58>Invisible means that a node or its ancestor is explicitly invisible.
59
60This is the same as the definition from [MSDN](https://msdn.microsoft.com/en-us/library/dd373609(VS.85).aspx):
61
62>The object is programmatically hidden.
63
64For example, these nodes are invisible:
65
66```html
67<div style="display:none">
68 This text should be marked 'invisible', along with its parent div.
69</div>
70
71<div style="visibility:hidden">
72 This text should also be marked 'invisible' along with its parent div.
73</div>
74
75<div style="opacity:0">
76 Opactiy zero is also treated as invisible.
77</div>
78```
79
80## Bounding box calculation
81A node's bounding box (location and size) are calculated based on its
82intrinsic width, height and location, and the sizes of its ancestors.
83We calculate size clipped by ancestors by default, but can also expose an
84unclipped size through the [automation API](https://developer.chrome.com/extensions/automation).
85
86The unclipped bounding box is helpful if you want to know the current
87coordinates of an element that's scrolled out of view, so you know how
88much to scroll to bring it in view.
89
90The clipped bounding box is helpful if you want to draw a visible bounding
91box around the element on the screen. Clipping the bounding box helps
92sighted users understand what container the element is in, even if it's
93not currently visible. Without clipping you end up with elements floating
94outside of windows.
95
96### Technical implementation
97A node's location and size are calculated in[AXTree::RelativeToTreeBounds](https://cs.chromium.org/chromium/src/ui/accessibility/ax_tree.cc),
98and so closely tied to the offscreen calculation. In this function, we walk up
99the accessibility tree adjusting a node's bounding box to the frame of its
100ancestors.
101
102In general, this calculation is straight forward. But there are several edge
103cases:
104
105* If a node has no intrinsic size, its size will be taken from the union of
106its children.
107
108```html
109 <!-- The outer div here has no size, so we use its child for its bounding box -->
110 <div style="visibility:hidden" aria-hidden=false>
111 <div style="visibility:visible">
112 Visible text
113 </div>
114 </div>
115```
116
117* If a node still has no size after that union, its bounds will be set to the
118size of the nearest ancestor which has size. However, this node will be marked
119`offscreen`, because it isn't visible to the user.
120
121 * This is useful for exposing nodes to screen reader users.
122
123In addition, [AXTree::RelativeToTreeBounds](https://cs.chromium.org/chromium/src/ui/accessibility/ax_tree.cc)
124is used to determine how location and size may be clipped by ancestors,
125allowing bounding boxes to reflect the location of a node clipped to its
126ancestors.
127
128* If a node is fully clipped by its ancestors such that the intersection of its
129bounds and an ancestor's bounds are size 0, it will be pushed to the nearest
130edge of the ancestor with width 1 or height 1.
131
132 * We use width and height 1 instead of 0 to distinguish between empty or
133 unknown sized nodes vs known small or clipped sized nodes.
134
135Both clipped and unclipped location and size are exposed through the
136[Chrome automation API](https://developer.chrome.com/extensions/automation).
137
138* `location` is the global location of a node as clipped by its ancestors. If
139a node is fully scrolled off a rootWebArea in X, for example, its location will
140be the height of the rootWebArea, and its height will be 1. The Y position and width will be unchanged.
141
142* `unclippedLocation` is the global location of a node ignoring any clipping
143by ancestors. If a node is fully scrolled off a rootWebArea in X, for example,
144its location will simply be larger than the height of the rootWebArea, and its
145size will also be unchanged.