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

docs: Accessibility (a11y) #99

Merged
merged 1 commit into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Follow the step-by-step [getting started instructions](docs/getting-started.md).
All documentation is located in [`docs/`](docs/):

- [Getting Started](docs/getting-started.md)
- [Accessibility (a11y)](docs/accessibility.md)
- [Blocks and Components](docs/blocks-and-components.md)
- [CMS Content Modelling](docs/cms-content-modelling.md)
- [CMS Data Loading](docs/cms-data-loading.md)
Expand Down
39 changes: 39 additions & 0 deletions docs/accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Accessibility (a11y)

**Head Start aims to provide an accessible baseline, by providing helper classes and components.**

## CSS helper classes

Head Start provides CSS helper classes for improved accessibility:

```astro
---
import '@assets/a11y.css';
---

<span class="a11y-sr-only">
This element is visually hidden, while its content is still
accessible by assistive technology like screen readers (sr).
</span>

<a href="..." class="a11y-kb-only">
This element is visually hidden, and appears
only when element has keyboard (kb) focus.
</a>
```

## Skip Link component

Head Start provides a [Skip Link component](../src/components/SkipLink/README.md) that enables keyboard users and users of assistive technology to jump over parts of the UI that are repeated. It's pre-configured in the [Default template](../src/layouts/Default.astro).

## Best practices

Head Start aims to stay close to the web standards. Here's a few tips to help keep it accessible:

- Use semantic HTML as a baseline.
- Use native elements for interaction like `<form>`s, `<label>`led `<input>`s, `<output>`s, `<dialog>`, `<details>` with `<summary>` and native API's like the [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API).
- Add relevant ARIA roles and attributes on custom interactive components.
- Require `alt` texts on assets in the CMS and use their value in templates.
- Test manually using only your keyboard and a screen reader like VoiceOver.
- Test regularly with tools like [Google Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/) and [WebAIM WAVE](https://wave.webaim.org/).
- When adding automated tests, consider [Cypress Axe](https://www.npmjs.com/package/cypress-axe#cychecka11y) or [Playwright Axe](https://playwright.dev/docs/accessibility-testing).
22 changes: 22 additions & 0 deletions src/assets/a11y.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.a11y-sr-only,
.a11y-kb-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
border: 0;
margin: -1px;
clip: rect(0 0 0 0);
overflow: hidden;
white-space: nowrap;
}

.a11y-kb-only:active,
.a11y-kb-only:focus {
position: static;
width: auto;
height: auto;
margin: 0;
clip: auto;
overflow: visible;
}
4 changes: 2 additions & 2 deletions src/components/Icon/Icon.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
import type { IconName } from '../../assets/icon-sprite';
import type { IconName } from '@assets/icon-sprite';

interface Props {
name: IconName;
Expand All @@ -8,7 +8,7 @@ interface Props {
const { name, ...props } = Astro.props;
---

<svg {...props} data-icon={name}>
<svg {...props} aria-hidden data-icon={name}>
<use xlink:href={`#${name}`} />
</svg>

Expand Down
17 changes: 2 additions & 15 deletions src/components/LocaleSelector/LocaleSelector.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { getLocale, locales, t } from '@lib/i18n';
import type { SiteLocale } from '@lib/types/datocms';
import type { PageUrl } from '@lib/seo';
import '@assets/a11y.css';

const activeLocale = getLocale();

Expand All @@ -19,7 +20,7 @@ const getPageHref = (locale: SiteLocale) => {
---
<locale-selector>
<nav aria-labelledby="locale-selector-title">
<span id="locale-selector-title" class="sr-only">
<span id="locale-selector-title" class="a11y-sr-only">
{ t('select_language') }
</span>
<ul role="list" style="list-style: none;">
Expand All @@ -39,20 +40,6 @@ const getPageHref = (locale: SiteLocale) => {
<script src="./LocaleSelector.client.ts"></script>

<style>
/* functional styling */
.sr-only {
/* @see https://tailwindcss.com/docs/screen-readers */
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}

/* basic styling, can be removed */
ul {
margin: 0;
Expand Down
16 changes: 4 additions & 12 deletions src/components/SkipLink/SkipLink.astro
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
---
import { t } from '@lib/i18n';
import '@assets/a11y.css';

interface Props {
targetId: string;
}
const { targetId } = Astro.props;
---
<a href={`#${targetId}`}>
<a href={`#${targetId}`} class="a11y-kb-only">
<slot>{ t('skip_to_content') }</slot>
</a>

<style>
/* functional styling */
a {
position: absolute;
top: 1rem;
left: -9999rem;
}
a:focus {
left: 1rem;
}

/* basic styling, can be removed */
a {
a:focus {
position: absolute;
background: white;
padding: .5em;
}
Expand Down
1 change: 1 addition & 0 deletions src/layouts/Default.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import LocaleSelector from '@components/LocaleSelector/LocaleSelector.astro';
import PreviewModeProvider from '@components/PreviewMode/PreviewModeProvider.astro';
import SeoHead from '@components/SeoHead.astro';
import SkipLink from '@components/SkipLink/SkipLink.astro';
import '@assets/a11y.css';

interface Props {
pageUrls: PageUrl[];
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@assets/*": ["src/assets/*"],
"@blocks/*": ["src/blocks/*"],
"@components/*": ["src/components/*"],
"@layouts/*": ["src/layouts/*"],
Expand Down