Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Animacje CSS i keyframes w React

Statki kosmiczne nie pojawiają się nagle na ekranie radaru - wlatują, pulsują sygnałem, płynnie przesuwają się po orbicie. Animacje w interfejsach webowych działają na tej samej zasadzie: nadają aplikacji dynamiki i pomagają użytkownikowi zrozumieć, co się dzieje. W tej lekcji poznasz techniki tworzenia animacji CSS w aplikacjach React - od prostych przejść po złożone sekwencje z keyframes, a na końcu zajrzymy do biblioteki React Transition Group.

CSS @keyframes z styled-components

Reguła

@keyframes
pozwala zdefiniować sekwencję kroków animacji. W styled-components korzystamy z helpera
keyframes
, który generuje unikalną nazwę animacji i zapobiega konfliktom:

1import styled, { keyframes } from 'styled-components';
2
3// Definicja animacji - pulsowanie sygnału radarowego
4const radarPulse = keyframes`
5  0% {
6    transform: scale(1);
7    opacity: 1;
8  }
9  50% {
10    transform: scale(1.5);
11    opacity: 0.5;
12  }
13  100% {
14    transform: scale(2);
15    opacity: 0;
16  }
17`;
18
19const RadarDot = styled.div`
20  width: 20px;
21  height: 20px;
22  border-radius: 50%;
23  background: #00ff88;
24  animation: ${radarPulse} 2s ease-out infinite;
25`;

Kluczowe elementy:

  • keyframes
    importujemy z
    styled-components
    (nie z CSS)
  • Wewnątrz definiujemy kroki procentowe (
    0%
    ,
    50%
    ,
    100%
    ) lub słowa kluczowe (
    from
    ,
    to
    )
  • Używamy interpolacji
    ${radarPulse}
    w propercie
    animation

Możesz definiować dowolnie wiele keyframes i łączyć je w różnych komponentach:

1const floatInSpace = keyframes`
2  0%, 100% { transform: translateY(0px); }
3  50% { transform: translateY(-15px); }
4`;
5
6const rotateOrbit = keyframes`
7  from { transform: rotate(0deg); }
8  to { transform: rotate(360deg); }
9`;
10
11const SpaceStation = styled.div`
12  animation: ${floatInSpace} 4s ease-in-out infinite;
13`;
14
15const OrbitRing = styled.div`
16  animation: ${rotateOrbit} 10s linear infinite;
17`;

Transition - płynne przejścia stanów

Właściwość

transition
w CSS to najprostszy sposób na animowanie zmian wartości. Zamiast definiować keyframes, mówisz przeglądarce: "gdy ta właściwość się zmieni, zrób to płynnie". To idealne rozwiązanie dla efektów hover, kliknięcia czy zmiany stanu komponentu.

1const NavButton = styled.button`
2  background: #1a1a3e;
3  color: #00ff88;
4  padding: 12px 24px;
5  border: 2px solid #00ff88;
6  border-radius: 8px;
7  cursor: pointer;
8
9  /* Definiujemy, co ma być animowane i jak */
10  transition: all 0.3s ease;
11
12  &:hover {
13    background: #00ff88;
14    color: #1a1a3e;
15    transform: scale(1.05);
16    box-shadow: 0 0 20px rgba(0, 255, 136, 0.4);
17  }
18`;

Składnia

transition
:

1transition: property duration timing-function delay;
  • property
    - co animujemy (
    all
    ,
    background
    ,
    transform
    ,
    opacity
    ...)
  • duration
    - jak długo trwa przejście (
    0.3s
    ,
    200ms
    )
  • timing-function
    - krzywa animacji (
    ease
    ,
    linear
    ,
    ease-in-out
    ,
    cubic-bezier()
    )
  • delay
    - opóźnienie startu (opcjonalne)

Możesz animować wiele właściwości z różnymi parametrami:

1const ShipPanel = styled.div`
2  opacity: 0.8;
3  transform: translateX(0);
4  background: #0a0a2e;
5
6  transition:
7    opacity 0.2s ease,
8    transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94),
9    background 0.3s ease;
10
11  &:hover {
12    opacity: 1;
13    transform: translateX(10px);
14    background: #1a1a4e;
15  }
16`;

Animation - ciągłe animacje

Właściwość

animation
to bardziej zaawansowana wersja
transition
. Pozwala na ciągłe, powtarzające się animacje, odtwarzanie wstecz i kontrolę nad każdym aspektem ruchu:

1const warningBlink = keyframes`
2  0%, 100% { opacity: 1; }
3  50% { opacity: 0.3; }
4`;
5
6const WarningLight = styled.div`
7  width: 16px;
8  height: 16px;
9  border-radius: 50%;
10  background: #ff4444;
11
12  animation-name: ${warningBlink};
13  animation-duration: 1s;
14  animation-timing-function: ease-in-out;
15  animation-iteration-count: infinite;
16  animation-direction: alternate;
17`;

Albo w skróconej formie:

1animation: name duration timing-function delay iteration-count direction fill-mode;

Najważniejsze parametry:

  • iteration-count
    -
    infinite
    (nieskończone) lub liczba powtórzeń (
    3
    )
  • direction
    -
    normal
    ,
    reverse
    ,
    alternate
    (tam i z powrotem)
  • fill-mode
    -
    forwards
    (zachowaj stan końcowy),
    backwards
    ,
    both
  • play-state
    -
    running
    lub
    paused
    (kontrola odtwarzania)

Dynamiczne animacje oparte na props

W styled-components możesz tworzyć animacje, które reagują na props komponentu. To pozwala na dynamiczne dostosowanie ruchu do stanu aplikacji:

1const moveShip = keyframes`
2  from { transform: translateX(0); }
3  to { transform: translateX(100%); }
4`;
5
6const Spaceship = styled.div`
7  width: 60px;
8  height: 30px;
9  background: #4488ff;
10  clip-path: polygon(0% 50%, 30% 0%, 100% 50%, 30% 100%);
11
12  animation: ${moveShip} ${props => props.speed || 3}s linear infinite;
13  animation-play-state: ${props => props.isFlying ? 'running' : 'paused'};
14  opacity: ${props => props.isFlying ? 1 : 0.5};
15  transition: opacity 0.3s ease;
16`;
17
18function FlightControl() {
19  const [isFlying, setIsFlying] = useState(false);
20  const [speed, setSpeed] = useState(3);
21
22  return (
23    <div>
24      <Spaceship isFlying={isFlying} speed={speed} />
25
26      <button onClick={() => setIsFlying(!isFlying)}>
27        {isFlying ? 'Zatrzymaj' : 'Leć'}
28      </button>
29
30      <input
31        type="range"
32        min="0.5"
33        max="5"
34        step="0.5"
35        value={speed}
36        onChange={(e) => setSpeed(e.target.value)}
37      />
38      <span>Prędkość: {speed}s na okrążenie</span>
39    </div>
40  );
41}

Możesz też dynamicznie wybierać różne keyframes w zależności od stanu:

1const slideIn = keyframes`
2  from { transform: translateX(-100%); opacity: 0; }
3  to { transform: translateX(0); opacity: 1; }
4`;
5
6const slideOut = keyframes`
7  from { transform: translateX(0); opacity: 1; }
8  to { transform: translateX(100%); opacity: 0; }
9`;
10
11const Panel = styled.div`
12  animation: ${props => props.isVisible ? slideIn : slideOut} 0.4s ease forwards;
13`;

To podejście pozwala na animowanie wejścia i wyjścia elementów - panel wsuwa się z lewej strony przy pojawieniu i wysuwa w prawo przy znikaniu.

React Transition Group - CSSTransition

Natywne CSS nie potrafi animować elementów, które są dodawane lub usuwane z DOM (np. przez warunkowe renderowanie

{show && <Component />}
). Biblioteka React Transition Group rozwiązuje ten problem, zarządzając cyklem życia animacji wejścia/wyjścia.

Najczęściej używany komponent to

CSSTransition
:

1import { CSSTransition } from 'react-transition-group';
2import { useState, useRef } from 'react';
3
4function NotificationPanel() {
5  const [showAlert, setShowAlert] = useState(false);
6  const nodeRef = useRef(null);
7
8  return (
9    <div>
10      <button onClick={() => setShowAlert(!showAlert)}>
11        {showAlert ? 'Ukryj alert' : 'Pokaż alert'}
12      </button>
13
14      <CSSTransition
15        in={showAlert}
16        timeout={300}
17        classNames="alert"
18        unmountOnExit
19        nodeRef={nodeRef}
20      >
21        <div ref={nodeRef} className="alert-box">
22          Wykryto obiekt na radarze!
23        </div>
24      </CSSTransition>
25    </div>
26  );
27}

CSSTransition
automatycznie dodaje i usuwa klasy CSS w odpowiednich momentach:

1/* Wejście - start */
2.alert-enter {
3  opacity: 0;
4  transform: translateY(-20px);
5}
6
7/* Wejście - aktywna faza */
8.alert-enter-active {
9  opacity: 1;
10  transform: translateY(0);
11  transition: opacity 300ms ease, transform 300ms ease;
12}
13
14/* Wyjście - start */
15.alert-exit {
16  opacity: 1;
17  transform: translateY(0);
18}
19
20/* Wyjście - aktywna faza */
21.alert-exit-active {
22  opacity: 0;
23  transform: translateY(-20px);
24  transition: opacity 300ms ease, transform 300ms ease;
25}

Kluczowe propsy

CSSTransition
:

  • in
    - boolean kontrolujący, czy element jest widoczny
  • timeout
    - czas trwania animacji (w ms), powinien odpowiadać CSS transition
  • classNames
    - prefiks klas CSS (np.
    "alert"
    generuje
    alert-enter
    ,
    alert-enter-active
    itd.)
  • unmountOnExit
    - usuwa element z DOM po animacji wyjścia
  • nodeRef
    - ref do animowanego elementu (zalecane dla uniknięcia ostrzeżeń)

Transition vs Animation - kiedy co wybrać?

Podsumujmy, kiedy używać poszczególnych technik:

transition
- dla prostych zmian stanów:

  • Efekty hover, focus, active
  • Zmiana koloru, rozmiaru, pozycji przy interakcji
  • Proste wejścia/wyjścia (opacity, transform)

@keyframes
+
animation
- dla złożonych i ciągłych animacji:

  • Pulsowanie, obracanie, latanie
  • Animacje wieloetapowe (więcej niż 2 stany)
  • Nieskończone animacje tła lub dekoracji

React Transition Group - dla animacji cyklu życia komponentów:

  • Animowane montowanie/odmontowanie elementów
  • Listy z animowanym dodawaniem/usuwaniem elementów
  • Przejścia między widokami/stronami

Dobrze zaprojektowane animacje to jak system nawigacyjny statku - prowadzą użytkownika, dają feedback i sprawiają, że interfejs czuje się naturalnie, jak lot przez galaktykę z warp drive, a nie teleportacja bez ostrzeżenia.

Vai a CodeWorlds