Przejdź do treści

Dostępność

Budowane, aby pomóc twojej aplikacji spełnić WCAG 2.2 AA

Skribly UI celuje w WCAG 2.2 poziom AA we wszystkim, co dostarcza. Ta strona mówi, jak to robi, co sprawdzają testy i za co nadal odpowiada aplikacja, która go używa.

Cel i to, czym nie jestLink do sekcji Cel i to, czym nie jest

Informacja: Bez deklaracji zgodności

Zgodność dotyczy całych stron, a nie części. Biblioteka nie może sama uczynić aplikacji zgodną, a Skribly UI nie został poddany audytowi ani certyfikacji. Usuwa typowe błędy z części, które dostarcza, a aplikacja nadal odpowiada za swoją treść, swoje słowa, strukturę swoich stron i własny CSS.

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.

Kryteria sukcesu WCAG 2.2, poziom, co robi biblioteka i za co odpowiada aplikacja
KryteriumPoziomJak spełniają je komponentyZa co odpowiada twoja aplikacja
1.1.1Treść nietekstowaAIkony 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 relacjeANatywne 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ólAAPola przekazują autoComplete dalej; formularze logowania i resetu je ustawiają.autoComplete na polach z danymi osobowymi.
1.4.1Użycie koloruAKaż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)AAPary 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 tekstuAARozmiary 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 ekranuAAKomponenty 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 nietekstowychAARamki 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ścieAATekst 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 fokusieAADymki podpowiedzi pokazują się przy fokusie, zostają, gdy są najechane, i zamykają się klawiszem Escape.Nic dodatkowego.
2.1.1KlawiaturaAKaż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 klawiaturyAOkna dialogowe trzymają fokus celowo, zamykają się klawiszem Escape i zwracają fokus elementowi otwierającemu.Nic dodatkowego.
2.2.1Możliwość dostosowania czasuAToasty 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 proguANic 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ówASkipLink i MainContent dają skok do treści; układy używają landmarków.Link pomijający na każdej stronie.
2.4.3Kolejność fokusaAKolejność czytania odpowiada kolejności wizualnej; fokus wraca po zamknięciu nakładek.Kolejność własnego układu.
2.4.6Nagłówki i etykietyAAKaż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 fokusAAJedna 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)AAObwó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 nazwieAWidoczna 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ąganiaAAZmiana 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)AACele 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 danychAWybranie 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łęduABłę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 instrukcjeAPola mają widoczną etykietę, znak wymagane lub opcjonalne i tekst pomocy.Słowa każdej etykiety i podpowiedzi.
3.3.3Sugestie dotyczące błędówAAerrorMessage zawiera poprawkę, a FormErrorSummary linkuje do każdego pola.Komunikaty, które mówią, jak to poprawić.
3.3.8Dostępne uwierzytelnianie (minimalne)AAFormularze 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śćAReact Aria ustawia role, stany i właściwości; typy wymagają każdej nazwy.Nazwy własnych niestandardowych kontrolek.
4.1.3Komunikaty o stanieAAToasty, 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

KlawiszCo robi
TabPrzechodzi do następnej kontrolki. Pierwsze naciśnięcie na stronie pokazuje link pomijający.
Shift+TabPrzechodzi do poprzedniej kontrolki.
F6Przenosi fokus do stosu toastów, gdy toasty są pokazane.
EscapeZamyka otwarte menu, okno podręczne, dymek podpowiedzi lub okno dialogowe i zwraca fokus temu, co je otworzyło.

Przyciski, przełączniki i linki

KlawiszCo robi
EnterlubSpacjaNaciska przycisk albo przełącza przełącznik, pole wyboru lub Switch.
EnterOtwiera 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

KlawiszCo robi
←lub→Przesuwa i zaznacza; strzałka w górę i w dół w pionowych listach kart.
HomelubEndPrzechodzi do pierwszej albo ostatniej karty.
DeletelubBackspaceZamyka kartę z fokusem w ClosableTabs.

Menu, listy wyboru i listy wyszukiwania

KlawiszCo 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–ZWpisanie litery przeskakuje do pierwszej pasującej pozycji.
EnterUruchamia albo wybiera podświetloną pozycję.

Listy, tabele i drzewa

KlawiszCo robi
↑lub↓Przechodzi między wierszami; w DataTable strzałki przechodzą między komórkami.
HomelubEndlubPage UplubPage DownSkacze po długich listach, także po wierszach, których VirtualList jeszcze nie narysował.
SpacjaZaznacza wiersz.
→lub←Otwiera albo zamyka gałąź drzewa, albo przechodzi do jej potomka lub rodzica.
EnterPodnosi przeciągany element i go upuszcza; strzałki wybierają miejsce, a Escape anuluje.

Suwaki, dzielniki i pola dat

KlawiszCo robi
←lub→lub↑lub↓Zmienia suwak o krok, przesuwa dzielnik albo zmienia segment daty.
Page UplubPage DownSkacze dalej, a w kalendarzu o miesiąc.
HomelubEndPrzechodzi do granic.
EnterZwija i przywraca widok podzielony albo dok.

Wpisywanie tekstu

KlawiszCo robi
EnterWysyła z Composer, dodaje chip w ChipInput, wysyła pole wyszukiwania.
Shift+EnterDodaje linię w Composer.
Ctrl+Enterlub⌘+EnterWysyła wpis z CommentForm.
EscapeCzyś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ę

  1. Tylko klawiaturaOdłóż mysz. Dotrzyj do każdej kontrolki klawiszem Tab, użyj jej i obserwuj obwódkę fokusa na całej drodze.
  2. Czytnik ekranuVoiceOver w macOS i iOS, NVDA w Windows, TalkBack w Androidzie. Słuchaj nazw, stanów i komunikatów.
  3. 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.
  4. Wymuszone kolory i ruchEmuluj forced-colors i prefers-reduced-motion w narzędziach deweloperskich przeglądarki.
  5. Kontrole automatyczneUruchamiaj axe w testach jednostkowych i w testach end-to-end prawdziwych stron, gdzie może mierzyć kontrast.
  6. 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ć?
Kontrola axe w Vitesttsx
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([])
})
Kontrola axe w Playwright, z kontrastemts
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([])
})

Szukaj na stronie

Strzałki przenoszą między wynikami, Enter otwiera, Esc zamyka. Ctrl K /