Co oznacza to kryterium
Podczas obsługi klawiaturą użytkownik musi móc zobaczyć, który element otrzyma następne działanie. Samo działające przechodzenie klawiszem Tab nie wystarcza, jeśli aktywna kontrolka wygląda tak samo jak wcześniej. Wskaźnik może pochodzić z przeglądarki, platformy lub własnego stylu, ale musi być widoczny w trybie obsługi klawiaturą i nie znikać tylko dlatego, że minął czas.
| Potrzeba / ID | Konkretna korzyść |
|---|---|
Motoryka i obsługa klawiaturą / motor |
Osoba korzystająca z klawiatury zamiast precyzyjnego wskaźnika widzi, co uruchomi Space lub Enter. |
Słabowidzenie / low-vision |
Wskaźnik pomaga odnaleźć bieżące miejsce pracy, także przy oglądaniu powiększonego fragmentu. |
Pamięć i koncentracja / cognitive |
Widoczna pozycja ogranicza konieczność liczenia naciśnięć i zapamiętywania kolejności kontrolek. |
Przykłady błędów i poprawek
Pracownia udostępnia lokalny podgląd miejsca odbioru dla syntetycznego P-104. Przyciski „Pokaż adres” i „Pokaż godziny” mają tę samą treść, geometrię i działanie we wszystkich wariantach. Space na „Pokaż adres” wyświetla „P-104: ul. Przykładowa 12. Wyświetlenia: 1.” Nie są wysyłane dane i nie jest zmieniane zamówienie.
| Wariant | Jedyna istotna różnica badanego przycisku | Oczekiwany wynik po Tab |
|---|---|---|
good |
Własny widoczny wskaźnik: pomarańczowy obrys. | Użytkownik widzi pozycję fokusu; następny Tab przenosi ją na godziny, Shift+Tab przywraca adres. |
bad |
Flutter: przezroczysty focusColor; WWW: usunięty outline i box-shadow. |
Fokus i aktywacja istnieją, lecz przycisk nie pokazuje pozycji fokusu. |
control |
Flutter: domyślny obrys CupertinoButton; WWW: przywrócony wskaźnik user agenta. | Widoczne wskazanie bez własnego pomarańczowego stylu. |
Bariera: użytkownik klawiatury nie widzi, co uruchomi Space. Poprawka: zachować lub przywrócić widoczny wskaźnik, bez zmiany kolejności, callbacku lub danych. Ocenę widoczności wykonało AI na prawdziwych obrazach; oczekiwane etykiety wariantów należą do fixture, nie są wynikiem niezależnego walidatora.
Kontrola control pokazuje, że własny obrys nie jest obowiązkowy. Kontrola zwykłego kliknięcia WWW pokazuje focus=true, focusVisible=false i brak obrysu przy działającej aktywacji; nie jest to sama w sobie usterka 2.4.7, gdy dostępny tryb klawiatury wskazuje fokus. Na iOS zwykły tap i reset potwierdzają działanie i powrót do stanu początkowego; nie służą do oceny heurystyki przeglądarki.
Dodatkowe przypadki do oceny produktu: obrys ucięty przez kontener, zlewający się z tłem albo znikający po sekundzie. Rozwiązaniem jest odpowiednio odsunięcie wskaźnika/zmiana clippingu, widoczny styl w rzeczywistym otoczeniu albo usunięcie czasowego ukrywania. Nie odtworzono tych trzech dodatkowych usterek; nie przypisujemy im wyniku wykonania.

Good po odebranym Tab: Pokaż adres ma własny pomarańczowy obrys, przed aktywacją. Surowy zrzut XCTest z 2026-10-04; Flutter/iOS Simulator.

Bad po Tab: aplikacja wskazuje primary focus na adresie, ale obraz nie pokazuje wskaźnika. Space nadal wykonuje akcję. Surowy kadr iOS Simulator z 2026-10-04.

Control po Tab zachowuje domyślny miętowy obrys CupertinoButton. Kadr z 2026-10-04 pokazuje wskaźnik frameworka; nie jest testem systemowego Full Keyboard Access.
Kiedy obowiązuje i gdzie są wyjątki
Normatywna treść wymaga trybu, w którym wskaźnik fokusu klawiatury jest widoczny. Nie wymaga obrysu po każdym kliknięciu lub tapnięciu. Mechanizm rozróżniający wejście klawiaturą i wskaźnikiem jest dopuszczalny, jeśli w trybie klawiatury wskaźnik faktycznie widać. Własny styl :focus-visible jest sposobem implementacji, a nie dowodem poprawności sam w sobie.
Widoczny kursor w polu tekstowym lub zaznaczenie całego tekstu może wskazywać fokus. Nie trzeba wtedy bezwarunkowo dodawać drugiego obrysu. Ten wpis bada przycisk, bez kursora tekstowego, hover lub stanu pressed zastępującego fokus. Podświetlenie przytrzymania przycisku nie wystarcza, jeżeli po puszczeniu klawisza użytkownik traci wskazanie bieżącego miejsca.
Wskaźnik musi trwać tak długo, jak potrzeba wskazania bieżącego fokusu; czasowe ukrywanie przy zachowanym fokusie jest usterką. Sekwencja kilku próbek pokazuje trwałość w zmierzonym przedziale, nie dowodzi zachowania przez dowolnie długi czas. W naszej implementacji nie ma timera ukrywającego obrys; timer badawczy tylko odczytuje stan.
2.4.7 nie ustanawia liczbowego minimum grubości, pola ani kontrastu. 1.4.11 — Kontrast elementów nietekstowych ma własny zakres, próg i wyjątki; AAA 2.4.13 — Focus Appearance ustanawia odrębne wymagania wyglądu. 2.4.11 — Focus Not Obscured (Minimum) dotyczy zasłonięcia komponentu z fokusem. Dobry wynik jednej właściwości nie potwierdza pozostałych. 2.1.1 i 2.1.2 dotyczą działania klawiatury i wyjścia z pułapki; ukrycie samego obrysu w naszej parze nie odbiera działania klawiaturą.
Understanding sprawdzono w wersji z aktualizacją 2026-09-06. Techniki i błędy są pomocnicze, nie normatywne:
- G149: zachowanie standardowego wskaźnika przeglądarki lub platformy, jeżeli jest widoczny. G165: wykorzystanie systemowego stylu, w tym ustawień użytkownika; zmian ustawień OS tu nie wykonano.
- C15 / SCR31 / G195: własna zmiana wyglądu przy fokusie. Numeryczne pomiary w procedurze G195 nie stają się dodatkowym progiem 2.4.7.
- C45: poprawny styl
:focus-visibletestowany klawiaturą w obu kierunkach. Sama obecność selektora nie potwierdza widoczności. - C40: dwukolorowy wskaźnik, w którym pasma mają wzajemny kontrast co najmniej 9:1, daje gwarancję co najmniej 3:1 jednego pasma względem jednolitego tła wyłącznie przy całym wskaźniku poza komponentem na tym tle. Gwarancji nie przenosimy na zdjęcie, gradient lub częściowe nałożenie na komponent.
box-shadowmoże zniknąć w forced-colors; pozostaw odpowiednioutline. To technika, nie obowiązek stosowania dwóch pasm lub jej liczbowych parametrów w 2.4.7. - F78: usunięcie lub ukrycie wskaźnika bez widocznego zamiennika może powodować usterkę. F55: zdejmowanie fokusu po jego otrzymaniu może naruszać także operowalność; nasz
badnie wywołujeblur, dzięki czemu izolujemy brak widocznego wskazania.
Platformy
| Środowisko / ID | Podstawa, wersja i miejsce | Stan / adaptacja | Warunek, zakres i uzasadnienie | Weryfikacja |
|---|---|---|---|---|
WWW / web |
WCAG 2.2, Recommendation 2024-12-12, 2.4.7 | dotyczy warunkowo / bez zmiany wymagania | Interfejs obsługiwany klawiaturą, także w przeglądarce telefonu. Każdy osiągalny element potrzebuje widocznego wskazania w tym trybie. | AI, 2026-10-04 |
Aplikacje mobilne / mobile |
WCAG2ICT 2.2, Group Note 2025-12-11, 2.4.7 | dotyczy warunkowo / bez zmiany wymagania | Natywne kontrolki obsługiwane klawiaturą z pozycją fokusu; sam dotykowy charakter telefonu nie wyłącza wymagania. | AI, 2026-10-04 |
Aplikacje desktopowe / desktop |
WCAG2ICT 2.2, Group Note 2025-12-11, 2.4.7 | dotyczy warunkowo / bez zmiany wymagania | Fokus klawiatury w interfejsie programu musi mieć widoczne wskazanie. | AI, 2026-10-04 |
Dokumenty / document |
WCAG2ICT 2.2, Group Note 2025-12-11, 2.4.7 | dotyczy warunkowo / bez zmiany wymagania | Interaktywne elementy dokumentu obsługiwane klawiaturą, np. pole formularza. Statyczny akapit w naszym scenariuszu nie jest taką kontrolką; nie wyłącza to dokumentów jako środowiska. | AI, 2026-10-04 |
Inne / other |
WCAG2ICT 2.2, Group Note 2025-12-11, 2.4.7 | dotyczy warunkowo / bez zmiany wymagania | Oprogramowanie kiosku z przemieszczanym fokusem. System o zamkniętej funkcjonalności może nie mieć pojęcia fokusu: osobne klawisze bezpośrednio wywołujące pozycje mówionego menu nie wymagają dodawania wskaźnika nieistniejącej pozycji. | AI, 2026-10-04 |
WCAG2ICT stosuje tu wymaganie bez adaptacji. Wskazówka o zamkniętej funkcjonalności nie jest ogólnym zwolnieniem dla urządzeń mobilnych ani kiosków: najpierw ustal, czy rzeczywiście istnieje przemieszczana pozycja fokusu. WCAG2ICT jest interpretacją poza WWW, nie osobną normą zgodności. Nie analizowano EN 301 549 ani obowiązków prawnych. Wykonano Flutter/Cupertino w iOS Simulator i minimalny przykład webowy; pozostałe środowiska NOT-RUN.
Rozwiązania w technologiach
Przegląd oficjalnych API: AI, 2026-10-04. Poniższe fragmenty są edukacyjne; historyczne wyniki istniejącej demonstracji Flutter przytoczono poniżej. Nie usuwaj domyślnego wskaźnika, zanim rzeczywiście sprawdzisz zamiennik klawiaturą i na jego tle.
Flutter
W CupertinoButton zachowaj domyślny wskaźnik albo ustaw widoczny focusColor. W użytym SDK framework rysuje przy fokusie zewnętrzny BorderSide o szerokości 3,5; to właściwość tej wersji, nie minimum WCAG. FocusNode.hasPrimaryFocus pomaga diagnozować pozycję, lecz sam nie rysuje wskaźnika.
import 'package:flutter/cupertino.dart';
CupertinoButton(
color: const Color(0xFF15201C),
foregroundColor: const Color(0xFFF4F1E8),
focusColor: const Color(0xFFC2410C),
onPressed: showAddress,
child: const Text('Pokaż adres'),
)Kontekst: showAddress jest callbackiem zwykłego działania w CupertinoApp, a otoczenie pozwala zobaczyć obrys. Dokumentacja i źródło SDK sprawdzone; właściwa pełna demonstracja skompilowana i uruchomiona na iOS. Android NOT-RUN.
iOS / SwiftUI
Zacznij od standardowego Button i zachowaj efekt fokusu platformy. Własny wygląd musi pozostawić faktycznie widoczne wskazanie; focus accessibility/VoiceOver i fokus klawiatury to różne mechanizmy.
import SwiftUI
struct PickupView: View {
@State private var shown = false
var body: some View {
VStack {
Button("Pokaż adres") { shown = true }
if shown { Text("P-104: ul. Przykładowa 12.") }
}
}
}Fragment zachowuje standardowy Button bez usuwania efektu fokusu. Dostępna na docelowym systemie nawigacja klawiaturą i jej ustawienia wymagają testu produktu. Przegląd dokumentacji Button wykonany; kompilacja oraz działanie tego fragmentu NOT-RUN. Build Fluttera nie potwierdza SwiftUI ani Full Keyboard Access.
Android / Compose
Obserwuj istniejący fokus Button przez onFocusChanged, a wskaźnik narysuj na jego podstawie. isFocused dotyczy samej kontrolki, hasFocus również potomków. Nie dodawaj drugiego focusable do Button wyłącznie dla obrysu.
import androidx.compose.foundation.BorderStroke
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
fun AddressButton(showAddress: () -> Unit) {
var focused by remember { mutableStateOf(false) }
Button(
onClick = showAddress,
modifier = Modifier.onFocusChanged { focused = it.isFocused },
border = if (focused) BorderStroke(3.dp, Color(0xFFC2410C)) else null
) { Text("Pokaż adres") }
}Sprawdź widoczność obrysu na faktycznym tle i nie utożsamiaj pressed z fokusem. Dokumentacja API sprawdzona; kompilacja i działanie NOT-RUN. Nie uruchamiano Androida.
React Native
Przykład dotyczy pola, którego dokumentowane onFocus i onBlur pozwalają powiązać styl z rzeczywistym fokusem. Widoczny kursor też może wskazywać fokus; obrys jest tu dodatkowym rozwiązaniem, nie bezwarunkowym obowiązkiem.
import React, { useState } from 'react';
import { Text, TextInput, View } from 'react-native';
export function PickupCode() {
const [focused, setFocused] = useState(false);
return (
<View>
<Text>Kod odbioru</Text>
<TextInput
accessibilityLabel="Kod odbioru"
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
style={{
borderWidth: 3,
padding: 12,
borderColor: focused ? '#C2410C' : 'transparent',
}}
/>
</View>
);
}Przegląd dokumentacji TextInput i View wykonany; kompilacja/typecheck i działanie NOT-RUN. To pole, nie dowód obsługi klawiaturą własnego Pressable. pressed nie oznacza fokusu; właściwości focusable i tabIndex dokumentowane dla Android View nie stanowią wspólnego rozwiązania iOS. Własny przycisk potrzebuje zweryfikowanego mechanizmu fokusu na docelowej platformie.
HTML / CSS / JavaScript
<button type="button">Pokaż adres</button>
<style>
button:focus-visible {
outline: 3px solid #c2410c;
outline-offset: 4px;
}
@media (forced-colors: active) {
button:focus-visible {
outline-color: Highlight;
}
}
</style>Nie dodawaj globalnego outline: none bez działającego zamiennika. Fragment przedstawia styl demonstracji: HTML/CSS/JS sprawdzono składniowo i uruchomiono rzeczywisty kontekstu webowego; forced-colors NOT-RUN, więc obecność reguły nie jest wynikiem testu tego trybu. Starszy odbiornik bez :focus-visible powinien zachować własny domyślny wskaźnik, dopóki nie zweryfikowano fallbacku.
Jak sprawdzić
- Ustal, które elementy można obsługiwać klawiaturą, jak przejść do każdego i gdzie znajduje się fokus. Zacznij przed pierwszą kontrolką; nie klikaj badanego przycisku w celu ustanowienia oczekiwanego fokusu.
- Przejdź Tab przez każdy element, wróć Shift+Tab. Oczekuj widocznego wskazania bieżącej pozycji w obu kierunkach. Sprawdź je na rzeczywistym tle, przy krawędziach i po przewinięciu.
- Uruchom działanie klawiszem właściwym dla kontrolki. Oddziel wskaźnik fokusu od chwilowego pressed, hover, kursora i nowej treści wyniku. Potwierdź, że działanie nie jest jedynie deklarowanym callbackiem.
- Pozostaw fokus bez dalszego wejścia i obserwuj jego wskazanie. Zapisz rzeczywisty czas i ograniczenie próbki; nie zamieniaj jednej sekundy z procedury narzędzia w minimum lub maksimum normy.
- Sprawdź dostępny standardowy wskaźnik i tryby wejścia. Sam brak obrysu po kliknięciu nie przesądza usterki, jeśli tryb klawiatury działa prawidłowo. W produkcie przetestuj istotne ustawienia platformy i dodatkowe motywy.
Wykonanie tej karty obejmuje dwa przyciski, trzy warianty i cykl/reset na opisanych odbiornikach. Nie jest pełnym przejściem przez wszystkie kontrolki istniejącej aplikacji ani audytem wszystkich ekranów. Odtwarzanie, limity i komendy mają źródło w dokumentacji technicznej.
Weryfikacja i ograniczenia
Wyniki wykonania i zachowane błędy
| Sprawdzenie | Wynik i zakres |
|---|---|
| Analiza Flutter | PASS |
| Istniejące testy hostowe bez Androida | PASS, 67 testów; to kontrola regresji, nie widoczności na urządzeniu |
| Build Flutter iOS Simulator | PASS |
| Build własnego drivera XCTest | PASS; zakończony przed instalacją |
| Jedyny natywny XCTest | PASS, 1 test, 82,390 s; wynik z timeoutami; marker runtime potwierdzony, bez FAIL iOS |
| WWW | Wykonane rzeczywiste klawisze, DOM/AX i obrazy; good/control wskazują fokus, bad ukrywa go przy zachowanym działaniu. Ocena AI konkretnej pary |
| Kontrola integralności i pomiarów | Kontrola źródłowa integralności; odczyt bez ponawiania UI, nie walidator zgodności |
| Człowiek / zaślepiony walidator | NOT-RUN |
Przygotowanie WWW zachowuje ERROR po otwarciu przed serwerem, nieudanym wywołaniu czytnika, niedostępnym navigator oraz starym callbacku. Nie nazywamy ich FAIL aplikacji ani usuwamy historii po poprawce narzędzia. Pierwsze polecenia SDK i serwera trafiły na ograniczenia sandboxu, a następnie wykonano je z dozwoloną eskalacją; to nie błąd produktu. Systemowy Python nie miał PIL; pomiar wykonano dostępnym bundled Python bez instalowania zależności. Szczegóły przeszkód i sprzątania zachowują wynik, a nie domyślny PASS. Serwer i live karta zostały zamknięte, własny runner już nie działał. Uchwyt początkowej karty błędu był zablokowany przez politykę URL; jej automatyczne zamknięcie na końcu tury pozostawało niepotwierdzone w chwili zapisu.
Tab osiągał adres, następny Tab godziny, Shift+Tab wracał na adres, a Space ujawniał adres z licznikiem 1. Po około 2,2 s na iOS obrys good i control pozostał, bad nadal go nie pokazywał. W próbkach webowych od aktywacji do późniejszego odczytu upłynęło 14,324 / 30,910 / 31,338 s; fokus pozostał na adresie. To próbki trwałości, bez obserwacji ciągłej między nimi i bez gwarancji dowolnie długiego czasu.
22 stany i drzewa XCTest, 21 rekordów wejść i 15 PNG dokumentują iOS. CUA dostarczyło zwykłe klawisze w przeglądarce; dziennik ma 91 zdarzeń isTrusted=true, w tym 21 keydown i 21 keyup. Domknięte odczyty DOM nie używały dispatchEvent ani ustawiania fokusu. DOM focus-visible lub primary focus bez obrazu nie potwierdzają widoczności.
Środowisko źródłowe: iPhone 17 Simulator, iOS 26.5; Flutter 3.44.9 / Dart 3.12.2. Badany przycisk miał ten sam prostokąt 24, 241, 354, 52 logical px. Kursor tekstowy, hover i pressed nie były zamiennikiem jego wskaźnika. Pomiar różnicy RGB dotyczył znanej pary obrazów i nie był wykonaniem ACT HSL.
Granice oceny
ACT oj04fd, zatwierdzona reguła z 2023-08-30, bada elementy HTML w sekwencyjnej kolejności fokusu. Porównuje stan przed i po fokusie, szukając co najmniej jednego różniącego się piksela urządzenia w HSL w widocznej części obszaru przewijania. PASS i inapplicable wymagają dalszego badania 2.4.7: mała zmiana piksela nie potwierdza, że użytkownik rozpoznaje pozycję, a element poza zakresem reguły nie jest automatycznie wyłączony z kryterium. Wykluczenie z applicability elementu usuwającego fokus w ciągu jednej sekundy nie usprawiedliwia blur; taki kod może naruszać wymagania klawiatury.
Próg jednej sekundy w definicji reguły jest umowną granicą procedury, nie normatywnym czasem WCAG. W tle historycznego ACT występują dawne numery projektu: Focus Appearance to obecnie 2.4.13, a Focus Not Obscured (Minimum) 2.4.11. Nie przepisujemy dawnej numeracji do karty WCAG 2.2.
Nasz checker nie implementuje ACT: kontroluje prawdziwość zapisów, geometrię, wskazaną parę pikseli RGB, zdarzenia i hashe. DOM :focus-visible, primary focus lub BorderSide bez obrazu nie potwierdzają widoczności; obraz bez zdarzeń nie potwierdza klawiatury. Ocena AI obejmuje wskazane surowe obrazy i kontekst, bez oceny człowieka. Badany walidator nie został uruchomiony; przekazanie mu nazw good/bad lub oczekiwanych etykiet z tej karty zlikwidowałoby zaślepienie.
NOT-RUN: człowiek, zaślepiony walidator, rzeczywisty ACT engine, fizyczny iPhone i zewnętrzna klawiatura, systemowy Full Keyboard Access, VoiceOver, modyfikacja systemowego wskaźnika G165, forced-colors i dodatkowe motywy. Nie są to wykonane próby z wynikiem FAIL ani automatyczny obowiązek czterech nowych buildów. Odbiór XCTest jest rzeczywistym wejściem aplikacji w symulatorze; nie jest testem sprzętu lub technologii asystującej.
Jak sprawdza Clearship
Clearship porównuje obrazy elementu przed i po otrzymaniu fokusu rzeczywistymi klawiszami przejścia na Androidzie. Brak zmiany wyglądu może wskazać kandydata usterki. Ocena nie ustala rozpoznawalności wskaźnika, jego kontrastu, wielkości ani trwałości po czasie; nie obejmuje osobno treści webowej.
W pomiarze z 7 października 2026 r. metoda nie spełniła progu Androida. We Flutterze badane przejście nie uruchamia widocznego wskazania, dlatego pakiet bez żadnego wskaźnika kierowany jest do człowieka. iOS nie ma dostępnego przejścia klawiaturowego produktu i pozostaje niezbadany. Historyczna demonstracja Flutter/iOS tego artykułu używa innego wejścia i nie uzupełnia tej luki produktu.