CSS Flexbox
Ovde ćemo objasniti Flexbox (tačnije CSS flexible box layout module), CSS tehnologiju za raspoređivanje elemenata (layout) na web strani. Iako se i dalje posmatra kao "novotarija", flexbox je već odavno uveden u web čitače. Kako joj ime kaže, ova tehnika je osmišljena upravo kako bi se postigao fleksibilan raspored, koji neće "pući" pri različitim rezolucijama ekrana ili prikazom na mobilnom uređaju.
Pogledajte samo sa koliko CSS atributa raspolažemo kako bismo doterali izgled Flexboxa:
Flex-kontejner | |
---|---|
display | Definisanje flex kontejnera - da bi neki objekat postao flex kontejner, zadajemo mu vrednost flex ili inline-flex. |
flex-direction | Osnovni pravac - da li se flex-elementi ređaju horizontalno (row) ili vertikalno (column). |
flex-wrap | Raspored u više linija - da li se flex-elementi koji prevazilaze dimenzije flex-kontejnera prebacuju u novi red/kolonu. |
flex-flow | Kompleksan atribut koji pokriva vrednosti flex-direction i flex-wrap atributa. |
justify-content | Poravnanje flex-elemenata po osnovnom pravcu |
align-content | Poravnanje linija po ukrštenom pravcu |
align-items | Poravnanje flex-elemenata unutar linije, po ukrštenom pravcu |
Flex-elementi | |
order | Redosled flex-elemenata |
flex-basis | Inicijalana veličina elementa |
flex-grow | Proporcija koja definiše koliko se flex-element može povećati u odnosu na ostale elemente |
flex-shrink | Proporcija koja definiše koliko se flex-element može smanjiti u odnosu na ostale elemente |
flex | Kompleksan atribut koji zamenjuje flex-grow, flex-shrink i flex-basis atribute |
align-self | Poravnanje pojedinog flex-elementa unutar linije, po ukrštenom pravcu |
Naravno, sa tim mogućnostima dolazi i malo komplikovanija postavka, pošto pored samih flex-elemenata koji se ređaju, obavezno mora postojati i tzv. flex-kontejner unutar koga se ti elemeti raspoređuju.
U ovom tekstu ćemo se baviti flexbox modelom i njegovim upotrebama. Atributi koji se odnose na flex-kontejner i flex-elemente, obrađeni su u posebnim tekstovima. Međutim, pre nego što krenemo na proučavanje samih atributa, moramo da se upoznamo sa nekim osnovnim pojmovima.
Osnovni pravac (main axis) je pravac ređanja elemenata. Ovaj pravac zadajemo u flex-kontejneru i to u smislu da li će se elementi ređati po redovima ili kolonama. Osnovni pravac po redovima predstavlja horizontalno ređanje elemenata (jedan za drugim), a po kolonama - vertikalno (jedan ispod drugog).
Ukršteni pravac (cross axis) je pravac koji je pod pravim uglom u odnosu na osnovni pravac (iako bismo voleli, nekako nam ne "ide" da ga nazovemo "kontra-pravac"). Drugim rečima, ako je zadato da se elementi ređaju horizontalno (po redovima), ukršteni pravac je vertikalan (onako kako idu sami redovi - u koloni) i obrnuto.
Elementima može biti zadat i raspored u više linija (wrap). To znači da ako je osnovni pravac horizontalan, elementi će biti raspoređeni jedan za drugim u redu, a ako treba, i u više horizontalnih redova, koji onda idu jedan ispod drugog. Isto važi i ako zadamo vertikalni osnovni pravac, možemo imati više kolona, jednu pored druge. Dakle, linije se smeštaju jedna za drugom po ukrštenom pravcu.
U ovom tekstu demonstriramo nekoliko zanimljivih upotreba flexboxa. Naš savet je da pogledate primere kako biste stekli neki pojam o tome čemu služi i za šta može da se upotrebi Flexbox, onda da savladate lekcije o flex-kontejneru i flex-elementima, pa da se na kraju opet vratite na ove primere kako biste proučili kako zaista funkcionišu.
Vertikalno centriranje
Među web dizajnerima je dugo kružila šala kako je najteži problem u CSS-u - postavljanje nekog elementa na sredinu, po vertikali. I zaista, obično, horizontalno centriranje je relativno jednostavno. Inline elementi se centriraju atributom text-align:center, dok se blokovi centriraju zadavanjem vrednosti auto za levu i desnu marginu.
Međutim, vertikalno centriranje je sasvim druga priča. Problem nastaje zbog toga što se sadržaj uobičajeno "kreće" po vertikali, tj. odozgo-naniže. Primetite kako izgleda prosečna web stranica - tekst je ograničen sa leve i desne strane, a sav "višak" sadržaja, "probija" nadole. Tako, kad skrolujemo stranicu, nikada ne skrolujemo udesno (osim u retkim slučajevima dizajnerske anti-kreativnosti), već naniže. Zbog toga je i mnogo teže postaviti neki elemenat u centar po vertikali.
Bilo je više načina koje su web dizajneri koristili, ali ni jedan nije bio jednostavan. Često je moralo da se umeša i JavaScript programiranje kako bi se izračunale trenutne visine elemenata i pozicija centriranog elementa, a sa promenom veličine prozora bi sve moralo da se računa ponovo. Malo inteligentniji način bi bio pomoću čistog CSS-a, ali uz pomoć 2D transformacija.
Srećom, sa pojavom Flexboxa, rešenje ovog problema postaje trivijalno!
Primer za vertikalno centriranje
Pomoću transformacija
<style>
.kont {
height: 70vh;
background-color: #999;
color: #fff;
position: relative;
}
.element {
background-color: #449;
padding: 1em;
border: 2px solid #000;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
</style>
<div class="kont">
<div class="element">Ovo je elemenat koji je <br>centriran po vertikali</div>
</div>
Dakle element je pozicioniran tako da mu gornji-levi ugao bude u centru (top:50% i left:50%), a onda je "povučen unazad" za po polovinu svoje širine i visine pomoću translate(-50%,-50%). Ovo funkcioniše zato što su vrednosti za top i left relativne u odnosu na kontejnerski blok, dok su veličine zadate u 2D transformaciji relativne u odnosu na sam unutrašnji element na koji se primenjuje.
Pomoću Flexboxa
<style>
.kont {
height: 70vh;
background-color: #999;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.element {
background-color: #449;
padding: 1em;
border: 2px solid #000;
}
</style>
<div class="kont">
<div class="element">Ovo je elemenat koji je <br>centriran po vertikali</div>
</div>
Kao što vidite, sva mudrost je u kontejneru. Prosto je zadato da se element centrira po horizontali (justify-content:center) i po vertikali, unutar svoje linije (align-items:center), pošto je sama linija po defaultu "razvučena" od vrha do dna.
Sami odlučite šta vam se više dopada. Mi smo naklonjeniji flexbox rešenju, pošto njime možemo lako smestiti i više elemenata jedan do drugog, takođe centrirano, dok bi takav problem za transformacije zahtavao malo više akrobatike sa kontejnerom i podkontejnerom.
Ravnomerna distribucija elemenata
Ovaj izazov u stvari predstavlja problem poravnanja po obe vertikalne ivice (justify), što je sa tekstom lako izvodljivo, ali kada imamo HTML elemente, onda prestaje da bude tako jednostavno.
Najčešći slučaj kada želimo da se elementi lepo "smeste" na stranicu ili neki kontejnerski blok je kada imamo formu sa mnoštvom polja za unos podataka sa tekstualnim natpisima ispred svakog polja. Obično smo takvu situaciju rešavali tabelom (najjednostavnije ako je svaki "red" forme zasebna tabela sa jednim redom i poljima). U tom slučaju bismo ograničavali širinu ćelija sa tekstom, a ćelije sa poljima puštali da se "rašire", s tim što bi sama polja bila podešena da zauzmu 100% nadređene ćelije.
Srećom, Flexbox nam i ovde priskače u pomoć i omogućava da kreiramo mnogo "čistiji" HTML - bez korišćenja tabela u svrhu raspoređivanja elemenata što je generalno pogrešna upotreba istih. Ovde prosto pustimo elemente u flex-kontejner i poljima zadamo faktor "širenja", što će im omogućiti da se rašire koliko mogu.
Primer za ravnomernu distribuciju elemenata
<style>
.kont {
margin-bottom: 0.5em;
display: flex;
}
input, select {
flex-grow: 1;
}
.kont div {
margin: 0 0.5em 0 1em;
}
.kont div:first-child {
margin-left: 0;
}
</style>
<div class="kont">
<div>Ime</div> <input type="text" />
<div>Ime roditelja</div> <input type="text" />
<div>Prezime</div> <input type="text" />
</div>
<div class="kont">
<div>Godina</div>
<select>
<option value="1">I godina</option>
<option value="2">II godina</option>
<option value="3">III godina</option>
</select>
<div>Telefon fiksni</div> <input type="text" />
<div>Telefon mobilni</div> <input type="text" />
</div>
<div class="kont">
<div>Komentar</div> <input type="text" class="long" />
</div>
I ovde je svaki "red" zaseban flex-kontejner. Ali pogledajte koliko je sada jednostavnije - prosto u svaki kontejner "natrpamo" tekstualne labele i polja, s tim što smo poljima zadali atribut flex-grow:1 - što znači da će se širiti dok se ne zauzme svo slobodno mesto. Na taj način, cela forma izgleda lepo i uredno. Ispada da se više brinemo oko podešavanja margina flex-elemenata, kako bi bili lepo razdvojeni.
Naravno, sve može dodatno da se komplikuje - npr. imali bismo još posla ako bismo hteli da rešimo problem "pristojnog" prelaska u sledeći red ako se cela forma jako suzi. Razmislite kako biste rešili da tekstovi uvek zajedno prelaze sa svojim poljima.
Ravnomerna distribucija po vertikali
Ovde smo odlučili da vam pokažemo i kako bi moglo da se postigne ravnomerno raspoređivanje elemenata, ne samo po horizontali, već i po vertikali, tako da ceo prostor bude popunjen elementima koji će biti ravnomerno "razvučeni", imali dovoljno sadržaja ili ne.
Takođe, ovde možete videti da ne postoji prepreka da smestite flexbox unutar flexboxa. Kontejneri imaju različit broj elemenata, a ipak, zahvaljujući magiji flexboxa, sve se savršeno uklapa.
Primer ravnomerne distribucije elemenata po vertikali
<style>
.main {
display: flex;
margin-bottom: 0.5em;
font-size: 9pt;
}
.prvi, .drugi {
flex: 50%;
display: flex;
flex-wrap: wrap;
background-color: #ccc;
margin-bottom: 0.5em;
}
.drugi {
background-color: #ace;
}
.item {
flex: 50px;
/* flex: 1; */
/* flex: auto; */
margin: 0.5em;
padding: 0.5em;
border: 2px solid #000;
background-color: #fff;
}
.drugi .item {
background-color: #cdf;
}
</style>
<div class="main">
<div class="prvi">
<div class="item"> I want to break free </div>
<div class="item"> "Is this the real life? Is this just fantasy?
Caught in a landslide, no escape from reality..." </div>
<div class="item"> We are the champions </div>
<div class="item"> The show must go on </div>
<div class="item"> Too much love will kill you </div>
<div class="item"> You don't fool me </div>
<div class="item"> Living on my own </div>
</div>
<div class="drugi">
<div class="item"> The great pretender </div>
<div class="item"> Princes of the universe </div>
<div class="item"> Barcelona </div>
<div class="item"> Another one bites the dust </div>
<div class="item"> Flash </div>
<div class="item"> "Pressure, pushing down on me, pressing down on you..." </div>
<div class="item"> One vision </div>
<div class="item"> Hammer to fall </div>
<div class="item"> I want it all </div>
<div class="item"> We will rock you </div>
<div class="item"> Innuendo </div>
<div class="item"> Friends will be friends </div>
<div class="item"> Who wants to live forever </div>
<div class="item"> A kind of magic </div>
</div>
</div>
Imamo jedan glavni kontejner (klase main) unutar koga se nalaze još dva kontejenra jedan do drugog (prvi i drugi). Flex elementi se inače po defaultu "šire" po ukrštenom pravcu - ovde konkretno, da zauzmu celu vertikalu. Samim tim je praktično samo od sebe obezbeđeno da se svi elementi lepo uklope. Savki element ima zadatu osnovnu širinu od 50px (flex:50px), a korišćenje tog atributa je obezbedilo i da se automatski uključi grow faktor, zahvaljujući kome se elementi šire dok ne zauzmu ceo prostor u svom redu.
Tek ćete naučiti koliko je atribut flex moćan. Sličan, a opet malo drugačiji raspored elemenata bi se postigao drugačijim vrednostima ovog atributa, kao npr. flex:1 ili flex:auto.
Bilo bi pošteno da navedemo i neke nedostatke flexboxa. Najpre, nemoguće je zadati "nasilan" prelazak u novu liniju. Drugim rečima nešto kao break, tj. prelom linije ne postoji. Ako želimo da postignemo takav efekat, moramo da manipulišemo veličinom elementa kako bismo isforsirali prelazak u novu liniju.
Druga stvar bi bila nemogućnost da željene elemente raširimo preko više linija. Dakle neki pandan "drop cap" formatiranju ili rowspan parametru kod ćelija tabele - ne postoji. Ovde bismo morali da se snalazimo sa više flex-kontejnera.
Iako postoje i neki nedostaci, odnosno layouti koje ne možemo tek-tako jednostavno da postignemo, smatarmo da flexbox i te kako ima upotrebnu vrednost.
Ako su vam se primeri dopali, vreme je da navalite na ostale dve lekcije. Videćete, Flexbox je moćno oružje u rukama svakog web dizajnera, iako je cela tehnologija u stvari jako jednostavna!
- W3C, CSS Flexible Box Layout Module Level 1
- CSS Tricks, A Complete Guide to Flexbox
- Mozilla Developer Network, CSS Flexible Box Layout
- Can I Use, CSS Flexible Box Layout Module