Bawimy się w pozycjonowanie absolutne względem rodzica – 4 kwadraty pod kątem składające się w całość. Uczymy się animować je symulując odpychanie się od siebie – za pomocą width i height (niezalecane) oraz za pomocą scale, które zwiększa rodzica, zachowując wielkość dziecka. Jeden wzór matematyczny do zapamiętania.
Tworzymy kwadrat-wrapper dla naszych elementów – relative
Tworzymy kwadrat-wrapper w samym środku ekranu, który będzie zawierał nasze kwadraty. Element <div> + linkujemy CSS:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./squares.css">
</head>
<body>
<div class="square-container"></div>
</body>
</html>
Teraz reset stylów, wycentrowanie elementów body przy użyciu flexboxa, stworzenie naszego kwadratowego wrappera, w którym umieszczać będziemy nasze elementy:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 100vh;
background-color: aliceblue;
display: flex;
justify-content: center;
align-items: center;
}
.square-container {
width: 200px;
height: 200px;
background-color: tomato;
position: relative;
}
Wrapper ma position relative, aby elementy wewnątrz niego mogły mieć position absolute i względem niego (rodzica) były pozycjonowane, nie względem całej strony.
Drobna uwaga jest taka, że position absolue pozycjonuje względem pierwszego rodzica, który nie ma positon static (domyślna pozycja) albo względem samej strony. Natomiast jest to pewien swego rodzaju wzorzec, że wrapper ma relative, jeżeli nie chcemy mu zmieniać pozycji tylko dodać dzieci absolutnie wypozycjonowane względem niego.
Tworzymy kwadraty i pozycjonujemy – position absolute
Mamy wrapper, względem niego będziemy pozycjonować elementy, teraz pora je utworzyć – najpierw w HTML, standardowo element <div> z klasą:
<div class="square-container">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>
Aby zmieścić 4 kwadraty w kontenerze 200×200 musimy im nadać wymiary 100×100 oraz position absolute:
.square {
width: 100px;
height: 100px;
position: absolute;
}
Teraz pierwszy kwadrat – pozycjonujemy w lewym górnym rogu i nadajemy mu kolor:
.square:nth-of-type(1){
top: 0;
left: 0;
background-color: thistle;
}
Drugi kwadrat w lewym dolnym rogu:
.square:nth-of-type(2){
bottom: 0;
left: 0;
background-color: teal;
}
Trzeci w prawym dolnym rogu:
.square:nth-of-type(3){
bottom: 0;
right: 0;
background-color: goldenrod;
}
Czwarty w prawym górnym rogu:
.square:nth-of-type(4){
top: 0;
right: 0;
background-color: aquamarine;
}
Dla lepszego efektu rotujemy wrapper o 45 stopni:
.square-container {
(...)
position: relative;
transform: rotate(45deg);
}
Wrapper ma position relative (a w zasadzie – pozycję inną niż domyślne static) więc jego dzieci mając pozycję absolute pozycjonują się absolutnie względem niego. Top 0 left 0 oznacza zero odstępu od góry i lewej strony a zatem górny prawy róg i tak dalej.
Tworzymy animację – kilka ważnych spraw
Aby utworzyć animację odpychania się elementów od siebie moglibyśmy zmienić kolor tła wrappera na brak oraz zmienić mu długość i szerokość:
.square-container {
width: 200px;
height: 200px;
/* background-color: tomato; */
position: relative;
transform: rotate(45deg);
transition: all .5s;
}
.square-container:hover {
width: 400px;
height: 400px;
}
Jeżeli to nas zadowala, to mission complete, nie mamy już nic do roboty. Problem polega na tym, że takich właściwości jak width czy height nie powinno się animować. Złe dla wydajności i nie tylko.
Cóż, możemy zwiększyć nasz wrapper za pomocą scale:
.square-container:hover {
transform: scale(2);
}
Uzyskaliśmy całkiem niezamierzony, ale ciekawy efekt. Tylko nie to chcieliśmy. Po pierwsze utraciliśmy rotację nadpisując transform, co możemy przywrócić:
.square-container:hover {
transform: rotate(45deg) scale(2);
}
Po drugie scale zwiększa nam zarówno element rodzica jaki i elementy dzieci, a nie o to chodziło. Chcieliśmy odepchnąć elementy od siebie. Na szczęście jest wzór matematyczny, który nam pomoże.
Jeżeli rodzic jest skalowany w górę przez scale factor n to dziecko aby zachować oryginalną wielkość musi być skalowane przez 1/n. Czyli rodzic 2, dziecko 1/2 czyli 0.5:
.square {
(...)
transition: all .5s;
}
(...)
.square-container:hover {
transform: rotate(45deg) scale(2);
}
.square-container:hover .square {
transform: scale(0.5);
}
Już, mamy nasz efekt. Znając calc i zmienne CSS moglibyśmy to jeszcze uprościć, ale generalnie to jest ten efekt, w dodatku bez zabawy z width i height, które nie powinny być animowane.