Animacja ładowania strony tylko w CSS – krok po kroku
Chciałem zrobić animacje ładowania strony, która składa się z kulek, które falują.
Jak zaplanowałem tak zrobiłem:
See the Pen Balls loading animation by soltys (@soltys) on CodePen.
Wygląd jest inspirowany malutką giereczką 140.
Podczas pisania nauczyłem się parę tricków w SASS i CSS.
Jak wycentrować coś pionie przy użyciu CSS?
Przy użyciu flexbox tak:
html,
body {
height: 100%;
background:#ddd;
}
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
Po pierwsze dbamy o to, aby przestrzeń zajmowana przez html
, body
oraz div.container
zajmowała całą dostępną wysokość w podglądzie CodePen. Następnie wszystko centrujemy przy użyciu flexboxa.
HTML, który jest potrzebny do naszej animacji wygląda, tak:
A tak to przekłada z klasy na kolor składowy każdej kulki:
Jak zrobić kulkę z kwadratu w CSS?
Trzeba ustalić border-radius
na połowę szerokości/wysokości kwadratu.
.circle {
width: $ball-size;
height: $ball-size;
border-radius: 50%;
background: $outer-ball-color;
margin: 0 5px;
}
Gdzie:
$ball-size
jest rozmiarem naszej kulki – u mnie jest30px
$outer-ball-color
jest kolorem naszej kulki – u mnie jest to#4D2C71
- ustalamy
margin
, aby dać każdej kulce trochę odstępu od siebie.
Jak zrobić kulkę w wewnątrz innej kulki?
Utwórz nowy div
, a w nim ustal kulkę na połowę wielkości tej zewnętrznej.
.inner-circle {
width: $ball-size/2;
height: $ball-size/2;
border-radius: 50%;
background: $inner-ball-color;
margin: $ball-size/4;
}
W porównaniu z zewnętrzną kulką ustalamy margin
w celu wycentrowania jej wewnątrz fioletowej kulki.
U mnie $inner-ball-color
ma wartość #F3BB1C
.
Jak pokolorować połowę kulki na inny kolor?
Trzeba nałożyć na połowę żółtej kulki kwadrat i odciąć to co wystaje poza żółta kulkę.
Aby przeglądarka pozbywała się czegoś co wychodzi poza obręb jakiegoś div
a trzeba zdefiniować overflow: hidden
. Ten atrybut trzeba dodać do .inner-circle
!
reszta CSSa wygląda tak:
.part-cicle {
position: relative;
top: $ball-size/4;
width: $ball-size/2;
height: $ball-size/2;
background: $part-ball-color;
}
Interesuje nas pozycja relatywna – position: relative
względem rodzica, czyli .inner-child
. Przesuwamy się o połowę wysokości .inner-child
.
U mnie $part-ball-color
ma wartość #FF0000
.
Jak zrobić efekt fali w poruszaniu się kulek?
Najpierw zdefiniujmy jak ma wyglądać animacja poruszania się góra-dół.
@keyframes up {
0% {
transform: translate(0, $moving-amplitute);
}
50% {
transform: translate(0, -$moving-amplitute);
}
100% {
transform: translate(0, $moving-amplitute);
}
}
$moving-amplitute
to maksymalne wychylenie, które będzie zastosowane na każdą z kulek. U mnie ta wartość wynosi 5px
. Animacja jest tak skonstruowana, aby zaczynała i kończyła się w tym samym miejscu, dzięki czemu kulki się poruszają w sposób płynny, nie ma przeskoków.
Efekt fali jest uzyskany dzięki temu, że każda animacja uruchomiona jest troszkę później niż poprzednia.
.circle:nth-child(1) {
animation: up 1s -0.25s infinite ease-in-out;
}
.circle:nth-child(2) {
animation: up 1s -0.5s infinite ease-in-out;
}
.circle:nth-child(3) {
animation: up 1s -0.75s infinite ease-in-out;
}
W powyższym przykładzie definiujemy animacje dla każdego kolejnego elementu .circle
. Składnia animation
wygląda następująco
up
– animation-name czyli wskazujemy na definicje animacji, zdefiniowanej przez@keyframes
.1s
– czas w sekundach na wykonanie animacji-0.25s
– czas w sekundach, opóźnienie animacji. Opóźnienie ujemne? Tego tricku nauczyłem dosłownie 5 minut temu 🙂 W momencie ustawienia animacji z opóźnieniem ujemnym, animacja rozpocznie się tak szybko jak może, ale zacznie od momentu0.25s
w animacji. Dzięki temu, przy ładowaniu strony kulki już są w odpowiednich miejscach i nie ma efektu, jakby one zaspały.infinite
– oznacza, że animacja będzie zapętlonaease-in-out
– oznacza, że przeglądarka wygładzi ruch kulki, będzie on przypominać odbicie od podłogi, niż ruch liniowy, bez hamowania.
Taki kod CSS może zostać wygenerowany przy użyciu SASSa, preprocesora CSS.
.circle {
/* ... wyciete ... */
@for $i from 1 to $ball-number+1 {
&:nth-child(#{$i}) {
animation: up 1s ($moving-up-delay * -$i) infinite ease-in-out;
}
}
}
$ball-number
to ilość kulek w naszej animacji czyli 3
. $moving-up-delay
to wartość opóźnienia, między kolejnymi kulkami u mnie ta wartość to 0.25s
. Znak &
oznacza odwołanie od rodzica w zapisie, czyli znak &
zostanie zastąpiony .circle
.
Bonus: Co zrobić jak nie wiesz, że animation-delay
może przyjąć wartość ujemną? Co zrobić, aby wartości ustawione przez animację animacji zostały?
Podczas pisania tej animacji za pierwszym razem, nie wiedziałem, że animation-delay
może przyjąć wartość ujemną. Efekt był taki, że kulki stoją pozycji startowej i czekają, aby zacząć się animować. Znalazłem na to rozwiązanie, jak ten brzydki efekt ukryć.
dodać do .circles
taki fragment kodu CSS:
.circles {
/* ... wyciete ... */
animation: fadein 1s ($moving-up-delay*$ball-number) ease-in;
animation-fill-mode: forwards;
opacity: 0;
}
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
czyli dodałem animację przejścia przeźroczystości od 0 do 1 (od niewidocznego do widocznego). Po załadowaniu strony niewidoczne kulki startują swoją animacje, gdy już wszystkie powinny wystartować startuje animacja przechodzenie przeźroczystości.
Tutaj ważne jest ustawienie animation-fill-mode: forwards;
dzięki niemu wartość opacity
pozostaje ustawione na 1
po wykonaniu animacji.
Jak wykonać rotację środka?
To bardzo proste:
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
.circle:nth-child(1) > .inner-circle {
animation: rotate 1s 0.05s infinite;
}
.circle:nth-child(2) > .inner-circle {
animation: rotate 1s 0.1s infinite;
}
.circle:nth-child(3) > .inner-circle {
animation: rotate 1s 0.15s infinite;
}
/*
* Czyli w SASS coś takiego
*/
.circle {
/* ... wyciete ... */
@for $i from 1 to $ball-number+1 {
&:nth-child(#{$i}) > .inner-circle {
animation: rotate 1s ($rotation-delay * $i) infinite;
}
}
}
Każda kulka obraca się w czasie 1s
z maleńkim opóźnieniem wobec swojego sąsiada, według mnie, dzięki temu wygląda to lepiej, niż synchroniczne obroty.
u mnie $rotation-delay
wynosi 0.05s
.
Podsumowanie
Dzięki zrobieniu tak prostej animacji sporo się nauczyłem:
- CodePen to fajne narzędzie do prototypowania swoich animacji (ALE raz Codepen zrobi mi totalną sieczkę z CSSa – narzędzie czasem nie jest idioto-odporne)
- Wykorzystanie SASSa i zmiennych przyspiesza jeszcze bardziej przyspiesza proces prototypowania
- CSS obsługuje centrowanie poziomie! Niech żyje
flexbox
. animation-fill-mode: forwards;
– dzięki niemu wartości wyliczone przez animację zostają zapisane.animation-delay
może przyjąć wartości ujemne.
Dzięki Łukasz za sprawdzenie posta przed publikacją.