Obsługa błędów i wyjaśnienia UX
1) Dlaczego ma znaczenie
Błąd nie jest „czerwonym tekstem”, ale kontynuacją skryptu. Dobre błędy UX:- wyjaśnia, co się stało i co dalej,
- zapisuje wprowadzone dane i zapobiega utracie postępu,
- zapewnia bezpieczną powtarzalność lub alternatywną ścieżkę,
- pozostaje dostępny (SR/klawiatura) i nie ujawnia zbyt wiele.
2) Typologia błędów (dla interfejsu)
1. Walidacja danych (klient 4xx): puste/nieprawidłowe pola, format, długość, konflikt reguł.
2. Zasady działalności: limity, ograniczenia geograficzne, KYC/KYB, duplikaty, niedostępne automaty.
3. Prawa/uprawnienia: rola, dostęp do zasobów, ograniczenia wieku.
4. Sieć/serwer: timeout, offline, 5xx, overload, limit szybkości.
5. Konflikty/status: 409/412 (zmiana danych), wyścigi, zamki.
6. Brak zasobów: 404/410, usunięto/przeniesiono.
7. Płatność i ryzyko: odrzucenie przez bank/PSP, zwalczanie nadużyć finansowych, granice odpowiedzialnej gry.
3) Kanały i poziom wyświetlania
Wybieramy „wolumin” dla kontekstu:Zasada: Nie ukrywać krytyczne w toast/hover. Gdzie użytkownik ogląda, jest wiadomość.
4) Błędy w kopiowaniu
Struktura: przyczyna → efekt → działanie.
Ton: uczciwy, neutralny, bez poczucia winy.
Dane szczegółowe: określić pole/warunek, unikać kodów i stosów.
Akcja przycisku: „Powtarzaj”, „Zmień kartę”, „Zresetuj filtry”, „Otwórz czat”.
Dane wrażliwe: nie pokazują (maskowanie PAN, atrybuty osobiste).
Przykłady
Dobra: "Płatność nie powiodła się: bank odrzucił transakcję. Spróbuj innej metody lub spróbuj ponownie później.
Źle: "Błąd 500. Coś poszło nie tak"
Dobrze: "Osiągnięto limit dziennych wydatków. Ustaw nowy limit lub spróbuj jutro"
Dobrze: "Plik jest zbyt duży (maks. 25 MB). Proszę skompresować lub pobrać kilka plików.
5) Zachowanie i skupienie (A11y)
Błąd jest wyświetlany w kontekście ostrości: przenosimy ostrość do pierwszego błędnego pola.
Regiony żywe: 'rola =' status '(grzeczny) dla informacji,' rola = 'alert' '(asertywny) dla krytycznych.
Widoczne ': focus-visible', kontrast ≥ AA, alternatywy dla koloru (ikona/tekst).
Łączymy wiadomość z polem poprzez 'aria-descripedby'.
html
<label for = "pwd "> Password </label>
<input id="pwd" name="password" aria-describedby="pwd-err" aria-invalid="true">
<p id = "pwd-err" role = "alert"> Minimum 8 characters </p>
6) Retrai, backoff i idempotency
Powtórzenie jest oferowane, jeśli istnieje szansa na sukces (awarie sieci, 5xx, limit szybkości).
Wykładniczy backoff 1-2-4-8 s, granica prób, zrozumiały przycisk „Powtórz”.
Transakcje krytyczne (stawki/płatności): obowiązkowe Idempotency-Key → wykluczyć duplikaty.
Zwijanie z powrotem optymistyczne aktualizacje - jasny wizualny powrót + wyjaśnienie.
js async function retry(fn, attempts=3){
let wait=1000; for(let i=0; i<attempts; i++){
try{ return await fn(); }catch(e){ if(i===attempts-1) throw e; await new Promise(r=>setTimeout(r,wait)); wait=2; }
}
}
7) Offline, timeouts i częściowa zawartość
Offline: pokazujemy baner „Bez połączenia”, dostęp do pamięci podręcznej (tylko do odczytu), kolejkę synchronizacji.
Timeouts: UI timeout (3-5 sekund) → status „Czekając na potwierdzenie”... z bezpiecznym redo/cofnąć.
Częściowy sukces: zachowujemy to, co udało nam się; oznakowanie „nie zsynchronizowane”.
8) Konflikty i konkurencyjność
409/412: nieaktualne dane. Sugeruj „Aktualizuj” i pokaż różnicę (która się zmieniła).
Zamki: informujemy, kto trzyma blok i jak długo, przycisk „Poproś o dostęp”.
9) Przykładowe szablony interfejsu użytkownika
Baner strony:html
<div class="banner banner--error" role="alert">
<strong> Connection failed. </strong> Shows cached data.
<button class =" btn btn--ghost" id = "retry "> Retry </button>
</div>
Modal błędu krytycznego:
html
<div role="alertdialog" aria-labelledby="err-title" aria-describedby="err-desc">
<h2 id = "err-title "> Session expired </h2>
<p id = "err-desc "> Sign in again to continue. </p>
<button class = "btn "> Sign in </button>
<button class =" btn btn--ghost"> Home </button>
</div>
Reakcja ErrorBoundary (z identyfikatorem korelacji):
tsx function Fallback({ id, onRetry }: { id: string; onRetry: ()=>void }) {
return (
<div role="alert" className="banner banner--error">
<strong> We couldn't load the page. </strong>
<div> Try again. Код: <code>{id}</code> <button onClick={()=>navigator. clipboard. writeText (id)}> Copy </button> </div>
<button onClick = {onRetry}> Retry </button>
</div>
);
}
10) Żetony błędów (system projektowania)
json
{
"error": {
"tones": { "danger": "#", "warning": "#", "info": "#" },
"aria": { "polite": true, "assertive": true },
"timing": { "toastMs": 3500, "retryBackoffMs": [1000,2000,4000] },
"layout": { "fieldGap": 8, "bannerIcon": 20 }
}
}
Ustawienia wstępne CSS:
css
.banner--error { background: var(--bg-danger); color: var(--on-danger); padding: 12px 16px; border-radius: 12px; }
.field-error { color: var(--role-danger); margin-top: 6px; font-size:.875rem; }
11) Bezpieczeństwo i prywatność
Nie wyświetlamy śladów stosu, wewnętrznych identyfikatorów, ścieżek baz danych.
Maskujemy wrażliwe wartości (mapy, dokumenty).
Wiadomości nie powinny wywoływać atakującego (na przykład, że konto istnieje).
Dla wsparcia - identyfikator korelacji zamiast części.
json
{"level":"error","event":"payment_fail","correlation_id":"c-8f1...","user_id":"u-","route":"/pay","psp_code":"DO_NOT_EXPOSE_TO_USER"}
12) Metryka i kontrola
INP i udział Long Tasks w momencie błędu (błąd nie powinien „zawiesić” interfejsu użytkownika).
Powtórny wskaźnik sukcesu, błędy na 1000 działań, czas na przywrócenie.
CTR na „Pomoc/Czat”, procent formularzy spadł.
Mapy ciepła: gdzie najczęściej występują błędy pola.
13) Lista kontrolna QA
Dostępność
- Skoncentruj się na pierwszym nieprawidłowym polu; 'aria-described by '/' aria-invalid' set.
- Komunikaty krytyczne - 'rola =' alert ''; kontrast ≥ AA.
Zachowanie
- Dane formularza nie są tracone z powodu błędu.
- Istnieje wyraźny 'Retry' i poprawne backoff.
- Praca w trybie offline/pamięci podręcznej; baner zobacz.
Copywriting
- Powód → Działanie; bez żargonu technicznego i oskarżeń.
- Teksty są zlokalizowane i nie łamią siatki.
Bezpieczeństwo
- Brak wycieków/tajemnic PII; pokaż tylko bezpieczne kody/ID.
- Idempotencja jest możliwa w przypadku operacji krytycznych.
14) Specyfika iGaming
Stawka:- interfejs użytkownika rejestruje natychmiast „zajęty”; z opóźnieniem> 3 s - „Czekanie na potwierdzenie”....
- W przypadku niepowodzenia: uczciwy status („rynek zamknięty”, „współczynnik zmienił się”) + bezpieczny 'Retry'.
- Idempotentny klucz do wyeliminowania podwójnej oferty.
- Rozróżniamy "awaria banku/PSP" vs "awaria serwera. "Dla pierwszego - "Wybierz inną metodę", dla drugiego - 'Retry '.
- Przejrzyste kroki KYC/AML; linki "Dlaczego jest to konieczne? ».
- Ton jest troskliwy, bez presji. „Osiągnięty limit - wstrzymać lub zaktualizować limit”.
- Brak ognisk/neonu; Kontrast AAA, dostępność w SR.
- Jasno wyjaśnij ograniczenia i sugeruj „Przeczytaj zasady/wsparcie”.
15) Anty-wzory
„Coś poszło nie tak” bez działania i kontekstu.
Resetuje formularz po błędzie.
Ukryj krytyczne tosty przez 3 sekundy.
Tylko kolor bez tekstu/ikony.
Niekończące się rekolekcje bez możliwości odwołania.
Pokaż kody wewnętrzne/trasy stosu.
16) Dokumentacja w systemie projektowym
Кобонента: „Error”, „FormError”, „Banner”, „AlertDialog”, „ErrorBoundary”.
Żetony tonalne/kontrastowe/czasowe, ustawienia wstępne a11y i przykłady ARIA.
Mapa typowych scenariuszy (walidacja, sieć, prawa, płatności) z szablonami tekstowymi.
„Do/Don”: prawdziwe przed/po ekranach z miernikami awarii/sukcesu.
Krótkie podsumowanie
Popełnić błędy zrozumiałe i zarządzalne: mówić językiem ludzkim, zapisywać wprowadzone dane, oferować bezpieczne powtarzanie i alternatywy, szanować dostępność i prywatność. Wtedy nawet sytuacje awaryjne zachowują pewność siebie i nie przerywają ścieżki użytkownika - zwłaszcza w krytycznych scenariuszach zakładów i płatności.