Skip to content
This repository was archived by the owner on Dec 7, 2022. It is now read-only.

Commit 782da95

Browse files
author
Alice Boxhall
committed
Avoid walking entire parent tree unnecessarily in isElementOrAncestorHidden.
1 parent 34c11c2 commit 782da95

File tree

4 files changed

+39
-21
lines changed

4 files changed

+39
-21
lines changed

src/js/AccessibilityUtils.js

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,6 @@ axs.utils.getContrastRatioForElement = function(element) {
430430
* @return {?number}
431431
*/
432432
axs.utils.getContrastRatioForElementWithComputedStyle = function(style, element) {
433-
if (axs.utils.isElementHidden(element))
434-
return null;
435-
436433
var bgColor = axs.utils.getBgColor(style, element);
437434
if (!bgColor)
438435
return null;
@@ -569,22 +566,41 @@ axs.utils.isElementDisabled = function(element) {
569566

570567
/**
571568
* @param {Element} element An element to check.
572-
* @return {boolean} True if the element is hidden from accessibility.
569+
* @return {boolean} True if an element itself has a style attribute which causes it
570+
* not to be visible.
573571
*/
574-
axs.utils.isElementHidden = function(element) {
575-
if (!(element instanceof element.ownerDocument.defaultView.HTMLElement))
576-
return false;
577-
578-
if (element.hasAttribute('chromevoxignoreariahidden'))
579-
var chromevoxignoreariahidden = true;
580-
572+
axs.utils.elementHasNonVisibleStyle = function(element) {
581573
var style = window.getComputedStyle(element, null);
582574
if (style.display == 'none' || style.visibility == 'hidden')
583575
return true;
576+
return false;
577+
}
578+
579+
/**
580+
* @param {Element} element An element to check.
581+
* @return {boolean} True if the element is not visible to any user.
582+
*/
583+
axs.utils.elementIsNotVisible = function(element) {
584+
if (axs.utils.elementHasNonVisibleStyle(element))
585+
return true;
586+
var boundingClientRect = element.getBoundingClientRect();
587+
if (boundingClientRect.width === 0 && boundingClientRect.height === 0 &&
588+
boundingClientRect.top === 0 && boundingClientRect.bottom === 0 &&
589+
boundingClientRect.left === 0 && boundingClientRect.right === 0) {
590+
return true;
591+
}
592+
return false;
593+
}
584594

595+
/**
596+
* @param {Element} element An element to check.
597+
* @return {boolean} True if the element is hidden from accessibility.
598+
*/
599+
axs.utils.elementIsAriaHidden = function(element) {
585600
if (element.hasAttribute('aria-hidden') &&
586-
element.getAttribute('aria-hidden').toLowerCase() == 'true') {
587-
return !chromevoxignoreariahidden;
601+
element.getAttribute('aria-hidden').toLowerCase() == 'true' &&
602+
!document.documentElement.hasAttribute('chromevoxignoreariahidden')) {
603+
return true;
588604
}
589605

590606
return false;
@@ -596,7 +612,9 @@ axs.utils.isElementHidden = function(element) {
596612
* hidden from accessibility.
597613
*/
598614
axs.utils.isElementOrAncestorHidden = function(element) {
599-
if (axs.utils.isElementHidden(element))
615+
if (axs.utils.elementIsNotVisible(element))
616+
return true;
617+
if (axs.utils.elementIsAriaHidden(element))
600618
return true;
601619

602620
if (axs.dom.parentElement(element))

test/audits/aria-on-reserved-element-test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646

4747
test('Reserved element with role and aria- attributes', function() {
4848
var fixture = document.getElementById('qunit-fixture');
49-
var widget = fixture.appendChild(document.createElement('meta'));
49+
var widget = fixture.appendChild(document.createElement('map'));
5050
widget.setAttribute('role', 'spinbutton');
5151
widget.setAttribute('aria-hidden', 'false'); // global
5252
widget.setAttribute('aria-required', 'true'); // supported
@@ -59,23 +59,23 @@
5959

6060
test('Reserved element with role only', function() {
6161
var fixture = document.getElementById('qunit-fixture');
62-
var widget = fixture.appendChild(document.createElement('meta'));
62+
var widget = fixture.appendChild(document.createElement('map'));
6363
widget.setAttribute('role', 'spinbutton');
6464
var expected = { elements: [widget], result: axs.constants.AuditResult.FAIL };
6565
deepEqual(rule.run({ scope: fixture }), expected, 'Reserved elements can\'t take any ARIA attributes.');
6666
});
6767

6868
test('Reserved element with aria-attributes only', function() {
6969
var fixture = document.getElementById('qunit-fixture');
70-
var widget = fixture.appendChild(document.createElement('meta'));
70+
var widget = fixture.appendChild(document.createElement('map'));
7171
widget.setAttribute('aria-hidden', 'false'); // global
7272
var expected = { elements: [widget], result: axs.constants.AuditResult.FAIL };
7373
deepEqual(rule.run({ scope: fixture }), expected, 'Reserved elements can\'t take any ARIA attributes.');
7474
});
7575

7676
test('Using ignoreSelectors, reserved element with aria-attributes only', function() {
7777
var fixture = document.getElementById('qunit-fixture');
78-
var widget = fixture.appendChild(document.createElement('meta'));
78+
var widget = fixture.appendChild(document.createElement('map'));
7979
var ignoreSelectors = ['#' + (widget.id = 'ignoreMe')];
8080
widget.setAttribute('aria-hidden', 'false'); // global
8181
var expected = { result: axs.constants.AuditResult.NA };
@@ -84,7 +84,7 @@
8484

8585
test('Reserved element with no ARIA attributes', function() {
8686
var fixture = document.getElementById('qunit-fixture');
87-
fixture.appendChild(document.createElement('meta'));
87+
fixture.appendChild(document.createElement('map'));
8888
var expected = { elements: [], result: axs.constants.AuditResult.PASS };
8989
deepEqual(rule.run({ scope: fixture }), expected, 'A reserved element with no ARIA attributes should pass');
9090
});

test/audits/bad-aria-attribute-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
*/
6161
test('Element with role and global but missing supported and required attributes', function() {
6262
var fixture = document.getElementById('qunit-fixture');
63-
var widget = fixture.appendChild(document.createElement('meta')); // note, a reserved HTML element
63+
var widget = fixture.appendChild(document.createElement('map')); // note, a reserved HTML element
6464
widget.setAttribute('role', 'spinbutton');
6565
widget.setAttribute('aria-hidden', 'false'); // global (so the audit will encounter this element)
6666
var expected = { elements: [], result: axs.constants.AuditResult.PASS };

test/audits/unsupported-aria-attribute-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
*/
6767
test('Element with role and global but missing supported and required attributes', function() {
6868
var fixture = document.getElementById('qunit-fixture');
69-
var widget = fixture.appendChild(document.createElement('meta')); // note, a reserved HTML element
69+
var widget = fixture.appendChild(document.createElement('map')); // note, a reserved HTML element
7070
var expected = { elements: [], result: axs.constants.AuditResult.PASS };
7171
widget.setAttribute('role', 'spinbutton');
7272
widget.setAttribute('aria-hidden', 'false'); // global (so the audit will encounter this element)

0 commit comments

Comments
 (0)