Skip to content
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

feat: fix accessibility of the captions setting dialog #4050

Merged
merged 16 commits into from
Feb 21, 2017

Conversation

gkatsev
Copy link
Member

@gkatsev gkatsev commented Feb 9, 2017

This fixes a lot of the issues from #2746 by making the dialog inherit from our actual ModalDialog which now has tab focus trapping.
Todo copied from #2746 to track what has been fixed. #2746 should be used to track what has been verified as fixed.

The Captions Settings dialog has some accessibility issues:

  • Field labels and fields are not explicitly associated
  • Keyboard focus does not move into the dialog when it is opened
  • Keyboard focus is not trapped inside the dialog while it is open
  • Keyboard focus does not return to the control which opened the dialog when it is closed
  • The extent (top and bottom) of the dialog is not indicated to screen readers
  • The dialog cannot be closed with the Esc key
  • The meaning of '---' in the select fields is not clear
  • The control to close the dialog is labeled "Done" rather than "Close"
  • The purpose of the "Defaults" button may not be obvious, and its effect may not be apparent to screen reader users
  • Focus highlighting (outline) on the Default and Done buttons is very hard to see
  • Pressing the Done button doesn’t seem to have the same effect as pressing the Close (x) button; does it trigger the same focus movement
  • This requirement to move it back to the triggering element is tricky, since clicking on that item in the CC menu dismisses the CC menu. I need to think about this a little more - either the menu should open again, or the focus should go to the main CC Menu Button
  • The focus outline on the whole dialog goes too far to the left (all the way to the edge of the video window, not just to the edge of the dialog)

@gkatsev
Copy link
Member Author

gkatsev commented Feb 9, 2017

@OwenEdwards I'm not sure how the "extent" is supposed to be specified.

@OwenEdwards
Copy link
Member

Here's the idea of the "extent" of the dialog:

The top and bottom of the dialog area are clearly marked for sighted users. Focus is constrained inside the dialog, but a screen reader user can use the up and down arrow keys to move the "virtual cursor" and read content which isn't focusable/actionable. If they move out of the top or bottom of the dialog and into other content in the DOM, they may not realize that this has happened, and may become confused/lost.

The preferred solution is to use aria-hidden="true" on all of the rest of the page except the dialog - this is tricky because aria-hidden doesn't nest, so you can't have aria-hidden="false" on the dialog element when it is a child of the main page which has aria-hidden="true". So you need to mark everything else as aria-hidden, or have a structure like this:

<body>
    <div class="main" aria-hidden="true> ... </div>
    <div role="dialog" ... > .... </div>
</body>

Alternatively, you can use hidden (screen reader only) text to say "Start of modal dialog", "End of modal dialog" at exactly the place where the extent of the dialog is visibly marked in the DOM.

There has been some talk that marking an ARIA region, or even the role="dialog", ought to be enough in itself, but screen readers don't always announce movement of the virtual cursor into/out of an ARIA region.

@gkatsev
Copy link
Member Author

gkatsev commented Feb 9, 2017

It sounds like have a "start" and "end" elements that are only available to screen readers is what we want.

@OwenEdwards
Copy link
Member

Right, and I forgot that we already have Beginning of dialog window...., so we only need End of dialog window.

@gkatsev
Copy link
Member Author

gkatsev commented Feb 9, 2017

@OwenEdwards this is ready for testing. Only issue is #4049.

@gkatsev gkatsev added the a11y This item might affect the accessibility of the player label Feb 10, 2017
@gkatsev
Copy link
Member Author

gkatsev commented Feb 10, 2017

@OwenEdwards I'm not really sure how to improve the highlighting of the defaults and done buttons. Both of those are using the default outlines when just using the keyboard or using voiceover.

The others can definitely be fixed and I've already fixed the last one.

@gkatsev
Copy link
Member Author

gkatsev commented Feb 10, 2017

I decided to update it so that it re-focuses on the captions button when it is closed.

Copy link
Member

@OwenEdwards OwenEdwards left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with IE11 & JAWS - a couple of changes needed. Also, it's failing one of the tests: ModalDialog should create the expected description element.

}),
createEl('select', {id}, undefined, config.options.map(o => {
createEl('select', {}, {
'aria-labeledby': `${legendId} ${id}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TYPO? aria-labelledby isn't spelled the way you'd expect!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, oops.

textContent: this.localize(o[1]),
value: o[0]
}, {
'aria-labeledby': `${legendId} ${id} ${optionId}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to aria-label each <option>, only the <select>.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was testing with voiceover on mac. Seems like Safari reads it out like White, Text Color, menu item but on chrome it reads it out only as white unless I add this labelledby.

Copy link
Member

@misteroneill misteroneill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like several methods of TextTrackSettings are missing JSDoc comments.

@gkatsev
Copy link
Member Author

gkatsev commented Feb 14, 2017

@misteroneill all the missing jsdocs are fixed by adding @extends ModalDialog.

textContent: this.localize(o[1]),
value: o[0]
}, {
'aria-labelledby': `${legendId} ${id} ${optionId}`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OwenEdwards did we have an answer whether we should keep this because of VO and Chrome or remove it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned about how well this will work - there's a circular reference where the label for this element includes the id of two other elements, and then the id of this element. The behavior in this situation is mentioned in the W3C Accessible Name Computation - Text Alternative Computation:

if computing a name, and the current node has a non-empty aria-labelledby attribute, and the current node is not already part of an aria-labelledby traversal, process its IDREFs in the order they occur:

but it may not work correctly in all browsers. I guess we'll just have to fix it if that happens?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from the little I understand about this, I think it should be fine and it falls within what the spec allows.
I'm 👌 with leaving this and then fixing in the future if we find an issue.

textContent: this.localize(o[1]),
value: o[0]
}, {
'aria-labelledby': `${legendId} ${id} ${optionId}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned about how well this will work - there's a circular reference where the label for this element includes the id of two other elements, and then the id of this element. The behavior in this situation is mentioned in the W3C Accessible Name Computation - Text Alternative Computation:

if computing a name, and the current node has a non-empty aria-labelledby attribute, and the current node is not already part of an aria-labelledby traversal, process its IDREFs in the order they occur:

but it may not work correctly in all browsers. I guess we'll just have to fix it if that happens?

@gkatsev gkatsev force-pushed the caption-settings-modal branch from e30adff to 1946cbe Compare February 16, 2017 19:14
const defaultsButton = createEl('button', {
className: 'vjs-default-button',
textContent: this.localize('Defaults')
title: defaultsDescription,
innerHTML: `${this.localize('Defaults')}<span class='vjs-control-text'> - ${defaultsDescription}</span>`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OwenEdwards @mmcc brought up that maybe 'Reset' would be a better name for this button, thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would work fine - if the button is marked 'Reset', then the hidden text can be ' all settings to the default values', and you don't need the ' - ' in the hidden text.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reset seems like a better name to me

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@@ -457,6 +485,10 @@ class TextTrackSettings extends Component {
* The element that was created.
*/
createEl() {
return super.createEl();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if we need this here, won't this be the default behavior?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Um... yeah, probably not needed.

return super.createEl();
}

content() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function and a few of the funcitons below this need jsdoc comments

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSDoc gets them from the parent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a11y This item might affect the accessibility of the player confirmed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants