Wykonamy kilka ćwiczeń z flexboxem, aby zrozumieć jego podstawowe możliwości. Zamieniamy wiedzę teoretyczną i pewne nieuporządkowane podstawy w praktykę za pomocą kilku prostych ćwiczeń.
Wycentruj elementy w pionie i poziomie
Jeden element-dziecko (box), jeden rodzic (body). Zadanie – wycentruj w pionie i poziomie ten kwadrat:
<body>
<div class="box"></div>
</body>
Reset stylów:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
Kwadrat 200 na 200 o jakimś kolorze:
.box {
height: 200px;
width: 200px;
background-color: tomato;
}
Body jako flex-rodzic:
body {
height: 100vh;
background-color: teal;
display: flex;
/*domyślnie:
flex-direction: row; */
justify-content: center;
align-items: center;
}
Body musi mieć wysokość. Domyślnie flex-direction to row, oś główna to lewo/prawo (jest jeszcze row-reverse, który ma prawo/lewo). Justify-content ustawia w centrum na osi lewo/prawo, align-items ustawia w centrum na osi góra/dół.
Wycentruj lewo/prawo, doklej do góry ekranu
Oto nasza pseudo-nawigacja:
<div class="nav">
<button>ClickMe</button>
<button>ClickMe</button>
<button>ClickMe</button>
<button>ClickMe</button>
</div>
Startowy CSS:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nav {
width: 100%;
height: 200px;
background-color: teal;
display: flex;
/* domyślnie
flex-direction: row;
align-items: stretch; */
}
Domyślnie flex-direction to row, czyli oś główna lewo/prawo, oś poboczna góra/dół. Domyślnie align-items ustawione na stretch, czyli na osi pobocznej wszystko rozciąga się, rozlewa się, zatem nasze guziki są od góry do dołu.
Mają być doklejone do góry, a zatem:
.nav {
width: 100%;
height: 200px;
background-color: teal;
display: flex;
/* domyślnie
flex-direction: row; */
align-items: flex-start;
}
Na osi pobocznej (góra/dół) przestały się rozciągać i zostały doklejone do początku tej osi (do góry). Teraz na osi lewo/prawo pora je wycentrować:
.nav {
width: 100%;
height: 200px;
background-color: teal;
display: flex;
/* domyślnie
flex-direction: row; */
align-items: flex-start;
justify-content: center;
}
Trzy responsywne elementy o równych proprocjach
Mamy pseudo-nawigację:
<div class="nav">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Chcemy trzy elementy o równych proporcjach, które zwężają się i rozszerzają. Najpierw flex-rodzic:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nav {
width: 100%;
height: 200px;
background-color: teal;
display: flex;
}
Teraz dzieci:
.item:nth-of-type(1) {
flex: 1;
background-color: gold;
}
.item:nth-of-type(2) {
flex: 1;
background-color: tomato;
}
.item:nth-of-type(3) {
flex: 1;
background-color: green;
}
Jeżeli chcemy mieć minimum, możemy ustawić dowolnemu dziecku min-width. Jeżeli chcemy inne proporcje – możemy proporcjonalnie zwiększać wartość flex elementu danego dziecka (proporcjonalnie względem innych flexów).
Tak wygląda prosty przykład 1/4 1/2 1/4:
.item:nth-of-type(1) {
flex: 1;
background-color: gold;
}
.item:nth-of-type(2) {
flex: 2;
background-color: tomato;
}
.item:nth-of-type(3) {
flex: 1;
background-color: green;
}
Gridowym odpowiednikiem byłoby 1fr 2fr 1fr w grid-template-columns.
Hamburger hidden column – flex-kolumna
Do naszego pseudo-navbara dodajemy kolumnę, która ma się wyświetlać na mobilnych urządzeniach po kliknięciu w hamburgera:
<div class="nav">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="hamburger-column">
<button>O NAS</button>
<button><a href="">COŚTAM</a></button>
<button><a href="">COŚTAM</a></button>
<button><a href="">COŚTAM</a></button>
<button><a href="">COŚTAM</a></button>
</div>
Ma zajmować całą szerokość. Elementy mają rozlewać się na całą szerokość kolumny, mieć domyślną wysokość 80px.
.hamburger-column {
width: 100%;
background-color: blueviolet;
display: flex;
flex-direction: column;
/* domyślne */
/* align-items: stretch; */
}
Szerokość na 100%. Kierunek – kolumna, zatem oś poboczna to lewo/prawo. Align-items domyślnie ustawione na stretch działa na osi pobocznej – rozlewa elementy na lewo i prawo.
Teraz element:
button {
flex-basis: 80px;
background-color: aliceblue;
}
Jako że element jest kolumnowy to oś główna to góra/dół. Flex-basis to domyślna wielkość osi głównej czyli domyślna wysokość 80px. Na osi lewo-prawo rozlewają się, jak należy.
Możemy jeszcze ustawić text-align, które nie ma nic wspólnego z flexboxem, ale ustawi tekst naszego guzika na lewo:
button {
flex-basis: 80px;
background-color: aliceblue;
text-align: left;
}
Kostka 4 i 6 – space-between, kolumny i rzędy
Budujemy flexboxową kostkę, pokazującą liczbę 4. Kostka to rząd 2 kolumn, każda zawiera dwa doty:
<div class="dice">
<div class="column">
<div class="dot"></div>
<div class="dot"></div>
</div>
<div class="column">
<div class="dot"></div>
<div class="dot"></div>
</div>
</div>
Podstawowe style kostki i reset stylów ogólnych CSS:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.dice {
width: 400px;
height: 400px;
border: 1px solid black;
border-radius: 25%;
background-color: thistle;
}
Podstawowe style kropki (no takiej prawie kropki) na naszej kostce:
.dot {
width: 40px;
height: 40px;
background-color: black;
border-radius: 25%;
}
Odpychamy dzieci naszej kostki od siebie:
.dice {
(...)
display: flex;
justify-content: space-between;
padding: 30px;
}
Jako że kostka to rząd oś główna to lewo/prawo, zatem justify content tutaj odpycha nasze 2 elementy-dzieci na osi lewo/prawo od siebie. Jedna kolumna po lewej, druga po prawej.
Teraz nasze kolumny, odepchnijmy dzieci od siebie:
.column {
display: flex;
flex-direction: column;
justify-content: space-between;
}
Jako że flex-direction mamy kolumnowy oś główna idzie od góry do dołu. Justify-content odpycha te elementy na osi góra/dół dając nam ładną kostkę. Nic, tylko dodać odrobinę paddingu:
.dice {
(...)
padding: 30px;
}
Kostkę 6 zrobimy sobie zaraz „po Bożemu”, ale na razie spróbujmy przerobić to co mamy na kostkę 6, to też cenna umiejętność. Robimy to w HTML:
<div class="dice">
<div class="column">
<div class="dot"></div>
<div class="dot"></div>
</div>
<div class="column">
<div class="dot"></div>
<div class="dot"></div>
</div>
<div class="column">
<div class="dot"></div>
<div class="dot"></div>
</div>
</div>
Mamy 3 kolumny po 2 elementy, kolumny i elementy odepchnięte od siebie. Taka kostka 6 bokiem, ale to można łatwo rozwiązać:
.dice {
(...)
transform: rotate(90deg);
}
Kostka 6 poprawne podejście – 2 kolumny po 3 elementy
Pomyślmy, jak wygląda kostka 6. Mamy jeden rząd 2 kolumn (odepchniętych od siebie lewo/prawo), każda kolumna po 3 kropki, odepchnięte od siebie góra/dół. Nasz HTML będzie wyglądać tak:
<div class="dice">
<div class="column">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div class="column">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
</div>
Główne style:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.dice {
width: 400px;
height: 400px;
border: 1px solid black;
border-radius: 25%;
background-color: thistle;
(...)
padding: 30px;
}
.dot {
width: 40px;
height: 40px;
background-color: black;
border-radius: 25%;
}
Odpychamy kolumny kostki od siebie:
.dice {
(...)
display: flex;
justify-content: space-between;
}
Skoro kostka to rząd (domyślny flex-direction) to oś główna to lewo/prawo. Justify-content odpycha nasze 2 dzieci (po 3 doty każdy) na osi lewo/prawo.
Teraz kolumna, która wygląda tak samo jak poprzednio
.column {
display: flex;
flex-direction: column;
justify-content: space-between;
}
Skoro kolumna, to oś główna góra/dół. Skoro tak, justify-content odpycha elementy na osi góra/dół od siebie. Mamy kostkę 6.
Kostka 2 – align-self dla ustawiania indywidualnie osi pobocznej
Potrzebny nam rząd odsuniętych od siebie elementów, dokładnie dwóch:
<div class="dice">
<div class="dot"></div>
<div class="dot"></div>
</div>
Teraz kostka:
.dice {
(...)
display: flex;
justify-content: space-between;
}
Rząd, czyli oś główna to lewo/prawo. Justify-content odsuwa elementy lewo/prawo od siebie. Align-items działałoby na osi pobocznej góra/dół i możemy te doty przenieść na dół:
.dice {
width: 400px;
height: 400px;
border: 1px solid black;
border-radius: 25%;
background-color: thistle;
display: flex;
justify-content: space-between;
align-items: flex-end;
padding: 30px;
}
.dot {
width: 40px;
height: 40px;
background-color: black;
border-radius: 25%;
}
Problem w tym, że tylko 1 ma być na dole (ten drugi). Więc albo za pomocą align-self cofniemy pierwszy do góry (align-self nadpisuje align-content, które działa na osi pobocznej, która dla rzędów jest góra/dół):
.dice {
(...)
display: flex;
justify-content: space-between;
align-items: flex-end;
padding: 30px;
}
.dot {
width: 40px;
height: 40px;
(...)
}
.dot:nth-of-type(1) {
align-self: flex-start;
}
Albo skorzystamy z domyślnego align-items, którym jest stretch, który tutaj nie rozciąga elementów, bo mają one określoną wysokość i szerokość, więc siedzą u góry i ten drugi można w dół opuścić:
.dice {
(...)
display: flex;
justify-content: space-between;
/* align-items: domyślny */
padding: 30px;
}
.dot {
width: 40px;
height: 40px;
background-color: black;
border-radius: 25%;
}
/* .dot:nth-of-type(1) {
align-self: flex-start;
} */
.dot:nth-of-type(2) {
align-self: flex-end;
}
Kostka 3 – bawimy się dalej z align-self
Robimy jeden rząd po 3 doty pod kostkę 3:
<div class="dice">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
Podstawowe style:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.dice {
width: 400px;
height: 400px;
border: 1px solid black;
border-radius: 25%;
background-color: thistle;
}
.dot {
width: 40px;
height: 40px;
background-color: black;
border-radius: 25%;
}
Tworzymy flex-rodzica będącego rzędem z kostki:
.dice {
(...)
display: flex;
justify-content: space-between;
padding: 30px;
}
Jako że mamy do czynienia z rzędem, oś główna idzie lewo/prawo. Justify content pracuje na osi głównej odpychając lewo-prawo kropki od siebie.
Oś poboczna to w przypadku rzędu góra/dół i tam chcemy mieć nasze kropki w centrum:
.dice {
(...)
display: flex;
justify-content: space-between;
align-items: center;
padding: 30px;
}
Skoro kostka jest rzędem, to oś poboczna idzie góra/dół zaś align-items na osi pobocznej kropki centruje. Na osi głównej dla rzędu czyli lewo/prawo są od siebie odepchnięte.
Teraz kropka pierwsza musi być w lewym, górnym rogu, zatem:
.dot:nth-of-type(1) {
align-self: flex-start;
}
Rząd – oś główna lewo/prawo, poboczna góra/dół. Align-items – ustawianie na osi pobocznej. Align-self – nadpisywanie align-items. Ustawiamy element idealnie na początku osi pobocznej czyli na górze.
Teraz ostatni element przenosimy na koniec osi pobocznej czyli na dół w przypadku rzędu:
.dot:nth-of-type(3) {
align-self: flex-end;
}
Ace of spades – podsumowanie ćwiczeń
Tworzymy naszego asa pik:
<div class="card">
<div class="top-left">
<span>A</span>
<span>♠</span>
</div>
<div class="middle">
<span>♠</span>
</div>
<div class="bottom-right">
<span>A</span>
<span>♠</span>
</div>
</div>
Podstawowe style:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.card {
width: 400px;
height: 800px;
background-color: aliceblue;
}
Ustawiamy display-flex, które będzie robiło nam rząd:
.card {
(...)
display: flex;
}
Skoro rząd, to oś główna idzie lewo/prawo. Skoro tak, to justify-content działa na osi lewo/prawo. Skoro tak, odpychamy na osi lewo prawo elementy od siebie:
.card {
(...)
display: flex;
justify-content: space-between;
}
Skoro rząd, to oś poboczna idzie góra/dół. Skoro tak, align-items działa na osi pobocznej. Skoro tak, ustawiamy elementy w centrum osi góra/dół:
.card {
(...)
display: flex;
justify-content: space-between;
align-items: center;
}
Teraz na osi góra/dół pierwsze dziecko (top-left) cofamy na górę, zaś ostatnie (bottom-right) opuszczamy na dół:
.top-left {
align-self: flex-start;
}
.bottom-right {
align-self: flex-end;
}
Robimy z nich flex-kolumny dla spanów, aby pik znajdował się pod asem:
.top-left {
align-self: flex-start;
display: flex;
flex-direction: column;
}
.bottom-right {
align-self: flex-end;
display: flex;
flex-direction: column;
}
Ujdzie, w końcu ćwiczymy pozycjonowanie. Teraz rotujemy bottom-right, aby wyglądało jak w rzeczywistości:
.bottom-right {
align-self: flex-end;
display: flex;
flex-direction: column;
transform: rotate(180deg);
}
Normalnie używalibyśmy ikon nie znaków unicode, ale ćwiczymy pozycjonowanie, nie wygląd, więc to nie taki problem.