Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Zaawansowane wzorce animacji

W zaawansowanych systemach NOVA LAB potrzebujemy wyrafinowanych efektów — kaskadowe ładowanie elementów dashboardu, animacja przy pierwszym wyświetleniu strony, precyzyjna kontrola czasów trwania i szacunek dla preferencji użytkowników dotyczących ruchu. Poznaj wzorce, które nadają interfejsom profesjonalny charakter.

Appear — animacja przy mount

Domyślnie

<Transition>
animuje element tylko przy przełączeniu
v-if
/
v-show
. Atrybut
appear
powoduje, że animacja uruchomi się również przy pierwszym renderowaniu (mount) komponentu:

1<Transition appear name="fade">
2  <div>Ten element animuje się przy załadowaniu strony</div>
3</Transition>

To idealne rozwiązanie dla elementów widocznych od razu po załadowaniu — logo stacji, nagłówek dashboardu, panel statusu. Bez

appear
te elementy po prostu "byłyby tam" bez żadnej animacji wejścia.

Możesz użyć specjalnych klas CSS dla animacji appear (niezależnych od normalnych klas enter):

1<Transition
2  appear
3  appear-from-class="appear-start"
4  appear-active-class="appear-running"
5  appear-to-class="appear-end"
6>
7  <div>Custom appear animation</div>
8</Transition>

Lub z bibliotekami:

1<Transition
2  appear
3  appear-active-class="animate__animated animate__fadeInDown"
4>
5  <header>NOVA LAB Control Center</header>
6</Transition>

Staggered list animation

Jeden z najbardziej efektownych wzorców — kaskadowe pojawianie się elementów listy, gdzie każdy kolejny element pojawia się z rosnącym opóźnieniem. Wygląda jak wyświetlanie danych na holograficznym dashboardzie NOVA LAB, element po elemencie:

1<TransitionGroup
2  appear
3  :css="false"
4  @before-enter="onBeforeEnter"
5  @enter="onEnter"
6  tag="div"
7>
8  <div v-for="(item, index) in items" :key="item.id" :data-index="index">
9    {{ item.name }}
10  </div>
11</TransitionGroup>

Kluczem jest atrybut

:data-index
— przekazuje indeks elementu do hooka JS, który oblicza opóźnienie:

1function onBeforeEnter(el) {
2  el.style.opacity = 0
3  el.style.transform = 'translateY(20px)'
4}
5
6function onEnter(el, done) {
7  // Każdy kolejny element ma o 150ms większe opóźnienie
8  const delay = el.dataset.index * 150
9
10  setTimeout(() => {
11    el.style.transition = 'all 0.5s ease'
12    el.style.opacity = 1
13    el.style.transform = 'translateY(0)'
14    el.addEventListener('transitionend', done, { once: true })
15  }, delay)
16}

Efekt: element 0 pojawia się natychmiast, element 1 po 150ms, element 2 po 300ms itd. Dla 10 elementów cała animacja trwa 1.5s + 0.5s (czas samej animacji) = ~2s.

Wskazówka: Ogranicz opóźnienie do max ~1s, aby użytkownik nie czekał zbyt długo na ostatnie elementy:

1const delay = Math.min(el.dataset.index * 100, 1000)

Explicit duration

Gdy element ma zarówno CSS transition jak i animation, lub gdy zagnieżdżone elementy mają różne czasy animacji, Vue może nie wykryć prawidłowego momentu zakończenia. Atrybut

:duration
pozwala jawnie określić czas trwania w milisekundach:

1<!-- Jednolity czas dla wejścia i wyjścia -->
2<Transition :duration="500">...</Transition>
3
4<!-- Różne czasy dla wejścia i wyjścia -->
5<Transition :duration="{ enter: 300, leave: 500 }">...</Transition>

Jest to szczególnie przydatne gdy:

  • Animujesz zagnieżdżone elementy z różnymi czasami
  • Łączysz CSS transition i animation na tym samym elemencie
  • Używasz bibliotek zewnętrznych, których czas trwania nie jest automatycznie wykrywany

Accessibility — prefers-reduced-motion

Szanuj ustawienia użytkownika dotyczące ruchu. Osoby z zaburzeniami przedsionkowymi lub epilepsją mogą mieć włączoną preferencję

prefers-reduced-motion
. Twój CSS powinien to respektować:

1/* Normalne animacje */
2.fade-enter-active,
3.fade-leave-active {
4  transition: opacity 0.3s ease, transform 0.3s ease;
5}
6
7.fade-enter-from,
8.fade-leave-to {
9  opacity: 0;
10  transform: translateY(10px);
11}
12
13/* Wyłącz animacje dla użytkowników, którzy ich nie chcą */
14@media (prefers-reduced-motion: reduce) {
15  .fade-enter-active,
16  .fade-leave-active {
17    transition: none;
18  }
19
20  .fade-enter-from,
21  .fade-leave-to {
22    opacity: 1;
23    transform: none;
24  }
25}

Możesz też obsłużyć to w JavaScript:

1const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
2
3function onEnter(el, done) {
4  if (prefersReducedMotion) {
5    done() // Pomiń animację
6    return
7  }
8  // Normalna animacja...
9}

Best practices wydajności

  1. Animuj tylko

    transform
    i
    opacity
    — te właściwości są akcelerowane przez GPU i nie powodują reflow/repaint. Unikaj animowania
    width
    ,
    height
    ,
    top
    ,
    left
    ,
    margin
    ,
    padding
    .

  2. Używaj

    will-change
    dla ciężkich animacji — informuje przeglądarkę o nadchodzącej animacji, pozwalając na optymalizację:

1.heavy-animation-enter-active {
2  will-change: transform, opacity;
3  transition: all 0.5s ease;
4}
  1. Preferuj CSS nad JS — CSS animations są optymalizowane przez przeglądarkę i działają na osobnym wątku. Używaj JS hooków tylko gdy potrzebujesz dynamicznych wartości.

  2. Krótkie czasy trwania — animacje UI powinny trwać 200-500ms. Dłuższe animacje spowalniają interakcję i irytują użytkowników.

  3. Testuj na urządzeniach mobilnych — animacje, które działają płynnie na desktopie, mogą lagować na starszych telefonach.

Przejdź do CodeWorlds