Kawałek Kodu

Jeśli jesteś pasjonatem zjawisk paranormalnych, to te w dzisiejszym wpisie powinny Cię ogromnie zainteresować. Będziemy poruszać problem restartu animacji CSS. Poruszać również dosłownie. I oczywiście zrobimy to bez wykorzytania JavaScript!

Zakasajmy rękawy! Za nasz przykład posłuży prosty HTML zawierający obiekt SVG oraz efekt bujania oparty o animację CSS. Oczywiście animacja może być inna, obiekt również.

<img src="ufo.svg" alt="Ufo" class="ufo"/>

+

.ufo {
  width: 181px;
  height: 112px;
  animation-name: swing;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-play-state: paused;
}

.ufo:hover {
  animation-play-state: running;
}

@keyframes swing {
  0% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(-7deg);
  }
  50% {
    transform: rotate(7deg);
  }
  75% {
    transform: rotate(-7deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

Nie ma co za dużo tu opisywać. Ustalamy dla obiektu klasy .ufo animację o nazwie swing. Animacja będzie trwać 2 sekundy z easingiem. Póki co jest spauzowana, a wystartuje po najechaniu myszą na obiekt.

Sprawdźmy więc co się dzieje.

Wszystko działa. Najeżdżam myszą na obiekt, ten się animuje. Zjeżdżam z obiektu, ten przestaje się animować.
Ale czekaj! Co się dzieje kiedy animacja dobiegnie końca i znów najedziesz myszą? Nic, dosłownie nic, animacja nie startuje ponownie.

Houston, mamy problem!

Dlaczego tak się dzieje? Powód jest taki, że animacja po prostu skończyła się... W zależności od tego czy animation-fill-mode jest ustawiona na forwards czy też none, w trakcie trzymania myszy nad obiektem, albo zostaniemy na ostatniej klatce, albo wrócimy do domyślnych właściwości obiektu, ale animacja wciąż nie wystartuje po powtórnym hover. To jest to pierwsze, dosyć osobliwe dla nas zjawisko. Ktoś widocznie uznał, że to standard.

My jednak na osobliwe zjawisko odpowiemy jeszcze dziwniejszym. Skoro mamy w CSS pseudoklasę :hover, to możemy wykorzystać :not, aby zanegować to "zdarzenie", co będzie odpowiadac momentowi zjechania myszy z obiektu. Właściwie nie momentowi, ale stanowi w jakim znajduje się obiekt. Może Cię tu zastanowić kwestia czy .ufo:not(:hover) nie jest równoważny selektorowi .ufo. Nie. Drugi odpowiada obiektowi w jakimkolwiek ze stanów (czy z hover czy bez, ale nie Ohio!).

This is not happening, this is not happening!

No, dobra, ale to jeszcze nie rozwiązuje problemu, bo jak wykorzystać ten fakt? Wykorzystamy go w ten sposób, że na ten moment ustawimy dla obiektu nieistniejącą animację. Hę?!

.ufo:not(:hover) {
  animation-name: empty;
}

Ja też robię "hę?!", ale to działa. Przypisanie na chwilę do obiektu innej animacji (w tym przypadku nieistniejącej) i powrót do głównej (swing) przy selektorze .ufo, powoduje wystartowanie tej drugiej animacji od nowa. Bo dlaczego miałoby nie działać(?)

Tak to będzie wyglądać teraz. Najedź myszą, odczekaj do końca, zjedź i...znów najedź.

Narazie chwila odpoczynku po ciągłym bujaniu, wjeżdżaniu i zjeżdżaniu. Niedługo kolejny wpis!

 

Przydatne linki:
Właściwość animation w CSS