Triângulo

Guia completo de Flexbox - display: flex;

por Hugo Bessa

O Flexbox é um dos módulos do CSS criados para facilitar a vida de quem precisa criar layouts na web. Com ele é possível controlar o tamanho, alinhamento e distribuição de um contêiner e seus elementos-filhos (chamados de itens). Esse conjunto de ferramentas torna o Flexbox extremamente capaz de resolver problemas de layout em uma dimensão.
Antes do Flexbox era bastante comum ouvir uma história de alguém que não conseguiu centralizar um elemento com CSS, já que as ferramentas de layout padrão (block e inline) não lidam muito bem com o alinhamento e distribuição de elementos. Outro problema bastante comum era não conseguir facilmente tornar o tamanho de um elemento flexível, já que a única forma de fazer isso era usando unidades em porcentagem e fazendo cálculos manuais com elas.
Este post de introdução vai te mostrar os principais conceitos por trás desse poderoso módulo do CSS e como utilizá-lo para estilizar seus projetos na web. Vamos começar criando um contêiner flex.

Criando um contêiner flex

Para criar um contêiner flex, você precisa apenas utilizar display: flex em um elemento.
.elemento {
  display: flex;
}
Ao aplicar a regra display: flex, o elemento se tornará um contêiner flex e seus elementos-filhos serão do tipo flex. Do lado de fora, um contêiner flex não é diferente de um outro elemento block, mas o comportamento de seus elementos-filhos é completamente modificado.
Dica: Isso pode ser explicado na especificação Display Module Level 3, que diz que a propriedade display especifica dois tipos de display: o externo e o interno. Usar display: flex é, então, a forma curta de display: block flex, que define o display do contêiner em si como block e de seus elementos-filhos como flex.

Alinhando elementos com Flexbox

A partir do momento que você tem um contêiner flex, seus elementos serão dispostos ao longo do eixo principal, formando uma linha. Usando a propriedade flex-direction, podemos trocar a direção do eixo principal com flex-direction: column, onde o elementos formarão uma coluna. O padrão para esta propriedade é flex-direction: row.
.container-row {
  display: flex;
  flex-direction: row; /* o eixo principal será uma linha */
}

.container-column {
  display: flex;
  flex-direction: column; /* o eixo principal será uma coluna */
}
Conteiner flex e seus
eixos
A propriedade flex-direction recebe também valores que inverterão a ordem de disposição dos elementos de um contêiner flex: row-reverse e column-reverse.
flex-direction com valores row, row-reversed, column e column-reversed
Para alinhar os elementos ao longo dos dois eixos, utilizamos três propriedades de alinhamento: justify-content, align-items e align-content.

justify-content

A propriedade justify-content define o alinhamento do conteúdo do contêiner flex ao longo de seu eixo principal. Cada um de seus possíveis valores afetará o alinhamento de todo o conteúdo, resolvendo o antigo problema de centralizar elementos ou distribuí-los de forma igual.
Seu valor padrão é flex-start, que define que o conteúdo será alinhado a partir do começo do eixo principal.
justify-content flex-start
O valor flex-end define que o conteúdo será alinhado a partir do final do eixo principal.
justify-content flex-end
Usando center, o conteúdo será alinhado ao centro do eixo principal.
justify-content center
Um outro valor bastante útil é o space-between, que alinha o conteúdo ao longo do eixo principal e adiciona um espaço padrão entre todos os elementos.
justify-content space-between
Já o space-around adiciona um espaço ao redor de todos os elementos.
justify-content space-around
Parecido com o space-around, o space-evenly adiciona um espaço ao redor de todos os elementos de forma igual, incluindo os das pontas.
justify-content space-evenly
Existem também outros valores para justify-content que não cobriremos neste artigo: start, end, left e right.

align-items

Para alinharmos elementos ao longo do eixo transversal de um contêiner flex, usamos a propriedade align-items. Os seus valores principais são: stretch, flex-start, flex-end, center, e baseline.
stretch é o valor padrão para align-items. Traduzindo para português, "stretch" significa "esticar". Então, por padrão, os elementos serão esticados para ocupar todo o espaço disponível no eixo transversal. Isso é muito útil quando queremos que todos os elementos tenham o mesmo tamanho quando o conteúdo interno deles é diferente.
align-items stretch
Com flex-start, todos os elementos do contêiner flex se alinharão a partir do início do eixo transversal.
align-items flex-start
Já o flex-end definirá que os elementos se alinhem a partir do final do eixo transversal.
align-items flex-end
Usando o valor center, todos os elementos serão alinhados a partir do centro do eixo transversal.
align-items center
O valor baseline distribuirá os elementos de certa forma que seus baselines se alinhem ao longo do eixo transversal.
align-items baseline
Neste artigo não cobriremos alguns dos outros valores possíveis para align-items como: start, self-start, end, self-end, e os modificadores safe e unsafe.

align-content

Ao invés de alinhar os elementos, é possível também alinhar todo o conteúdo de um contêiner flex no eixo transversal. A propriedade align-content é menos utilizada que a align-items, mas muito útil em situações em que o contêiner flex tem um tamanho pré-definido (100vh por exemplo) e não sabemos com antecedência o tamanho de todos os elementos-filhos.
O valor padrão para esta propriedade é normal, que funciona como se nenhum valor tivesse sido definido.
Com flex-start, o conteúdo será alinhado ao início do eixo transversal. Já flex-end alinhará o conteúdo do contêiner flex ao final. Usando center, o conteúdo será alinhado ao centro.
align-content flex-start, flex-end e center
Também podemos utilizar o valor space-between para adicionar espaçamento entre as linhas de conteúdo, space-around para espaçamento ao redor destas linhas e space-evenly para espaçamento igual ao redor das linhas de conteúdo incluindo as pontas.
align-content space-between, space-around e space-evenly
O valor stretch fará com que as linhas de conteúdo se estiquem para tomar todo o espaço disponível no eixo transversal.
align-content stretch
Neste artigo não cobriremos alguns dos outros valores possíveis para align-content como: start, end e os modificadores safe e unsafe.

align-self

Podemos também utilizar align-self em elementos flex para alterar seu alinhamento no eixo transversal de forma independente.
align-self
A propriedade align-self recebe os mesmos valores que align-items ou align-content.

Quebrando o conteúdo em novas linhas ou colunas

Por padrão, os elementos-filhos de um contêiner flex serão dispostos ao longo dos eixos, sem quebrarem em novas linhas e colunas. Para controlar este comportamento, podemos utilizar a propriedade flex-wrap.
O valor padrão para esta propriedade é nowrap, que define que os elementos serão dispostos em uma única linha.
wrap definirá que os elementos irão ocupar novas linhas, em direção ao fim do eixo transversal.
Já o valor wrap-reverse especifica que os elementos irão ocupar novas linhas em direção ao início do eixo transversal
flex-wrap

Definindo tamanhos flexíveis para os elementos flex

Além de ferramentas para distribuir e alinhar elementos-filhos em um contêiner flex, o Flexbox também tem propriedades para auxiliar na definição do tamanho de elementos. Assim como o nome deixa a entender, o forte dessas propriedades é poder escolher valores flexíveis. Com flex-grow, flex-shrink e flex-basis aplicados a um elemento-filho flex, podemos controlar o seu tamanho dentro um contêiner flex e como ele lida com a sobra ou falta de espaço.

flex-grow

A propriedade flex-grow recebe como valor um número que represente o "fator de crescimento". Esse número define como o elemento-filho reagirá à sobra de espaço em um contêiner flex. A sobra de espaço é calculada pelo o tamanho total do contêiner flex menos o espaço base total ocupado pelos elementos-filhos. Por padrão, o valor de flex-grow é 0.
Para entender um pouco melhor como essa propriedade funciona na prática, vamos utilizar um exemplo. Em um contêiner flex com 300px de tamanho, temos três elementos-filhos com 100px de tamanho. Os dois primeiros têm o valor de flex-grow: 1 e o terceiro tem o valor de flex-grow: 2. Nesse exemplo, teríamos uma sobra de espaço de 200px que seria distribuída entre os três elementos-filhos de acordo com os seus fatores, de forma que no final o espaço ocupado por eles seja igual ao tamanho do contêiner. Já que o terceiro elemento tem um fator de crescimento 2, e os dois primeiros têm um fator de crescimento 1, o terceiro elemento crescerá duas vezes mais do que os outros dois.
flex-grow

flex-shrink

Assim como podemos tornar flexível o crescimento dos elementos-filhos, podemos também utilizar flex-shrink para definir os seus fatores de encolhimento.
Quando faltar espaço em um contêiner flex, os seus elementos-filhos são encolhidos de acordo com o fator de encolhimento. Por padrão, o valor de flex-shrink é 1.
flex-shrink

flex-basis

O tamanho dos elementos em um contêiner flex é calculado também de forma flexível. Por padrão, esse tamanho é calculado de acordo com o tamanho do conteúdo do elemento ou pelo seu width ou height. Esse valor padrão ajuda a pessoa desenvolvedora a criar interfaces que se adaptam ao tamanho do conteúdo, mas pode ser um tanto confuso para quem não espera esse comportamento
flex-basis auto
A propriedade flex-basis pode ser alterada de seu valor padrão auto para qualquer unidade de medida de tamanho e porcentagem. Se o elemento tiver width ou height definidos e um flex-basis for definido, o valor de flex-basis tomará precedência no cálculo do tamanho base de um elemento flex.
flex-basis com valores numéricos

Ordenando elementos-filhos de um contêiner flex

Outra propriedade que o Flexbox adicionou ao CSS foi a order, que controla a ordem dos elementos-filhos em um contêiner flex. Elementos em um contêiner serão ordenados de forma ascendente baseados no valor de order e sua posição no DOM.
O valor padrão de order é 0. Você pode definir order com qualquer número inteiro.
order
Vale alertar que a ordenação através de valores order não altera a ordenação desses elementos no DOM, o que cria uma diferença na ordem real dos elementos e sua ordem de exibição. Isso é um problema no uso da navegação por teclado, mas um problema ainda maior para usuários de softwares de leitura de tela. Evite utilizar order se a ordenação tiver efeitos hierárquicos que prejudicariam a acessibilidade do seu site.

Suporte em diferentes navegadores

O Flexbox é suportado por grande parte dos navegadores. Mesmo assim, alguns bugs podem quebrar ou mudar o comportamento dos seus elementos de um navegador para outro. O projeto flexbugs possui uma lista de mais de 10 bugs, com dicas de como contorná-los.
Fora estes bugs, você pode esperar que o seu site estilizado com Flexbox seja renderizado corretamente em todos os navegadores mais utilizados do mercado. O site Can I Use lista o módulo CSS de Flexbox como sendo suportado nos navegadores de mais de 97% dos usuários no mundo.

Continue aprendendo

Todas essas ferramentas do módulo CSS Flexbox trouxeram uma quantidade enorme de controle e flexibilidade para estilizar componentes e layouts com CSS. Em breve escreveremos um outro post com exemplos práticos utilizando todas as propriedades que cobrimos nesta introdução. Por enquanto, você pode dar uma olhada no Solved by Flexbox para ver como o Flexbox resolve problemas clássicos de layout ou então jogar o Flexbox Froggy para aprender na prática.
Para escrever este post eu utilizei diversas referências, incluindo a especificação da W3. Para continuar aprendendo sobre Flexbox, recomendo:
Obrigado Jonathan Zanella por toda a ajuda na revisão e edição deste post.