Adaptive design med flexbox (CSS)




Hvad går det ud på?

En af de metoder man kan anvende til adaptive design er det der hedder flexbox. Det er en feature der er kommet med CSS3 og som har store anvendelsesmuligheder. I al sin enkelthed går flexbox ud på, at man deler sine elementer op i bokse, som flyder rundt på brugerfladen afhængig af bredden af viewporten (i praksis er det det samme som skærmbredden for de fleste brugere). Det betyder, at man kan lave et design hvor siden f.eks. har tre søjler, af en given bredde, hvis viewporten er bred nok, men kun to eller en, hvis viewporten er for smal til at vise indholdet i tre søjler.

Flexbox anvendes på dele af sider, der skal være fleksible. Har man brug for at lave noget overordnet med header, footer og en sidebar, skal man over i det der hedder grid (kommer på et tidspunkt).

Der hvor flexboxen især bliver interessant og anvendelige, er at man kan styre hvordan flowet af elementer skal være, og hvordan de enkelte elementer skal aligne i flexboxen. Det kommer til at give mere mening, når vi ser på eksemplerne neden under.


Container og items

Flexboxen er bygget op om container og items. Items er de elementer der skal flyde rundt, og containeren er kassen som items skal flyde rundt i. Det ser med andre ord således ud:

Containeren



Containeren skal være en tag der kan indeholde andre elementer, så der er nogle begrænsninger på hvad man kan anvende her. I praksis vil det antageligt mest være en DIV der fungerer. Items kan være stort set hvad som helst. Der er heller ikke noget til hinder for, at et item er en container i sig selv, med sine items.

Måden hvorpå man specificerer at det er en flexbox, er display:flex i STYLE. Har man brug for at containeren er et inline object, bruger man display:inline-flex. Her gør vi det med en klasse, som vi kalder FlexContainer:

.FlexContainer {
display:flex;
}



Rækkefølge og flowretning på items

Det første man skal specificere, når man har containeren med items er, om items skal være på en vandret linje eller stakket i en søjle. Dette gøres med variablen flex-direction. Her har man flg. muligheder:

VærdiEffekt
rowArrangeret i en vandret linje fra venstre mod højre (default)
row-reverseArrangeret i en vandret linje fra højre mod venstre
columnArrangeret i en søjle fra top mod bund
column-reverseArrangeret i en søjle fra bund mod top


flex-direction: row


flex-direction: row-reverse


flex-direction: column




flex-direction: column-reverse




Lige nu er strukturen fikseret i den ene række eller søjle, dvs. hvis det fylder mere end bredden på viewporten, kommer der en vandret scrollbar (med mindre man har specificeret at den ikke skal dukke op) og fylder det mindre, har man noget tom plads. Det kan man gøre fleksibelt, således at items der ikke er plads til på linjen flyttes ned på den næste, eller hvis der er plads til flere kolonner, arrangeres items i flere kolonner. Dette er parameteren flex-wrap.

Hvis det er lidt svært at visualisere, så prøv at ændre bredde (og højde) på containeren neden under, ved at trække i det nederste højre hjørne. Dette er effekten man ser ved flex-wrap på en row.



Til parameteren flex-wrap har man flg. muligheder:

VariabelEffekt
nowrapArrangeret i én linje/søjle (default)
wrapArrangeret i flere linjer/søjler, afhængig af pladsen. Vandret linje: fra venstre mod højre. Søjle: fra top mod bund.
wrap-reverseArrangeret i flere linjer/søjler, afhængig af pladsen. Vandret linje: fra højre mod venstre. Søjle: fra bund mod top.


Der findes en parameter der hedder flex-flow, som er en kombination af flex-direction og flex-wrap, dvs. man kan bruge variablerne fra disse parametre adskilt med mellemrum. Default er "flex-flow: row nowrap". Hvis man ikke er vandt til at arbejde med flexbox, er det ligesom alle andre kombinationsparametre noget jeg anbefaler at man holder sig fra at bruge. Koden fylder mindre, men det er på bekostning af overblik, hvis man er utrænet.

Når man har fået styr på hvordan items arrangeres i rækker eller søjler i containeren, kan man begynde at arbejde med udslutningen.


Vandret udslutning på items

Hvis vi starter med den sideværs udslutning, så styres dette med parameteren justify-content, som specificeres for containeren. Til dette har man flg. muligheder:

justify-content: flex-start
Alignment mod containerens venstre side.

justify-content: flex-end
Alignment mod containerens højre side.

justify-content: center
Centreret i forhold til containerens bredde, uden at ændre den indbyrdes afstand mellem items.

justify-content: space-between
Fordeling med samme afstand mellem items i hele containerens bredde.

justify-content: space-around
Fordeling med samme afstand mellem items og containerens højre og venstre side, i hele containerens bredde.



Lodret udslutning på items

Lodret udslutning styres med parameteren align-items, som specificeres for containeren. Til dette har man flg. muligheder:

align-items: flex-start
1

2


3

4


Alignment mod containerens top.

align-items: flex-end
1

2


3

4


Alignment mod containerens bund.

align-items: center
1

2


3

4


Lodret centrering i forhold til items højde.

align-items: stretch
1

2


3

4


Højden på item strækkes til containerens højde. Vær opmærksom på, at hvis man har specificeret en højde på sit item, fungerer stretch ikke, da parameteren height til en hver tid overtrumfer tilpasninger med stretch.

align-items: baseline
1

2


3

4


Indholdet i item arrangeres på linje efter første linjes basislinje. Den samlede gruppe af items alignes mod containerens top.



Udslutning når der er flere linjer med items

Når der er flere linjer i containeren, f.eks. når items omarrangeres pga. forskellig størrelse viewport, kan man også specificere udslutningen på hele containeren. Til dette har man flg. muligheder:

align-content:flex-start
1
2
3
4
5
6
7
8
Alignment mod containerens top. Bemærk at hvis ét item er højere end de andre, tilpasses højden på alle items på linjen der indeholder det pågældende item. Containeren er gjort fleksibel (træk i nederste højre hjørne), så man kan se hvordan størrelser og placeringer ændrer sig når containeren ændrer størrelse.

align-content:flex-end
1
2
3
4
5
6
7
8
Alignment mod containerens bund. Bemærk at hvis ét item er højere end de andre, tilpasses højden på alle items på linjen der indeholder det pågældende item. Containeren er gjort fleksibel (træk i nederste højre hjørne), så man kan se hvordan størrelser og placeringer ændrer sig når containeren ændrer størrelse.

align-content:center
1
2
3
4
5
6
7
8
Alignment mod containerens midte. Bemærk at hvis ét item er højere end de andre, tilpasses højden på alle items på linjen der indeholder det pågældende item. Containeren er gjort fleksibel (træk i nederste højre hjørne), så man kan se hvordan størrelser og placeringer ændrer sig når containeren ændrer størrelse.

align-content:stretch
1
2
3
4
5
6
7
8
Højden på items strækkes, så linjerne får samme højde og den samlede højde på linjerne svarer til containerens indre højde. Containeren er gjort fleksibel (træk i nederste højre hjørne), så man kan se hvordan størrelser og placeringer ændrer sig når containeren ændrer størrelse.

align-content:space-between
1
2
3
4
5
6
7
8
Afstanden mellem linjerne med items bliver tilpasset, så linjerne fylder hele containeren. Højden på items strækkes, så items på samme linje får samme højde. Containeren er gjort fleksibel (træk i nederste højre hjørne), så man kan se hvordan størrelser og placeringer ændrer sig når containeren ændrer størrelse.

align-content:space-around
1
2
3
4
5
6
7
8
Afstanden mellem linjerne med items og afstandene til containerens top og bund bliver tilpasset, så linjerne fylder hele containeren. Højden på items strækkes, så items på samme linje får samme højde. Containeren er gjort fleksibel (træk i nederste højre hjørne), så man kan se hvordan størrelser og placeringer ændrer sig når containeren ændrer størrelse.



Hvis man har brug for at et eller flere specifikke items bruger en anden alignment end det ser specificeres med align-content, hedder det sig, at man også kan dette. I praksis fungerer det ikke som det skal, men lad os se på hvad variablen kan præstere. Effekten laves med variablen align-self, som lægges på det pågældende items style.

Hvis vi tager eksemplet med align-content:flex-start fra før, og for item 5 sætter align-self:flex-end, kommer det til at se således ud:

1
2
3
4
5
6
7
8

Item 5 skulle have været nede ved containerens bund, men i stedet får det sin oprindelige højde i stedet for at blive strukket til samme højde som item 4, og alignment er bunden af linjen som item er på.


Nummerering af items

De items man har i containeren vises som default i den række de er skrevet i koden, men det behøver ikke at være tilfældet. Man har til sin style parameteren order som bruges til at sætte rækkefølgen af items i en given container. Order er et heltal, defaultværdien er 0, flere items må gerne have samme nummer, og man må også anvende negative værdier.

Hvis vi ser på disse items:

1
2
3
4
5
6

Så kan vi prøve at give hver især et andet order-nummer (skrevet i parantes efter item-nummeret), og rækkefølgen kommer nu til at se således ud:

1(2)
2(1)
3(-3)
4(5)
5(20)
6(1-)



Fleksibel bredde af items

Hvis man vil give sine items fleksibel bredde, kan man gøre dette med variablen flex-grow. Default-værdien er 0, hvorved item beholder en given bredde, men ved at give det andre værdier, kan man styre de relative bredder. Her skal man være opmærksom på, at bredden påvirkes af en række faktorer, så items der burde få samme størrelse, gør det ikke nødvendigvis.

Hvis vi ser på disse tre items, med to forskellige størrelser:

1
2
3

Så kan vi sætte flex-grow til 1 for alle tre items, hvorved alle tre items sættes til at skulle udfylde hele containerens bredde og have samme bredde. Det kommer til at se således ud:

1
2
3

Hvis man ser godt efter, er item 2 en lille smule større end 1 og 3, men de er næsten samme størrelse.

Hvis det ene item er så bredt, at det skulle gøre smallere, for at alle tre items blev lige store, beholder dette item sin bredde, og den resterende plads til at gøre bredere fordeles på de andre items. Her er item 2 gjort for bredt. Så ser det således ud:

1
2
3

Ved at give de forskellige items forskellige værdier, kan man styre de relative størrelser for items. Her er item 2 sat til flex-grow:2, mens de to andre bibeholder deres flex-grow:1:

1
2
3

Det påstås, at ved at ved flex-grow:2 skulle item blive dobbelt så stort som det eller de items der har flex-grow:1, forudsat der er plads. Af samme grund som at de tre items ikke fik hel samme størrelse i eksemplet længere oppe, bliver størrelsesforholdene i praksis heller ikke helt 1:2, som de skulle.

Man kan ikke have negative tal ved flex-grow. Skal man gøre items smallere, bruger man angivelig flex-shrink i stedet. I praksis, gør man ikke, da parameteren ikke fungerer, men for lige at demonstrere variablen:

Dette er de tre items, hvor item 2 er for bredt til at kunne danne tre lige brede items med flex-grow:

1
2
3

Hvis nu nu i stedet laver flex-grow:1 på item 2 om til flex-shrink:1, kommer det til at se således ud:

1
2
3

Item 2 er blevet smallere, som det skulle. Uheldigvis ændrer item 2 ikke bredde uanset hvilken værdi man sætter på flex-shrink, så man kan ikke på nogen måde styre bredden.


Endnu en parameter som angiveligt skulle fungere, men ikke fungerer ret godt i praksis er flex-basis. Med denne parameter, kan man angive en default størrelse på et item, udfra hvilken at størrelsen på de andre items beregnes. De absolutte størrelser (px, cm, osv.) fungerer fint, men her kan man lige så godt bruge width. De relative størrelser (procenter) og auto fungerer ikke ordentligt, og der er ikke fordele ved denne parameter i forhold til blot at bruge width.


I stedet for at bruge flex-grow, flex-shrink og flex-basis, kan man bruge en samlet variabel der hedder flex. Syntaksen er "flex: flex-grow flex-shrink flex-basis" hvor default er "flex: 0 1 auto". Fordi flex-shrink og flex-basis fungerer så dårligt som de gør, er den generelle anbefaling herfra, at man ikke anvender denne variabel.