Cel i to, czym nie jestLink do sekcji Cel i to, czym nie jest
Informacja: Bez deklaracji zgodności
Każdy komponent jest projektowany względem kryteriów AA z WCAG 2.2, zbudowany na React Aria, aby obsługa klawiatury, fokus i zachowanie dla czytników ekranu podążały za ARIA Authoring Practices, i opisany własnymi notatkami o dostępności na swojej stronie.
Co sprawdzają testyLink do sekcji Co sprawdzają testy
axe na każdym przykładzie
Przykłady: 211, przechodzą przez axe-core w motywie dziennym, nocnym i wysokiego kontrastu: 633 uruchomień przy każdym npm test.
Kontrast par tokenów
Pary tekstu i podbarwienia, ramki kontrolek i obwódka fokusa są mierzone w każdym motywie względem 4,5:1 i 3:1, a w wysokim kontraście 7:1 i 4,5:1.
Każdy komponent jest pokazany
Test kończy się błędem, gdy wyeksportowany komponent nie ma przykładu, więc nic nie jest dostarczane bez przejścia przez axe.
Zachowanie każdego komponentu
Każdy komponent ma testy Testing Library dla swoich ścieżek klawiatury, nazw dostępnych, stanów i komunikatów na żywo.
Ta strona w prawdziwej przeglądarce
Przed każdym wydaniem każda strona tego serwisu jest otwierana w Chromium przy szerokości 320 i 1280 pikseli i przechodzi przez axe z układem, więc mierzone są też rozmiar celu, kontrast kolorów we wszystkich trzech motywach, linki w tekście i pola przewijane. Strona, która przewija się na boki albo nie została znaleziona, przerywa build.
Testy jednostkowe działają w jsdom, który nie ma układu. Własna reguła kontrastu axe jest tam wyłączona, dlatego pary tokenów są sprawdzane z ich wartości, a zbudowana strona jest sprawdzana jeszcze raz w przeglądarce. Są rzeczy, których nie zobaczy żaden test automatyczny:
- co naprawdę mówi czytnik ekranu i w jakiej kolejności;
- czy obwódka fokusa jest widoczna na tle tego, co jest za nią;
- układ przy powiększeniu 400% i na ekranie 320 px;
- słowa i treść, które twoja aplikacja wkłada do komponentów.
Sprawdza się je ręcznie podczas przeglądu, a twoja aplikacja też powinna je sprawdzać.
Kryteria WCAG 2.2 AALink do sekcji Kryteria WCAG 2.2 AA
Kryteria, przy których biblioteka wykonuje prawdziwą pracę, jak jej komponenty je spełniają i część, która zostaje po stronie twojej aplikacji.
| Kryterium | Poziom | Jak spełniają je komponenty | Za co odpowiada twoja aplikacja |
|---|---|---|---|
| 1.1.1Treść nietekstowa | A | Ikony są ukryte przed czytnikami ekranu albo mają nazwę. IconButton wymaga label; Logo jest dekoracją, chyba że dostanie nazwę. | Tekst alternatywny obrazów, które pokazuje. |
| 1.3.1Informacje i relacje | A | Natywne elementy i role React Aria. Etykiety, pomoc i błędy są powiązane ze swoją kontrolką; tabele mają komórki nagłówkowe; poziomy nagłówków są propami. | Struktura nagłówków i landmarki każdej strony. |
| 1.3.5Określenie przeznaczenia pól | AA | Pola przekazują autoComplete dalej; formularze logowania i resetu je ustawiają. | autoComplete na polach z danymi osobowymi. |
| 1.4.1Użycie koloru | A | Każdy ton łączy swój kolor ze słowem, kształtem ikony albo oboma. | Ta sama zasada we własnych widokach i wykresach. |
| 1.4.3Kontrast (minimalny) | AA | Pary tekstu osiągają 4,5:1 w motywie dziennym i nocnym oraz 7:1 w wysokim kontraście. Sprawdzają je testy. | Własne kolory i tekst na obrazach. |
| 1.4.4Zmiana rozmiaru tekstu | AA | Rozmiary są w rem i podążają za rozmiarem tekstu w przeglądarce. | Brak stałych rozmiarów fontów w pikselach we własnym CSS. |
| 1.4.10Dopasowanie do ekranu | AA | Komponenty zawijają się albo układają w stos aż do 320 px; szerokie tabele i kod przewijają się we własnym polu z fokusem. | Układ strony, który się układa przy 320 px. |
| 1.4.11Kontrast elementów nietekstowych | AA | Ramki kontrolek i obwódka fokusa osiągają 3:1 w motywie dziennym i nocnym oraz 4,5:1 w wysokim kontraście, co sprawdzają testy. | Własne ikony i znaczniki wykresów. |
| 1.4.12Odstępy w tekście | AA | Tekst się zawija, a pola rosną razem z nim, zamiast go ucinać. | Własne pola o stałej wysokości. |
| 1.4.13Treść pojawiająca się po najechaniu lub fokusie | AA | Dymki podpowiedzi pokazują się przy fokusie, zostają, gdy są najechane, i zamykają się klawiszem Escape. | Nic dodatkowego. |
| 2.1.1Klawiatura | A | Każda kontrolka działa z klawiatury. Przeciąganie zawsze ma ścieżkę z klawiatury. | Własne widżety, które buduje sama. |
| 2.1.2Brak pułapki klawiatury | A | Okna dialogowe trzymają fokus celowo, zamykają się klawiszem Escape i zwracają fokus elementowi otwierającemu. | Nic dodatkowego. |
| 2.2.1Możliwość dostosowania czasu | A | Toasty sukcesu i informacji zostają co najmniej 5 sekund i wstrzymują się po najechaniu lub przy fokusie; ostrzeżenia, błędy i toasty z akcją zostają do zamknięcia. | Brak limitów czasu we własnych komunikatach. |
| 2.3.1Trzy błyski lub wartości poniżej progu | A | Nic nie błyska. Wskaźniki ładowania się obracają; pulsowanie zanika powoli i zatrzymuje się przy ograniczonym ruchu. | Własne animacje i wideo. |
| 2.4.1Możliwość pominięcia bloków | A | SkipLink i MainContent dają skok do treści; układy używają landmarków. | Link pomijający na każdej stronie. |
| 2.4.3Kolejność fokusa | A | Kolejność czytania odpowiada kolejności wizualnej; fokus wraca po zamknięciu nakładek. | Kolejność własnego układu. |
| 2.4.6Nagłówki i etykiety | AA | Każda etykieta i każdy nagłówek jest propem, więc może opisywać swój cel. | Słowa, które opisują cel. |
| 2.4.7Widoczny fokus | AA | Jedna obwódka fokusa dla każdego elementu z domyślnych stylów strony, 3 px przy ustawieniu wyraźnego fokusa. | Nieusuwanie obrysów we własnym CSS. |
| 2.4.11Fokus niezasłonięty (minimalny) | AA | Obwódki są rysowane wewnątrz pól, które ucinają; nakładki otwierają się obok swojego elementu otwierającego. | scroll-padding pod własnymi przyklejonymi nagłówkami i stopkami. |
| 2.5.3Etykieta w nazwie | A | Widoczna etykieta jest nazwą dostępną; przyciski z ikoną pokazują swoją nazwę jako dymek podpowiedzi. | Utrzymanie tych samych widocznych słów i etykiet. |
| 2.5.7Ruchy przeciągania | AA | Zmiana kolejności ma NudgeButtons, dzielniki poruszają się klawiszami, a upuszczanie plików ma przycisk. | Ścieżka dla pojedynczego wskaźnika dla własnych funkcji przeciągania. |
| 2.5.8Rozmiar celu (minimalny) | AA | Cele mają co najmniej 24 na 24 piksele, także w zwartej gęstości. | Odstępy między własnymi małymi celami. |
| 3.2.2Przy wprowadzaniu danych | A | Wybranie opcji nigdy samo nie wysyła formularza ani nie przechodzi na inną stronę. | To samo we własnych procedurach obsługi. |
| 3.3.1Identyfikacja błędu | A | Błędy są tekstem z ikoną, ustawiają aria-invalid i są powiązane ze swoim polem. | Komunikaty błędów, które mówią, co jest nie tak. |
| 3.3.2Etykiety lub instrukcje | A | Pola mają widoczną etykietę, znak wymagane lub opcjonalne i tekst pomocy. | Słowa każdej etykiety i podpowiedzi. |
| 3.3.3Sugestie dotyczące błędów | AA | errorMessage zawiera poprawkę, a FormErrorSummary linkuje do każdego pola. | Komunikaty, które mówią, jak to poprawić. |
| 3.3.8Dostępne uwierzytelnianie (minimalne) | AA | Formularze logowania pozwalają wklejać i współpracują z menedżerami haseł przez autocomplete. | Żadnych łamigłówek ani ręcznego przepisywania kodów. |
| 4.1.2Nazwa, rola, wartość | A | React Aria ustawia role, stany i właściwości; typy wymagają każdej nazwy. | Nazwy własnych niestandardowych kontrolek. |
| 4.1.3Komunikaty o stanie | AA | Toasty, komunikaty flash, alerty na żywo, statusy formularzy i announce() używają regionów na żywo typu polite albo assertive. | Ogłaszanie wyników własnej pracy asynchronicznej. |
KlawiaturaLink do sekcji Klawiatura
Klawisze podążają za ARIA Authoring Practices, więc są to te, które użytkownicy czytników ekranu i klawiatury już znają. Strona każdego komponentu wymienia jego własne klawisze.
Wszędzie
| Klawisz | Co robi |
|---|---|
| Tab | Przechodzi do następnej kontrolki. Pierwsze naciśnięcie na stronie pokazuje link pomijający. |
| Shift+Tab | Przechodzi do poprzedniej kontrolki. |
| F6 | Przenosi fokus do stosu toastów, gdy toasty są pokazane. |
| Escape | Zamyka otwarte menu, okno podręczne, dymek podpowiedzi lub okno dialogowe i zwraca fokus temu, co je otworzyło. |
Przyciski, przełączniki i linki
| Klawisz | Co robi |
|---|---|
| EnterlubSpacja | Naciska przycisk albo przełącza przełącznik, pole wyboru lub Switch. |
| Enter | Otwiera link. Linki otwierają też menu przeglądarki prawym przyciskiem myszy. |
| ←lub→ | Przechodzi między przyciskami paska narzędzi, który jest jednym przystankiem Tab. |
Karty, kontrolki segmentowe i grupy przycisków opcji
| Klawisz | Co robi |
|---|---|
| ←lub→ | Przesuwa i zaznacza; strzałka w górę i w dół w pionowych listach kart. |
| HomelubEnd | Przechodzi do pierwszej albo ostatniej karty. |
| DeletelubBackspace | Zamyka kartę z fokusem w ClosableTabs. |
Menu, listy wyboru i listy wyszukiwania
| Klawisz | Co robi |
|---|---|
| EnterlubSpacjalub↓ | Otwiera menu albo listę wyboru na pierwszej pozycji; strzałka w górę otwiera menu na ostatniej. |
| ↑lub↓ | Przesuwa po pozycjach, podczas gdy fokus zostaje w polu wyszukiwania GlobalSearch, CommandPalette i QuickOpen. |
| A–Z | Wpisanie litery przeskakuje do pierwszej pasującej pozycji. |
| Enter | Uruchamia albo wybiera podświetloną pozycję. |
Listy, tabele i drzewa
| Klawisz | Co robi |
|---|---|
| ↑lub↓ | Przechodzi między wierszami; w DataTable strzałki przechodzą między komórkami. |
| HomelubEndlubPage UplubPage Down | Skacze po długich listach, także po wierszach, których VirtualList jeszcze nie narysował. |
| Spacja | Zaznacza wiersz. |
| →lub← | Otwiera albo zamyka gałąź drzewa, albo przechodzi do jej potomka lub rodzica. |
| Enter | Podnosi przeciągany element i go upuszcza; strzałki wybierają miejsce, a Escape anuluje. |
Suwaki, dzielniki i pola dat
| Klawisz | Co robi |
|---|---|
| ←lub→lub↑lub↓ | Zmienia suwak o krok, przesuwa dzielnik albo zmienia segment daty. |
| Page UplubPage Down | Skacze dalej, a w kalendarzu o miesiąc. |
| HomelubEnd | Przechodzi do granic. |
| Enter | Zwija i przywraca widok podzielony albo dok. |
Wpisywanie tekstu
| Klawisz | Co robi |
|---|---|
| Enter | Wysyła z Composer, dodaje chip w ChipInput, wysyła pole wyszukiwania. |
| Shift+Enter | Dodaje linię w Composer. |
| Ctrl+Enterlub⌘+Enter | Wysyła wpis z CommentForm. |
| Escape | Czyści pole wyszukiwania. |
Czytniki ekranu i komunikaty na żywoLink do sekcji Czytniki ekranu i komunikaty na żywo
Każdy komponent ma nazwę, rolę i stan. Nazwy pochodzą z propów, nigdy z biblioteki, więc są w języku aplikacji. Słowa statusu, takie jak „Błąd”, są odczytywane przed komunikatem, więc ton nigdy nie opiera się na kolorze i ikonie.
Komunikaty, które pojawiają się później, są odczytywane przez regiony na żywo: polite dla sukcesu i informacji, który czeka, aż czytnik ekranu skończy, oraz assertive dla błędów, które zatrzymują czytelnika. LiveRegion i announce() robią to samo dla własnych komunikatów aplikacji. Wzorzec komunikatów mówi, którego komponentu użyć.
Ograniczony ruchLink do sekcji Ograniczony ruch
Ruch jest krótki i nigdy nie jest potrzebny do zrozumienia zmiany. Przy prefers-reduced-motion: reduce albo klasie a11y-reduce-motion z ustawień czytelnika tokeny czasu trwania spadają niemal do zera, pulsowanie się zatrzymuje, zmiany motywu następują od razu, a przewijanie skacze. Wskaźniki ładowania nadal się powoli obracają, bo nieruchomy wskaźnik powiedziałby, że praca stanęła.
Wymuszone koloryLink do sekcji Wymuszone kolory
Tryb wysokiego kontrastu systemu Windows zastępuje każdy kolor kilkoma kolorami systemowymi. Komponenty zachowują tam swój kształt: plakietki i kafelki mają przezroczyste ramki, które stają się widoczne, bieżący element dostaje podkreślenie albo pasek Highlight, zaznaczone opcje używają Highlight, a szkielety dostają obrys. Próbki kolorów, na przykład w tabelach tokenów, zachowują swoje prawdziwe kolory.
Motyw wysokiego kontrastu to osobna rzecz: motyw biblioteki dla czytelników, którzy chcą mocnego kontrastu w wyglądzie Skribly.
Powiększenie, układ i odstępy w tekścieLink do sekcji Powiększenie, układ i odstępy w tekście
- Rozmiary tekstu są w rem, więc ustawienie rozmiaru tekstu w przeglądarce skaluje każdy komponent.
- Przy powiększeniu 400% okno 1280 px ma szerokość 320 px. Komponenty się zawijają, układają w stos i ucinają z zachowaniem pełnego tekstu dla czytników ekranu, a nic nie przewija się na boki poza tabelami danych i kodem, które przewijają się we własnym polu.
- Pola mają tekst 16 px poniżej 640 px, więc telefony nie powiększają widoku, gdy pole dostaje fokus.
- Kontenery tekstu rosną przy dodatkowych odstępach między liniami, słowami i literami, zamiast je ucinać.
Rozmiar celuLink do sekcji Rozmiar celu
Cele wskaźnika mają co najmniej 24 na 24 piksele, czyli minimum AA z WCAG 2.2. Kontrolki mają domyślnie 36 px wysokości; zwarta gęstość daje 30 px, nadal powyżej minimum. Małe przyciski zamknięcia dostają pole trafienia 24 px, nawet gdy ikona jest mniejsza, a przyciski zmiany wartości w ustawieniach czytelnika mają 44 px.
Jak testować twoją aplikacjęLink do sekcji Jak testować twoją aplikację
- Tylko klawiaturaOdłóż mysz. Dotrzyj do każdej kontrolki klawiszem Tab, użyj jej i obserwuj obwódkę fokusa na całej drodze.
- Czytnik ekranuVoiceOver w macOS i iOS, NVDA w Windows, TalkBack w Androidzie. Słuchaj nazw, stanów i komunikatów.
- Powiększenie i 320 pxPowiększ do 200% i 400% i użyj okna o szerokości 320 px. Nic nie powinno być ucięte ani przewijać się na boki.
- Wymuszone kolory i ruchEmuluj forced-colors i prefers-reduced-motion w narzędziach deweloperskich przeglądarki.
- Kontrole automatyczneUruchamiaj axe w testach jednostkowych i w testach end-to-end prawdziwych stron, gdzie może mierzyć kontrast.
- Własna treśćPrzeczytaj na głos każdą etykietę, błąd i pusty stan. Czy mówi, co się stało i co zrobić?
import axe from 'axe-core'
import { render } from '@testing-library/react'
it('has no axe violations', async () => {
const { container } = render(<SettingsPage />)
const results = await axe.run(container, { rules: { 'color-contrast': { enabled: false } } })
expect(results.violations).toEqual([])
})import AxeBuilder from '@axe-core/playwright'
test('settings page', async ({ page }) => {
await page.goto('/settings')
const results = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze()
expect(results.violations).toEqual([])
})