Lekcja 27
Dostępne animacje i prefers-reduced-motion
Ruch w interfejsie może pomagać zrozumieć zmianę, ale może też przeszkadzać użytkownikom wrażliwym na animacje. W tej lekcji nauczysz się projektować mikrointerakcje, które respektują ustawienia systemowe i zachowują informację bez zbędnego ruchu.
Cele lekcji
Po ukończeniu tej lekcji będziesz umieć:
- wyjaśnić, czym jest
prefers-reduced-motion, - napisać regułę
@media (prefers-reduced-motion: reduce), - odróżnić ograniczenie ruchu od usunięcia całego feedbacku,
- projektować alternatywy dla animacji wejścia, loaderów i efektów scrolla,
- używać prostych tokenów ruchu w CSS,
- testować, czy komponent nadal komunikuje stan po wyłączeniu animacji.
Kontekst praktyczny
Dostępny ruch jest ważny w dashboardach, formularzach, aplikacjach edukacyjnych, sklepach i panelach użytkownika. Największe ryzyko pojawia się przy efektach scrolla, parallaxie, dużych przesunięciach, nieskończonych loaderach i animacjach, które migają albo wymuszają śledzenie elementu wzrokiem.
Czym jest prefers-reduced-motion
prefers-reduced-motion to media feature, który informuje stronę, że użytkownik preferuje mniej animacji. Najczęściej obsługujesz wartość reduce.
@media (prefers-reduced-motion: reduce) {
.animated-panel {
animation: none;
transition-duration: 0ms;
}
}
Ta reguła powinna być świadomym wariantem komponentu, a nie przypadkowym wyłączeniem wszystkiego na końcu arkusza.
Reduce, nie zawsze remove
Ograniczenie ruchu nie oznacza usunięcia informacji. Gdy karta przestaje wysuwać się z boku, nadal może zmienić kolor obramowania, tło albo ikonę statusu. Feedback ma zostać, tylko bez dużego ruchu.
.notice {
opacity: 0;
transform: translateY(.75rem);
animation: notice-enter 240ms ease-out forwards;
}
@media (prefers-reduced-motion: reduce) {
.notice {
opacity: 1;
transform: none;
animation: none;
border-color: #22c55e;
}
}
Transition i animation
Dla transition najczęściej skracasz czas trwania albo zostawiasz tylko zmianę koloru. Dla @keyframes zwykle wyłączasz sekwencję i ustawiasz stan końcowy wprost.
.card-link {
transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
}
.card-link:hover {
transform: translateY(-.2rem);
}
@media (prefers-reduced-motion: reduce) {
.card-link {
transition: border-color 120ms ease, background-color 120ms ease;
}
.card-link:hover {
transform: none;
}
}
Alternatywa bez ruchu
Wariant bez ruchu powinien nadal odpowiadać na pytanie: co się zmieniło? Używaj koloru, kontrastu, obramowania, tekstu statusu, ikony albo zmiany układu, która nie jest animowana.
.save-state {
border: 1px solid #bbf7d0;
background: #f0fdf4;
color: #166534;
}
@media (prefers-reduced-motion: reduce) {
.save-state::before {
content: "Zapisano";
font-weight: 800;
}
}
Nie polegaj wyłącznie na ruchu. Jeśli animowany element znika albo zatrzymuje się, użytkownik nadal musi rozumieć stan.
Scroll i parallax
Efekty scrolla i parallax potrafią być bardziej obciążające niż małe mikrointerakcje. W trybie ograniczonego ruchu wyłącz płynne przewijanie i ruch zależny od scrolla.
html {
scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
.parallax-layer {
transform: none;
}
}
Tokeny ruchu
W większym projekcie warto zapisać czas i dystans ruchu jako zmienne CSS. Dzięki temu tryb ograniczonego ruchu można kontrolować globalnie, bez przepisywania każdego komponentu.
:root {
--motion-duration-fast: 160ms;
--motion-distance-sm: .35rem;
}
@media (prefers-reduced-motion: reduce) {
:root {
--motion-duration-fast: 1ms;
--motion-distance-sm: 0;
}
}
Demo dostępnego ruchu
Demo pokazuje ten sam komunikat w dwóch wariantach: z ruchem oraz z ograniczonym ruchem. Drugi wariant nie traci informacji, tylko rezygnuje z przesunięć i pulsowania.
Animowany feedback
Komunikat wchodzi przez krótki ruch i subtelny fade.
Spokojny feedback
Stan jest widoczny przez kolor, obramowanie i tekst bez ruchu.
- transformnone
- animationnone
- feedbackzachowany
Najczęstsze błędy początkujących
- Wyłączanie animacji bez ustawienia stanu końcowego komponentu.
- Usuwanie całego feedbacku, zamiast zamiany ruchu na kolor, tekst albo obramowanie.
- Zostawianie
scroll-behavior: smoothw trybie ograniczonego ruchu. - Animowanie dużych przesunięć, parallaxu i nieskończonych efektów bez alternatywy.
- Ukrywanie błędów formularza albo statusów tylko przez animację.
- Dodawanie jednej globalnej reguły, która przypadkowo niszczy potrzebne stany UI.
Mini zadanie
Przerób komponent powiadomienia z lekcji 26 na wersję dostępną.
- Dodaj animację wejścia przez
opacityitransform. - W
@media (prefers-reduced-motion: reduce)wyłącz animację. - Ustaw stan końcowy ręcznie:
opacity: 1itransform: none. - Zachowaj informację o sukcesie przez kolor, ikonę albo tekst statusu.
- Sprawdź, czy po ograniczeniu ruchu komponent nie znika i nie traci znaczenia.
Checklista
- Wiem, po co istnieje
prefers-reduced-motion. - Potrafię napisać wariant
@media (prefers-reduced-motion: reduce). - Nie polegam wyłącznie na animacji jako informacji o stanie.
- W trybie reduced motion ustawiam stan końcowy komponentu wprost.
- Wyłączam albo ograniczam efekty scrolla, parallax i nieskończony ruch.
- Projektuję feedback tak, żeby był czytelny także bez animacji.
Podsumowanie lekcji
Dostępna animacja ma cel, krótki czas trwania i spokojną alternatywę. prefers-reduced-motion pozwala uszanować ustawienia użytkownika, ale Twoim zadaniem jest zachować sens komponentu także wtedy, gdy ruch zostanie ograniczony.
Kolejny krok roadmapy to Moduł 6 i lekcja o nazewnictwie klas oraz BEM-like naming.
Przejdź do Lekcji 28