-
Notifications
You must be signed in to change notification settings - Fork 75
New rule: Content triggered on hover is hoverable (ep1s13) #1396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
f109b97
5c20803
090fbb3
393c4de
cb5b248
33c9b18
d0a18d4
6cbddb3
e223fd1
234efdd
94d5bb8
2c2e2d3
46a2d85
395db17
d6acc0e
fae5c5e
4333a26
0d80d3b
d1c5415
39dd0b9
6385d29
fbc3aa9
58c7d33
fec59f6
6762af2
ff84c74
8916e70
c0ea1e0
b464dae
8cb273e
c1d16c9
71a73d8
e31b821
527f9cd
45c552f
050a60d
a693b76
bf5528c
35d92db
c6ed956
8d6c6bc
4cb492d
f5ce160
e8b272d
2a36383
5994410
fdfca64
9eae6f9
70eb886
f2c882f
db0d914
f86a116
40618d3
e06744e
d7f0ef8
876bab4
5bfaa59
034aaab
5f7cf90
74bcce6
08926d1
e6155c2
00b9758
dc254c0
ca18503
141ff43
6ccf74c
d6c03c9
65e7c42
30e6850
996b043
602745c
7af8cad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
--- | ||
id: ep1s13 | ||
name: Additional content triggered on hover is hoverable | ||
rule_type: atomic | ||
description: | | ||
This rule checks that any additional content that was triggered by hovering an element can be reached from that element and remains available to the user while the mouse pointer is over the element or the additional content | ||
accessibility_requirements: | ||
wcag21:1.4.13: # Content on Hover or Focus (AA) | ||
forConformance: true | ||
failed: not satisfied | ||
passed: further testing needed | ||
inapplicable: further testing needed | ||
input_aspects: | ||
- DOM Tree | ||
- CSS Styling | ||
- Mouse pointer | ||
acknowledgments: | ||
authors: | ||
- Carlos Duarte | ||
--- | ||
|
||
## Applicability | ||
|
||
The rule applies to any element in a [web page][] with [content that becomes visible][]. | ||
|
||
### Applicable states (transitions?) | ||
|
||
This rule applies if all of the following is true: | ||
|
||
- the [content becomes visible][content that becomes visible] after the test target transitions from the not [hovered][] state to the [hovered][] state; and | ||
- the [content becomes invisible][content that becomes invisible] after the test target transitions from the [hovered][] state to the not [hovered][] state, except if the content itself is in the [hovered][] state. | ||
|
||
## Expectation 1 | ||
|
||
The target element's [bounding box][] is [adjacent][] or [overlaps][] the [bounding box][] of the [content that becomes visible][]. | ||
|
||
## Expectation 2 | ||
|
||
The [content that becomes visible][] remains [visible][]. | ||
|
||
Comments for reviewers: how to test this in practice? A tester will never know for sure if in the next second the content won't vanish. The previous version of the rule required this for only 1 minute (the assumption is still below). | ||
|
||
### Expected state (transitions?) | ||
|
||
The above expectations must hold while any of the following are true: | ||
|
||
- the test target is in the [hovered][] state; or | ||
- the [content that became visible][content that becomes visible] is in the [hovered][] state. | ||
|
||
## Assumptions | ||
|
||
- The user does not dismiss the content causing the changes in content by pressing a key on the keyboard. In this instance the rule will fail while [success criterion 1.4.13: Content on Hover or Focus][sc1.4.13] might be satisfied. | ||
- The content that becomes visible does not become irrelevant. In this instance the rule will fail while [success criterion 1.4.13: Content on Hover or Focus][sc1.4.13] might be satisfied. | ||
- This rule assumes that the additional content that becomes visible does not disappear after 1 minute of being triggered by the hovering event. If the content disappears after this time span the rule may pass but [Success Criterion 1.4.13: Content on Hover or Focus][sc1.4.13] is not satisfied. The arbitrary 1 minute time span, selected so that testing this rule would not be impractical, is not included in WCAG. | ||
|
||
## Accessibility Support | ||
|
||
_No accessibility support issues known._ | ||
|
||
## Background | ||
|
||
- [Understanding Success Criterion 1.4.13: Content on Hover or Focus][sc1.4.13] | ||
- [F95: Failure of Success Criterion 1.4.13 due to content shown on hover not being hoverable](https://www.w3.org/WAI/WCAG21/Techniques/failures/F95) | ||
|
||
## Test Cases | ||
|
||
### Passed | ||
|
||
#### Passed Example 1 | ||
|
||
This button element causes [content to become visible][content that becomes visible] by presenting a tooltip when [hovered][]. The tooltip is [adjacent][] to the button element and remains displayed while the mouse pointer does not leave its boundaries. | ||
|
||
```html | ||
<link rel="stylesheet" type="text/css" href="/test-assets/ep1s13/styles.css" /> | ||
<script src="/test-assets/ep1s13/scripts.js"></script> | ||
|
||
<body onload="bindEvents({tooltipRemains: true})"> | ||
<div class="tooltip-container"> | ||
<button aria-labelledby="tooltip"> | ||
<span>WCAG</span> | ||
</button> | ||
<p id="tooltip" role="tooltip" hidden>Web Content Accessibility Guidelines</p> | ||
</div> | ||
</body> | ||
``` | ||
|
||
#### Passed Example 2 | ||
|
||
This list item element causes [content to become visible][content that becomes visible] by presenting a menu item when [hovered][]. The menu item is [adjacent][] to the list item element and remains displayed while the mouse pointer does not leave its boundaries. | ||
|
||
```html | ||
<link rel="stylesheet" type="text/css" href="test-assets/ep1s13/styles_menu.css" /> | ||
<script src="test-assets/ep1s13/scripts.js"></script> | ||
|
||
<body onload="bindEvents({tooltipRemains: true})"> | ||
<div> | ||
<ul class="tooltip-container"> | ||
<li>menu</li> | ||
<div role="tooltip" hidden> | ||
<ul class="tooltip-container"> | ||
<li>submenu</li> | ||
<div role="tooltip" hidden> | ||
<ul> | ||
<li>subsubmenu</li> | ||
</ul> | ||
</div> | ||
</ul> | ||
</div> | ||
</ul> | ||
</div> | ||
</body> | ||
``` | ||
|
||
### Failed | ||
|
||
#### Failed Example 1 | ||
|
||
This button element causes [content to become visible][content that becomes visible] by presenting a tooltip when [hovered][]. However, the tooltip is not [adjacent][] neither [overlaps][] the button. | ||
|
||
```html | ||
<link rel="stylesheet" type="text/css" href="/test-assets/ep1s13/stylesbad.css" /> | ||
<script src="/test-assets/ep1s13/scripts.js"></script> | ||
|
||
<body onload="bindEvents({tooltipRemains: true})"> | ||
<div class="tooltip-container"> | ||
<button aria-labelledby="tooltip"> | ||
<span>WCAG</span> | ||
</button> | ||
<p id="tooltip" role="tooltip" hidden>Web Content Accessibility Guidelines</p> | ||
</div> | ||
</body> | ||
``` | ||
|
||
#### Failed Example 2 | ||
|
||
This button element causes [content to become visible][content that becomes visible] by presenting a tooltip when [hovered][]. The tooltip is [adjacent[] to the button element but does not remain visible when the mouse pointer is inside its boundaries. | ||
|
||
```html | ||
<link rel="stylesheet" type="text/css" href="/test-assets/ep1s13/styles.css" /> | ||
<script src="/test-assets/ep1s13/scripts.js"></script> | ||
|
||
<body onload="bindEvents({tooltipRemains: false})"> | ||
<div class="tooltip-container"> | ||
<button aria-labelledby="tooltip"> | ||
<span>WCAG</span> | ||
</button> | ||
<p id="tooltip" role="tooltip" hidden>Web Content Accessibility Guidelines</p> | ||
</div> | ||
</body> | ||
``` | ||
|
||
### Inapplicable | ||
|
||
#### Inapplicable Example 1 | ||
|
||
This element does not cause [content to become visible][content that becomes visible] when [hovered][]. | ||
|
||
```html | ||
<button>WCAG</button> | ||
``` | ||
|
||
[adjacent]: #adjacent 'Definition of adjacent' | ||
[bounding box]: https://www.w3.org/TR/css-ui-3/#valdef-box-sizing-border-box | ||
[center]: #center 'Definition of center of a bounding box' | ||
[content that becomes invisible]: #content-that-becomes-invisible 'Definition of content that becomes invisible' | ||
[content that becomes visible]: #content-that-becomes-visible 'Definition of content that becomes visible' | ||
[hovered]: #hovered 'Definition of hovered' | ||
[overlaps]: #overlap 'Definition of overlap' | ||
[sc1.4.13]: https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html 'Understanding Success Criterion 1.4.13: Content on Hover or Focus, July 24, 2020' | ||
[visible]: #visible 'Definition of visible' | ||
[web page]: #web-page-html 'Definition of HTML web page' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--- | ||
title: Adjacent | ||
key: adjacent | ||
unambiguous: true | ||
objective: true | ||
input_aspects: | ||
- CSS styling | ||
- DOM tree | ||
--- | ||
|
||
[Bounding boxes][] A and B are _adjacent_ if they do not [overlap][] and at least one point from box A is at the Euclidean distance of 1 [CSS pixel][] from one point in box B. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little nervous about this being exactly 1px with no margin of error. I think we should include anything less than 2, and greater than 0. |
||
|
||
[bounding boxes]: https://drafts.csswg.org/cssom-view/#dom-element-getboundingclientrect 'Definition of getBoundingClientRect' | ||
[CSS pixel]: https://drafts.csswg.org/css-values-3/#visual-angle-unit | ||
[overlap]: #overlap 'Definition of overlap' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
title: Center | ||
key: center | ||
unambiguous: true | ||
objective: true | ||
input_aspects: | ||
- CSS styling | ||
- DOM tree | ||
--- | ||
|
||
The _center_ of a [bounding box][] is the point given by the following coordinates: | ||
|
||
- The [x coordinate][] is equal to the [left coordinate][] of the [bounding box][] plus half its [width][]; and | ||
- The [y coordinate][] is equal to the [top coordinate][] of the [bounding box][] plus half its [height][]. | ||
|
||
[bounding box]: https://drafts.csswg.org/cssom-view/#dom-element-getboundingclientrect 'Definition of getBoundingClientRect' | ||
[height]: https://drafts.fxtf.org/geometry/#rectangle-height-dimension | ||
[left coordinate]: https://drafts.fxtf.org/geometry/#dom-domrectreadonly-left | ||
[top coordinate]: https://drafts.fxtf.org/geometry/#dom-domrectreadonly-top | ||
[width]: https://drafts.fxtf.org/geometry/#rectangle-width-dimension | ||
[x coordinate]: https://drafts.fxtf.org/geometry/#rectangle-x-coordinate | ||
[y coordinate]: https://drafts.fxtf.org/geometry/#rectangle-y-coordinate |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
--- | ||
title: Content that becomes invisible | ||
key: content-that-becomes-invisible | ||
unambiguous: true | ||
objective: true | ||
input_aspects: | ||
- CSS styling | ||
- DOM tree | ||
--- | ||
|
||
The _content that becomes invisible_ is the [root][] element of the [tree][], if a [tree][] exists, that contains all elements that, after half a second of an [event][] [firing][], meet any of the following: | ||
|
||
- the element is removed from the [web page][] where the [event][] was [fired][firing] and the element had [visible text content][]; or | ||
- the element has [attributes][] whose [values][] changed from what they were before the [event][] [firing][] and the change caused some or all of the element's [text nodes][] to stop being [visible][]. | ||
|
||
[attributes]: https://dom.spec.whatwg.org/#concept-attribute 'Definition of attribute' | ||
[event]: https://dom.spec.whatwg.org/#concept-event 'Definition of event' | ||
[firing]: https://dom.spec.whatwg.org/#concept-event-fire 'Definition of event firing' | ||
[root]: https://dom.spec.whatwg.org/#concept-tree-root 'Definition of root' | ||
[text nodes]: https://dom.spec.whatwg.org/#text 'Definition of DOM text' | ||
[tree]: https://dom.spec.whatwg.org/#concept-tree 'Definition of tree' | ||
[values]: https://dom.spec.whatwg.org/#concept-attribute-value 'Definition of attribute value' | ||
[visible]: #visible 'Definition of visible' | ||
[visible text content]: #visible-text-content 'Definition of visible text content' | ||
[web page]: #web-page-html 'Definition of web page' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--- | ||
title: Content that becomes visible | ||
key: content-that-becomes-visible | ||
unambiguous: true | ||
objective: true | ||
input_aspects: | ||
- CSS styling | ||
- DOM tree | ||
--- | ||
|
||
The _content that becomes visible_ after an [event][] [firing][] is any element for which all of the following is true: | ||
|
||
- 500 milliseconds after the [event][] [firing][] the element has [visible text content][]; and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to capture an assumption that content on hover will appear within 500ms. |
||
- a tick before the [event][] [firing][] there was no element with the same [descendant text content][] that the element has after the [event][] [firing][]; and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems to me like this would apply to elements that update their content too. If I have a button that changes its text on hover, it 1. has visible content after the event. and 2. does not have the same descendant text content. Additionally, descendant text content does not take shadow DOM into account. |
||
- the element has no [descendants][] for which the above two conditions are true. | ||
|
||
[descendants]: https://dom.spec.whatwg.org/#concept-tree-descendant | ||
[descendant text content]: https://dom.spec.whatwg.org/#concept-descendant-text-content 'Definition of descendant text content' | ||
[event]: https://dom.spec.whatwg.org/#concept-event 'Definition of event' | ||
[firing]: https://dom.spec.whatwg.org/#concept-event-fire 'Definition of event firing' | ||
[visible text content]: #visible-text-content 'Definition of visible text content' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
title: Hovered | ||
key: hovered | ||
unambiguous: true | ||
objective: true | ||
input_aspects: | ||
- DOM tree | ||
--- | ||
|
||
An element is hovered (by a pointing device) when that element matches the [`:hover` pseudo-class](https://drafts.csswg.org/selectors-4/#hover-pseudo). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
title: Overlap | ||
key: overlap | ||
unambiguous: true | ||
objective: true | ||
input_aspects: | ||
- CSS styling | ||
- DOM tree | ||
--- | ||
|
||
[Bounding boxes][] A and B _overlap_ if one of the following is true: | ||
|
||
- the value of the [x coordinate][] property of box A is between the values of the [top][] and [bottom][] properties of box B and the value of the [y coordinate][] of box A is between the values of the [left][] and [right][] properties of box B; or | ||
- the value of the [x coordinate][] property of box B is between the values of the [top][] and [bottom][] properties of box A and the value of the [y coordinate][] of box B is between the values of the [left][] and [right][] properties of box A. | ||
|
||
[bounding boxes]: https://drafts.csswg.org/cssom-view/#dom-element-getboundingclientrect 'Definition of getBoundingClientRect' | ||
[bottom]: https://drafts.fxtf.org/geometry-1/#dom-domrectreadonly-bottom | ||
[left]: https://drafts.fxtf.org/geometry-1/#dom-domrectreadonly-left | ||
[right]: https://drafts.fxtf.org/geometry-1/#dom-domrectreadonly-right | ||
[top]: https://drafts.fxtf.org/geometry-1/#dom-domrectreadonly-top | ||
[x coordinate]: https://drafts.fxtf.org/geometry-1/#dom-domrectreadonly-x | ||
[y coordinate]: https://drafts.fxtf.org/geometry-1/#dom-domrectreadonly-y |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
function bindEvents(bind) { | ||
let containers; | ||
if (bind.tooltipRemains) | ||
containers = document.querySelectorAll(".tooltip-container"); | ||
else | ||
containers = document.querySelectorAll("button"); | ||
for (const container of containers) { | ||
container.addEventListener("mouseenter", () => { | ||
console.log(container); | ||
showTooltip(container); | ||
}); | ||
container.addEventListener("mouseleave", () => { | ||
hideTooltip(container); | ||
}); | ||
} | ||
} | ||
|
||
function showTooltip(elem) { | ||
const tooltip = elem.querySelector("[role=tooltip]"); | ||
console.log(tooltip); | ||
tooltip.removeAttribute("hidden"); | ||
} | ||
|
||
function hideTooltip(elem) { | ||
const tooltip = elem.querySelector("[role=tooltip]"); | ||
tooltip.setAttribute("hidden", "hidden"); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
:root { | ||
--tooltip-thingy-width: 0.5em; | ||
} | ||
|
||
.tooltip-container { | ||
position: relative; | ||
display: inline-block; | ||
} | ||
|
||
[role="tooltip"] { | ||
position: absolute; | ||
top: 0%; | ||
left: 100%; | ||
transform: translateY(-60%) translateX(2%); | ||
padding: 0.5em 0.5em; | ||
color: white; | ||
background: black; | ||
min-width: max-content; | ||
} | ||
|
||
[role="tooltip"]::before { | ||
position: absolute; | ||
left: 0; | ||
top: 0; | ||
transform: translateY(50%) translateX(-99%); | ||
border: var(--tooltip-thingy-width) solid transparent; | ||
border-right-color: black; | ||
content: ""; | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.