O formato da água é algo que varia conforme o recipiente, a água se adapta à garrafa, jarra, copo, etc., da mesma forma, o layout do FlexBox se adapta à tela do dispositivo. Ou seja: O formato do FlexBox se adapta dependendo do container.
O Flexible Box Module trabalha com uma caixa com um tamanho base, mas não exatamente definido. Dentro dessa caixa podemos tem vários itens, e caso usemos coisas como display: block e display: inline-block, pode ser que os itens de dentro não se adaptem caso o container de fora seja redimensionado. Se usarmos o display: flex no container de fora e flex: auto nos itens de dentro, poderemos adaptar os itens de forma melhor pra dispositivos diferentes. O elemento pai é o container (o de fora, que recebe o display: flex) e os elementos filhos são os itens.
Vamos exemplificar com essas divs:
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
<div class="item">G</div>
</div>
Com esse CSS:
div.container {
background-color: lightsalmon;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
}
Colocando display: flex no container, ele já tentará se adaptar:
div.container {
background-color: lightsalmon;
display: flex;
}
E ao colocar flex: auto nos itens, eles já ficarão mais adaptáveis, podendo redimensionar o navegador:
div.item {
background-color: lightskyblue;
border: 1px solid black;
flex: auto;
}
No caso acima, ele ocupa o máximo de espaço disponível, ao diminuir e aumentar o navegador, ele vai se adaptando.
A configuração padrão de direção é row
(deitado, em linha, da esquerda pra direita). Podemos definir isso explicitamente com flex-direction: row, isso é o padrão do idioma português, inglês, espanhol e outros mais comuns. Para sentido contrário de leitura (como no idioma árabe), colocaremos flex-direction: row-reverse. Podemos também configurar verticalmente com flex-direction: column, lido de cima pra baixo (o padrão), pra reverter usamos flex-direction: column-reverse.
Ao definir ambos teremos a definição dos eixos (axis), e o eixo principal é o main-axis
, começando da esquerda pra direita, e o eixo transversal é o cross-axis
, de cima pra baixo, ambos com começo (start) e fim (end). Isso na configuração padrão (row), em outras configurações isso muda, como visto abaixo:
Deixe o CSS assim:
div.container {
background-color: lightsalmon;
display: flex;
flex-direction: row;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
text-align: center;
padding: 10px;
}
Experimente mudar o flex-direction para row-reserve, column e column-reverse.
A propriedade flex-wrap vai configurar o comportamento da cápsula
(o container, que é o pai). Com a opção nowrap ele não quebra os itens ao diminuir o container a um tamanho menor que o limite, ele vai os encolher (o nowrap
é o padrão). Lembrando que o tamanho mínimo do bloco de item é o tamanho do conteúdo, portanto, não tem como diminuir mais do que o bloco permite. Ao colocar flex-wrap: wrap ele vai quebrar o item pra baixo (ou melhor, no sentido do cross-axis). Se colocarmos flex-wrap: wrap-reverse, ele vai pra cima (ou melhor, pro sentido inverso ao cross-axis).
Deixe o HTML assim:
<div class="container">
<div class="item">Exemplo de bloco A</div>
<div class="item">Exemplo de bloco B</div>
<div class="item">Exemplo de bloco C</div>
<div class="item">Exemplo de bloco D</div>
<div class="item">Exemplo de bloco E</div>
<div class="item">Exemplo de bloco F</div>
<div class="item">Exemplo de bloco G</div>
</div>
E o CSS assim:
div.container {
background-color: lightsalmon;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
text-align: center;
padding: 10px;
}
Altere o flex-wrap assim, e ele quebrará os itens:
flex-wrap: wrap;
E de forma reversa:
flex-wrap: wrap-reverse;
Faça assim:
flex-direction: row-reverse;
flex-wrap: wrap;
E assim:
flex-direction: row-reverse;
flex-wrap: wrap-reverse;
Temos também a opção flex-flow, que junta numa mesma declaração, o flex-direction e o flex-wrap, dispensando o uso das duas últimas. Dessa forma aqui:
flex-flow: row nowrap;
Inclusive, é recomendado usar o flex-flow, pra simplificar aqui.
Lembrando que o flex: auto só funciona nos filhos (itens). Ele é pra não ter espaço em branco no elemento pai. Por exemplo:
div.container {
background-color: lightsalmon;
display: flex;
flex-flow: row nowrap;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
text-align: center;
padding: 10px;
flex: auto;
}
Pra ver um efeito interessante, coloque flex-flow: row wrap no código acima, deixando o restante sem alterações. Tente também com flex-flow: row wrap-reverse.
PS: Ao colocar algo como flex-flow: column wrap-reverse ele apenas vai empilhar, mas podemos fazer essa configuração, por exemplo:
div.container {
background-color: lightsalmon;
height: 150px;
display: flex;
flex-flow: column wrap;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
text-align: center;
padding: 10px;
flex: auto;
}
Como visto, o container (o pai) define o comportamento dos filhos, para alinhar os itens em relação ao main-axis (no row, seria da esquerda pra direita), do main-start ao main-end. Ao colocar justify-content: flex-start (que é o padrão), o primeiro item ficará grudado no main-start (no caso do row, à esquerda) e o espaço em branco fica no final. Ao colocar flex-end, ele ficará grudado no main-end (no caso do row, à direita), e o espaço em branco fica antes dos itens. Temos também a propriedade center pra centralizar os itens e o espaço fica dividido entre o main-start e o main-end.
Além disso, temos o space-between que coloca o primeiro item grudado no main-start, o último item grudado no main-end, e os outros terão espaço distribuídos entre eles. Para distribuir espaço entre todos os itens incluindo o primeiro e o último (de forma que não fiquem grudados no main-start e main-end) usamos o space-evenly. Já o space-around pega o espaço do container, divide pela quantidade de itens, e distribui o espaço igualmente pra cada um deles (atenção que entre os itens, tem o espaço do final de um item grudado com o espaço do começo de outro. Veja como ficam cada um deles:
Lembrando que ao mudar o direction (como o column nowrap), o main-axis tem outra posição (no caso seria de cima pra baixo) e o espaço. Veja abaixo:
A mesma regra segue com row-reverse e column-reverse.
Deixe o HTML novamente assim:
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
<div class="item">G</div>
</div>
E o CSS assim:
div.container {
background-color: lightsalmon;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
text-align: center;
padding: 10px;
}
Depois mude a propriedade pro flex-end, assim:
justify-content: flex-end;
PS: Isso não é a mesma coisa que pôr row-reverse no flex-flow. O flex-end não reverte os itens.
Tente os valores center, space-between, space-evenly e space-around.
Também podemos fazer o alinhamento no cross-axis (no caso do row, é de cima pra baixo). Nesse caso usamos o align-items. Nesse caso, devemos aumentar o container de cima pra baixo (no caso do row). O valor padrão é o stretch, que estica os itens junto com o container, dessa forma aqui:
align-items: stretch;
As outras opções são flex-start, que gruda os itens no cross-start e deixa o espaço do outro lado. O flex-end gruda os itens no cross-end e deixa espaço do outro lado. O center centraliza os itens no meio.
Deixe o CSS assim, definindo o height do container e colocando o align-items:
div.container {
background-color: lightsalmon;
height: 300px;
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
align-items: stretch;
}
Tente mudar as opções para flex-start, flex-end e center.
Vamos fazer um exercício com um item apenas, mas podemos fazer com vários itens também. Nós centralizaremos perfeitamente o item, independente de como redimensionamos a página. Vamos usar a base dos eixos principal (main-axis) e transversal (cross-axis), nos quais usamos para posicionamentos o justify-content e o align-items, respectivamente, com o center em ambos.
Para exemplificar vamos limpar o nosso HTML e CSS totalmente, e vamos usar tags semânticas dessa vez (que é o recomendado). Deixe o HTML assim:
<main>
<section>
<h1>Tela de Login</h1>
</section>
</main>
Com esse CSS:
* {
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
body {
background-color: lightsalmon;
}
main {
background-color: lightgreen;
height: 90vh; /* 90vh ocupa 90% da tela */
width: 90vw; /* Aqui é vm mesmo */
}
section {
background-color: lightseagreen;
height: 200px;
width: 200px;
}
Para centralizarmos perfeitamente, vamos considerar que o main é o container principal e o section é o item. No CSS do main, apenas adicione isso:
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
Isso já alinhará o item, mesmo que nós só tenhamos mexido no CSS do container (main).
PS: Evite usar o body como o container (pai).
Caso deseje colocar a área do container preenchendo 100% da tela, deixe o CSS do main assim:
height: 100vh;
width: 100vw;
Relembrando, ao colocar flex-flow: row wrap, ele vai jogar os itens pro sentido do cross-end do cross-axis (no caso do row, pra baixo) caso o container fique menor do que o espaço dos itens. Mas caso ele aumente pro sentido do cross-end (pra baixo, no caso do row) ele ficará um espaço em branco. Para podermos definir o que fazer nesse espaço, usamos a propriedade align-content, que alinha os elementos no eixo transversal quando eles estão empacotados. Os valores aceitos nele são stretch (padrão, que estica), flex-start (que gruda os elementos no cross-start), flex-end (que gruda os elementos no cross-end), center (que centraliza com espaços iguais entre o cross-start e cross-end), space-between (que gruda os primeiros no cross-start, os últimos no cross-end e os espaços são divididos igualmente entre os items), space-evenly (com espaços iguais entre o cross-start e o cross-end) e space-around (que divide os espaços igualmente, e entre os itens tem um espaço de um e do outro).
Vamos voltar pro primeiro exercício, deixando o HTML assim:
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
<div class="item">G</div>
</div>
Com esse CSS:
div.container {
background-color: lightsalmon;
display: flex;
flex-flow: row wrap;
height: 400px;
align-items: stretch;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
padding: 40px;
text-align: center;
}
Por padrão, ele vai esticar, então coloque no container a propriedade align-items: flex-start, aí eles não esticarão e ficarão grudados
no cross-start (no caso, em cima). Mas ele continuará quebrando os itens pra baixo.
Deixe o CSS do container assim:
div.container {
background-color: lightsalmon;
display: flex;
flex-flow: row wrap;
height: 400px;
align-content: flex-start; /* Aqui é content */
}
Coloque mais uns itens no HTML, indo até o M
, pra formar três linhas ao quebrar. E deixe o align-content do container assim:
align-content: stretch;
Teste na mesma propriedade, todos as outras opções: flex-end, center, space-between, space-evenly e space-around.
PS: Lembre-se sempre que apenas o container é flex, o que está dentro dele não é flex.
Todo item em Flexbox (que está dentro de um container) tem como padrão o order como 0
(se tivermos 4 itens, todos eles terão a ordem 0). Caso queiramos mudar a ordem dos elementos, podemos modificar também. Isso é útil para, por exemplo, menus, que podem ter uma ordem diferente no PC e no celular.
No mesmo HTML com os itens de A a G, deixe o CSS assim:
div.container {
background-color: lightsalmon;
display: flex;
flex-flow: row wrap;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
padding: 20px;
text-align: center;
}
Em um dos itens, faça um estilo inline assim:
<div class="item" style="order: -3">D</div>
Ao fazer isso, o D acabará vindo primeiro.
Coloque isso em outro elemento:
<div class="item" style="order: 1">F</div>
Aí o F ficará por último, já que o D tem valor -3, o F tem valor 1 e todos os outros são 0, por padrão.
Deixe o HTML assim, com as IDs:
<div class="container">
<div class="item" id="i1">A</div>
<div class="item" id="i2">B</div>
<div class="item" id="i3">C</div>
<div class="item" id="i4">D</div>
<div class="item" id="i5">E</div>
<div class="item" id="i6">F</div>
<div class="item" id="i7">G</div>
<div class="item" id="i8">H</div>
<div class="item" id="i9">I</div>
</div>
E coloque o CSS assim, com todos os itens em ordem aleatória no order:
div#i1 {
order: 0;
}
div#i2 {
order: -2;
}
div#i3 {
order: 4;
}
div#i4 {
order: 8;
}
div#i5 {
order: 2;
}
div#i6 {
order: 0;
}
div#i7 {
order: -4;
}
div#i8 {
order: 5;
}
div#i9 {
order: -2;
}
No caso, o primeiro valor é o menor (no caso, -4), e o último é o maior (no caso, 8). Caso tenha mais de um valor igual (como o 0, que está em dois itens, ele vai colocar o primeiro com esse valor, e depois o segundo e assim por diante).
Temos a propriedade align-self que se aplica a cada um dos itens, os alinhando no sentido do cross-axis (pra baixo, no caso do row). O valor auto herdará a característica de alinhamento configurado no container (pai). O flex-start alinha perto do cross-start, e da mesma forma o flex-end alinha perto do cross-end. O center calcula o meio entre o cross-start e o cross-end. O stretch puxará
o item para que ele ocupe todo o espaço do eixo transversal. Isso só será visível ao aumentar o container, dessa forma:
Retire todos os orders do CSS, deixando só o bloco dos seletores da DIV, assim:
div.container {
background-color: lightsalmon;
display: flex;
flex-flow: row wrap;
align-items: flex-start;
height: 400px;
}
div.item {
background-color: lightskyblue;
border: 1px solid black;
padding: 20px;
text-align: center;
}
div#i1 {
}
div#i2 {
}
/* Segue igual até o div#i9 */
Da forma acima, todos ficarão como flex-start porque é o que foi definido no container, e ao deixar a opção align-self como auto, ele ficará dessa mesma forma porque é o container pai que manda.
O align-self é configurado para cada item individualmente:
div#i1 {
}
div#i2 {
align-self: auto; /* Pode ser inherit também, que herda */
}
div#i3 {
align-self: flex-end;
}
div#i4 {
}
div#i5 {
align-self: center;
}
div#i6 {
align-self: flex-start;
}
div#i7 {
align-self: stretch;
}
div#i8 {
}
div#i9 {
}
Agora tente mudar o align-items do container pra outro valor, por exemplo:
align-items: center;
Podemos também tirar a propriedade acima do container, aí ele assumirá o valor padrão (que é stretch).