зеркало из https://github.com/mozilla/treeherder.git
217 строки
9.3 KiB
Markdown
217 строки
9.3 KiB
Markdown
# Accessibility
|
|
|
|
## General Practices
|
|
|
|
As a general rule, accessible software is achieved by following web development best practices. As Treeherder uses the [reactstrap](https://reactstrap.github.io/) library, it is recommended to use one of its components, if possible.
|
|
|
|
If you can not find a suitable component, prefer [HTML5 semantic tags](https://developer.mozilla.org/en-US/docs/Glossary/Semantics#Semantics_in_HTML) and avoid using generic tags, such as `span` and `div`. Moreover, try to use more **headings** (`h1` to `h6`) whenever possible, because screen readers users usually navigate by headings and that is only possible when developers insert them in the code.
|
|
|
|
If you can build your layout neither with reactstrap nor with semantic tags, please insert `aria-role` in them. There are examples of how to use `aria-role` in: [Tables](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Table_Role), [Progress Bar](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_progressbar_role), [List](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/List_role).
|
|
|
|
`aria-role` is important because it gives meaning to the generic HTML tag. That gives some direction to screen readers on which functionalities to provide and some information to users.
|
|
|
|
**In summary**, implement your layout trying to use these in the following order:
|
|
|
|
1. Use reactstrap;
|
|
2. Use HTML semantic tags;
|
|
3. Use `aria-role` attributes.
|
|
|
|
### Font Awesome
|
|
|
|
Treeherder also uses the `Font Awesome` library for some icons. Usually, there is no need to insert an additional explanation to them. However, if the icon has a semantic meaning, you can insert it by adding a `title` prop in the `FontAwesomeIcon` component.
|
|
|
|
```jsx
|
|
<FontAwesomeIcon icon={icon} title="Icon description" />
|
|
```
|
|
|
|
## Colors
|
|
|
|
Treeherder uses [Bootstrap color](https://getbootstrap.com/docs/4.0/utilities/colors/) utility classes. A few colors were modified in order to meet [WCAG standards](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_WCAG/Perceivable/Color_contrast?utm_source=devtools&utm_medium=a11y-panel-checks-color-contrast) for color contrast.
|
|
|
|
Please use this custom color according to the following table:
|
|
|
|
| Bootstrap Color | Treeherder Color |
|
|
| ---------------: | :--------------------- |
|
|
| `btn-info` | `btn-darker-info` |
|
|
| `text-info` | `text-darker-info` |
|
|
| `btn-secondary` | `btn-darker-secondary` |
|
|
| `text-secondary` | `text-darker-secondary` |
|
|
|
|
For example, if inserting a text color into an element, use `className="text-darker-info"`, instead of using `className="text-info"`.
|
|
|
|
In some reactstrap components, you can insert a `prop` specifying its color. In that case, you use only the color name, without its prefix.
|
|
|
|
| Component prop color |
|
|
| :------------------: |
|
|
| `darker-info` |
|
|
| `darker-secondary` |
|
|
|
|
For example:
|
|
|
|
```jsx
|
|
<Button color="darker-info">
|
|
Info colored button with contrast passing score
|
|
</Button>
|
|
```
|
|
|
|
Known reactstrap components that accept the `color` prop and work with custom Treeherder colors: `Badge`, `Button`, `Card`, `DropdownToggle`, `FormText`, `NavBar`, `Progress`, `Spinner`.
|
|
|
|
In case you need to add more custom colors, please add on [treeherder-custom-styles.css](https://github.com/mozilla/treeherder/blob/master/ui/css/treeherder-custom-styles.css#L348) style sheet.
|
|
|
|
### Inserting new colors
|
|
|
|
If you add new colors to the style sheets, please make sure the text and background color combination passes the minimum contrast ratio defined by WCAG.
|
|
|
|
In order to check if it passes, you can use [WebAIM contrast checker](https://webaim.org/resources/contrastchecker/) or use [Firefox's Accessibility Devtools](https://developer.mozilla.org/en-US/docs/Tools/Accessibility_inspector#Check_for_accessibility_issues).
|
|
|
|
### Red and Green
|
|
|
|
Red and green colors are not very noticeable for some types of color deficiency. For that reason, it is recommended to insert an accompanying icon, such as a checkmark (for success) or an exclamation point (for warning or error).
|
|
|
|
For that task, `FontAwesome` is a supported choice.
|
|
|
|
## Images
|
|
|
|
### Image HTML tag
|
|
|
|
If you add an image, make sure you also write an alternative text for it. The text should be descriptive and support the screen reader user.
|
|
|
|
```jsx
|
|
<img src={image} alt="A description of the image">
|
|
```
|
|
|
|
If you are not sure how to write this, please refer to [this guide](https://webaim.org/techniques/alttext/).
|
|
|
|
### SVG
|
|
|
|
For SVG images, do the following:
|
|
|
|
- `<svg>` should have `aria-labelledby` attribute, with the ids of the following elements, separated by a blank space. It should also have a `role="img"`;
|
|
- As the first child of `<svg>`, add `<title>` with an `id` attribute. The content of this element should be the title of the image;
|
|
- (_Optional_) Following `<title>`, you can add `<desc>`, which describes the image. You should also add an `id`.
|
|
|
|
```jsx
|
|
<svg aria-labelledby="imageTitle imageDesc" role="img">
|
|
<title id="imageTitle"> A title of this image </title>
|
|
<desc id="imageDesc"> A description of this image </desc>
|
|
// ...
|
|
</svg>
|
|
```
|
|
|
|
If your case is more specific, please check [this guide](https://css-tricks.com/accessible-svgs/#article-header-id-1).
|
|
|
|
## Interactive elements
|
|
|
|
When creating elements that have event listeners, prefer any component of the reactstrap interactive elements. Examples are: `Button`, `Input`, `DropdownToggle`. You can also choose a HTML `<a>` element.
|
|
|
|
If you need to insert an event listener in a non-interactive element, such as a `span`, add also an `aria-role` of `button`, `link`, `checkbox`, or whatever seems closer to the functionality of the element.
|
|
|
|
```html
|
|
<span onClick={someFunction} aria-role="button">
|
|
Unconventional button
|
|
</span>
|
|
```
|
|
|
|
### Dropdown menu
|
|
|
|
There is a special case when you are creating a dropdown menu. First of all, try to follow [reactstrap structure](https://reactstrap.github.io/components/dropdowns/).
|
|
|
|
Lastly, insert an additional tag `prop` to `DropdownItem` component.
|
|
|
|
```jsx
|
|
<DropdownItem tag="a"> Menu Item </DropdownItem>
|
|
```
|
|
|
|
## Forms, inputs and buttons
|
|
|
|
Apart from inserting high color contrast combinations in buttons, also make sure it has a `:focus` style (usually a blue outline is enough). If you use reactstrap's `Button` component, this is added by default, hence it is recommended.
|
|
|
|
In case the content of the button is not a text (an icon or graphical element, for example), this element should have an `aria-label`, explaining what it does.
|
|
|
|
```jsx
|
|
<Button aria-label="Bookmark alert 12345" onClick={onClickFunction}>
|
|
<FontAwesomeIcon icon={icon} />
|
|
</Button>
|
|
```
|
|
|
|
For input and checkbox, those are important to be labeled - placeholders are not enough for screen reader users. For example, when inserting an email input and a checkbox, using reactstrap, the structure should be:
|
|
|
|
```jsx
|
|
<Form>
|
|
<FormGroup>
|
|
<Label for="email">Email</Label>
|
|
<Input
|
|
type="email"
|
|
name="email"
|
|
id="email"
|
|
placeholder="Insert your email"
|
|
/>
|
|
</FormGroup>
|
|
|
|
<FormGroup>
|
|
<Label check>
|
|
<Input type="checkbox" /> I agree with the terms
|
|
</Label>
|
|
</FormGroup>
|
|
</Form>
|
|
```
|
|
|
|
If in doubt, please check the [reactstrap Form documentation](https://reactstrap.github.io/components/form/).
|
|
|
|
## Specific elements
|
|
|
|
### Progress Bar
|
|
|
|
Across Perfherder, there are some Progress Bars, which are built using reactstrap components. There is still an [issue](https://github.com/reactstrap/reactstrap/issues/1681), however, when adding labels on each bar. While this is still not solved, it is recommended to add an `aria-label` in the wrapping component, explaining the values of the bar.
|
|
|
|
For example:
|
|
|
|
```jsx
|
|
<Progress
|
|
multi
|
|
aria-label={`Description of progress bar. Metric: ${finalValue}`}
|
|
>
|
|
<div aria-hidden="true">
|
|
<Progress bar value={valueOne} />
|
|
<Progress bar value={valueTwo} />
|
|
</div>
|
|
</Progress>
|
|
```
|
|
|
|
### Tables
|
|
|
|
In tables, there should always be headers.
|
|
|
|
```jsx
|
|
<Table>
|
|
<thead>
|
|
<tr>
|
|
<th> First header </th>
|
|
<th> Second header </th>
|
|
<th> Third header </th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</Table>
|
|
```
|
|
|
|
Also, if you are not using `<table>` tag or reactstrap's `Table` component to create the table, please use [all the necessary `role` attributes](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Table_Role).
|
|
|
|
Alternatively, you may choose to use the [React Table](https://github.com/tannerlinsley/react-table) library. The only requirement here is to insert a `role="table"`, like this:
|
|
|
|
```jsx
|
|
<ReactTable
|
|
getTableProps={() => ({ role: 'table' })}
|
|
/>
|
|
```
|
|
|
|
### Other Components (Third-Party)
|
|
|
|
Take special care when bringing in new elements/components to the app. They should have a good documentation on accessibility and should be tested beforehand by an a11y fellow.
|
|
|
|
## References
|
|
|
|
- [WAI-ARIA Authoring Practices](https://www.w3.org/TR/wai-aria-practices-1.1/) is the official document that covers specific cases for creating accessible web applications.
|
|
- [Auditing For Accessibility Problems With Firefox Developer Tools](https://hacks.mozilla.org/2019/10/auditing-for-accessibility-problems-with-firefox-developer-tools/) is a guide on how to use the Accessibility tab in Firefox Devtools.
|
|
- [Accessibility Inspector](https://developer.mozilla.org/en-US/docs/Tools/Accessibility_inspector) is the official documentation for Accessibility Inspector in Firefox Devtools.
|