Se você é um desenvolvedor web mais das antigas, deve ter algumas lembranças da época em que tínhamos que montar layouts com tabelas. Em não muito tempo a partir de agora, um sentimento semelhante permeará os corações dos webdevs que, um dia, usaram position e float para montar suas lindas telinhas web.

Durante uma conversa descontraída tomando um cafezinho, eles lembrarão saudosos da tecnologia que um dia os ajudou tanto, mas que, à época, não passará de uma boa lembrança. Eles já estarão usando Flexbox.

O que é Flexbox

Flexbox, ou Flexible Box Layout, é um novo modo de layout em CSS3, projetado para leiautar aplicações complexas e páginas web.

Em CSS 2.1, 4 modos de layout foram definidos para determinar o tamanho e posição dos boxes baseados na relação com seus boxes irmãos e ancentrais: block para leiautar documentos e documentos na página verticalmente; inline para dispor textos horizontalmente dentro de elementos a nível de bloco; table para dados em 2 dimensões em formato tabular e; positioned para posicionamento explícito sem se importar tanto com outros elementos no documento.

Flexbox é similar ao layout em bloco (block), exceto que ele não tem muitas das propriedades que podem ser usadas num layout em bloco, como floats e columns. Flexbox também é mais flexível por distribuir espaço e alinhar conteúdo em formas que aplicações web e páginas web complexas geralmente precisam. Isso resolve diversos outros problemas de layout que desenvolvedores front-end temos lutado e tentando resolver ao longo dos anos — como centralização vertical, por exemplo, dentro muitos outros.

Flexbox permite que se disponha elementos em um contêiner, organize-os e (re)ordene-os, alinhe-os e se distribua o espaço entre eles (e/ou em volta), independentemente de seu tamanho. Permite que você os torne literalmente flexíveis — itens dentro de um contêiner podem ser esticados e contraídos para acomodar o espaço disponível; redimensionados proporcionalmente entre si; qualquer espaço entre eles ou ao redor deles pode ser distribuído através de uma proporção especificada.
Ao usar flexbox também é possível leiautar elementos dentro de um contêiner em qualquer direção: horizontal ou vertical — o que é chamado de flex directions –, ou seja, não é preciso ficar preso a somente uma direção como em outros modos de layout. Isso permite a criação de layouts mais responsivos, que se adaptam às mudanças que acontecem em diferentes resoluções (e tamanhos) de tela e orientações.

Por último — mas não menos importante –, flexbox permite alterar a ordem visual dos elementos sem afetar sua ordem na marcação. Isso significa que é possível alterar a ordem em que certos itens aparecem na página enquanto sua ordem é preservada na camada de conteúdo. Isso é útil para quando é preciso evidenciar certos itens (ex.: posts em destaque num blog), mesmo que estes itens não estejam em primeiro lugar na marcação HTML.

Sumário das propriedades Flexbox:

Criando um layout Flex: “Flex Container” e “Flex Items”

O primeiro passo para começar a usar Flexbox é criar um flex container. Elementos-filhos de um flex container são chamados flex items e são leiautados dentro do flex container usando as propriedades Flexbox. Algumas das propriedades Flexbox são aplicadas ao container; outras, aos items.

Um flex container é criado ao usar a propriedade display de um elemento com valor flex ou inline-flex.

display: flex cria um flex container a nível de bloco (block-level); display: inline-flex; cria um flex container inline. O flex container se torna um flex context para seus descendentes diretos.

Elementos-filhos de um flex container, os flex items, são leiautados usando layout Flebox. Qualquer elemento fora de um flex container não é afetado pelo layout Flexbox definido e será renderizado na página como de costume.

Conceitos e terminologia

Antes da apresentação das propriedades de Flexbox, propriamente ditas, que controlam e customizam um layout Flexbox, existem 2 conceitos e termos que é preciso estar familiarizado: Eixos Flex (Flex Axes) e Linhas Flex (Flex Lines).

Flex Axes

Ao contrário de layout block ou inline, nos quais o layout é baseado em fluxos de direação em bloco ou em linha, flex layout é baseado em flex directions (direções flex).

O conceito de flex directions em Flexbox é baseado no conceito de eixos (axes) que determinam as direções em que flex items são dispostos. A ilustração a seguir mostra os eixos definidos num flex container (como você vai trabalhar com isso escrevendo em inglês, vai o texto em inglês, mesmo):

Eixos Flex ou Flex Axes

Dependendo dos valores das propriedades Flexbox, flex items serão dispostos dentro de um flex container seguindo ou o eixo horizontal (Main Axis) ou o eixo vertical (Cross Axis).

Sobre a figura, algumas considerações:

É preciso que você se familiarize com estes conceitos antes de começar a mexer com Flexbox já que absolutamente tudo em Flexbox é relativo a estes 2 eixos.

Flex Lines

Flex items em um flex container são leiautados e alinhados dentro de Flex Lines, linhas imaginárias usadas para agrupamento e alinhamento de flex items dentro de seus respectivos containers. Flex Lines seguem o Main Axis. Um flex cotainer pode ser single-line ou multi-line, dependendo da propriedade flex-wrap:

Modos de Escrita (Writing Modes)

A figura acima assume que o Modo de Escrita seja left-to-right (esquerda-para-direita) — mais referenciado como LTR. A flex line segue a direção que do texto que, no modo LTR, é da esquerda para a direita e de cima para baixo. Entretanto, se a direção do texto for alterada através da propriedade direction, a direção da flex line também se altera, mudando a direção dos flex items.

Também, se o Modo de Escrita (writing-mode) é alterado, a direção de ambos os eixos, Main e Cross, também é alterada. Por exemplo, num site em japonês, O Main Axis é vertical e o Cross Axis é horizontal — para mais informações sobre Modos de Escrita e direções, veja o documento CSS Writing Modes Module da W3C.

Propriedades de Flex Container

Agora que os conceitos e termos-chave sobre Flexbox já foram devidamente apresentados, é hora de conhecer cada uma das propriedades de Flex Container.

flex-direction

flex-direction: row | row-reverse | column | column-reverse

Flexbox: flex-direction

A propriedade flex-direction especifica como os flex items são dispostos em um flex container ao especificar a direção do main axis. Isso determina em qual direção que os flex items serão leiautados.

Valores possíveis:

Perceba que os valores reversos não alteram a ordenação da box; como em writing-mode e direction, apenas são alterados a direção e o fluxo. A ordem de painting de fala (dispositivos de leitura de tela) e navegação sequencial não são afetados.

Na prática:


Com o Modo de Escrita RTL (right-to-left):


Vale ressaltar que um flex container tem, inicialmente, uma flex line, e os flex items são dispostos nessa única linha, mesmo que isso “estoure” (overflow) o contêiner. Mais sobre como poder usá-los em múltiplas linhas a seguir, na propriedade flex-wrap.

flex-wrap

flex-wrap: nowrap | wrap | wrap-reverse

Flexbox: flex-wrap

A propriedade flex-wrap controla se o flex container é single-line ou mult-line e a direção do Cross Axis, que determina a direção em que novas linhas são empilhadas (stacked).

Valores possíveis:

Na prática:


Como é possível de ser, flex items tentarão se acomodar em uma só linha. Usando valores diferentes para flex-wrap, é possível mudar isso e fazer com que os itens se disponham em múltiplas linhas.

flex-flow

flex-flow: <'flex-direction'> <'flex-wrap'>

A propriedade flex-flow é um propriedade de declaração única (shorthand) de usar as propriedades flex-direction e flex-wrap que, juntas, definem os Eixos de um flex container.

O valor inicial de flex-flow é a concatenação dos valores iniciais de flex-direction e flex-wrap:

Os exemplos a seguir mostram o resultado de aplicar diferentes valores de flex-flow para um flex container.


Perceba que as direções de flex-flow são escritas em modo sensitivo. Em Japonês vertical, por exemplo, a linha dipõe o conteúdo de cima para baixo:

Flexbox: exemplo de flex-flow

“English” e “Japanese” são apenas exemplos; a diferença é entre uma linguagem horizontal e uma vertical

justify-content

justify-content: flex-start | flex-end | center | space-between | space-around

Flexbox: justify-content

A propriedade justify-content alinha os flex items através do Main Axis da linha atual do flex container. Isso é feito depois que todas as medidas flexíveis e margens automáticas já tiverem sido resolvidas. Normalmente, isso ajuda a distribuir espaço extra que sobra quando todos os flex items numa linha são inflexíveis ou quando são flexíveis, mas atingiram seu tamanho máximo. justify-content também exerce algum controle sobre o alinhamento de itens quando eles “estouram” (overflow) a linha.

Valores possíveis:

Na prática:


align-items

align-items: flex-start | flex-end | center | baseline | stretch

Flexbox: align-items

Em Flexbox, a propriedade align-items é similar a justify-content, mas, ao invés de alinhar os itens através do Main Axis, o faz no Cross Axis.

Valores possíveis:

Na prática:


A propriedade align-self permite que o alinhamento especificado por align-items seja sobrescrito em flex items individualmente.

align-content

align-content: flex-start | flex-end | center | space-between | space-around | stretch

Flexbox: align-content

A propriedade align-content alinha as linhas de um flex container quando há espaço extra no Cross Axis, similarmente ao que justify-content faz com items individuais no Main Axis. Essa propriedade não apresenta qualquer efeito quando o flex container tem somente 1 linha.

Valores possíveis:

Na prática:


Propriedades de Flex Items

A seguir, cada uma das propriedades de Flex Container.

order

order: <integer>

Flexbox: order

Flex items são, por padrão, mostrados e leiautados na mesma ordem em que aparecem no código-fonte do documento. A propriedade order pode ser usada para alterar essa ordem.

A propriedade order de Flexbox controla a ordem em que flex items aparecem num flex container ao colocá-los em grupos ordinais, atribuindo-se um valor <integer> que define a qual grupo ordinal o flex item pertence — sendo que items com o mesmo grupo ordinal são leiautados na ordem em que aparece na camada de conteúdo. O valor inicial de order de todos os flex items é 0 e é possível especificar valores negativos.

Apesar de óbvio, vale a pena lembrar que Flexbox faz parte de CSS, então, a ordem é alterada somente na apresentação dos elementos, não afetando em nada a Camada de Conteúdo — inclusive, leitores de tela lerão na ordem do HTML.

Na prática:


align-self

align-self: auto | flex-start | flex-end | center | baseline | stretch

Flexbox: align-self

Flex items podem ser alinhados no Cross Axis da atual linha do flex container, similarmente a justify-content, mas na direção perpendicular. align-items especifica o alinhamento padrão de todos os flex items do container; a propriedade align-self permite sobrescrever esse alinhamento padrão para items individuais.

Valores possíveis:

Na prática:


flex-grow

flex-grow: <number>

Flexbox: flex-grow

A propriedade flex-grow especifica o fator de crescimento de um flex item. O fator de crescimento é um <number> que determina o quanto o flex item vai crescer em relação ao restante dos flex items no flex container quando espaço em branco positivo é distribuído. O valor inicial de flex-grow é 0 e números negativos são inválidos.

Se os flex items são dispostos na linha de maneira a não ocupar todo seu espaço, é possível “expandir” esses items de maneira a que ocupem toda a linha. A quantidade de espaço disponível na linha pode ser distribuída entre os flex items, seguindo a proporção específica que pode ser especificada usando a propriedade flex-grow. Quanto maior o valor de flex-grow, mais o item poderá crescer relativamente aos outros items.

Por exemplo, é possível distribuir o espaço entre os flex items de maneira tal que 1 destes items tenha o dobro de espaço que os demais usando para a propriedade flex-grow o valor 2. Um item com flex-grow: 2 crescerá o dobro que um flex item com flex-grow: 1 — então, para cada pixel que o segundo item tem, o primeiro cresce em 2 pixels.

No exemplo de prática abaixo, experimente com valores diferentes para cada item e veja os resultados.


A propriedade flex-grow é geralmente usada em conjunto com flex-shrink e flex-basis, tendo como propriedade de declaração única flex.

flex-shrink

flex-shrink: <number>

A propriedade flex-shrink especifica o fator de encolhimento de um flex item. O fator de crescimento é um <number> que determina o quanto o flex item vai encolher em relação ao restante dos flex items no flex container quando espaço em branco negativo é distribuído. O fator de encolhimento é multiplicado pela propriedade flex-basis quando distribui espaço negativo. O valor inicial de flex-grow é 0 — significando que items não têm fator de encolhimento por padrão — e números negativos são inválidos.

Se a soma de Main Size e Cross Size de todos os items for maior que o Main Size do flex container, é possível “encolher” estes flex items; a quantidade pela qual os Main Size dos flex items excede o Main Size do container é o espaço negativo. Usando flex-shrink, é possível distribuir esse espaço negativo através dos flex items em proporção a flex-basis multiplicado pela proporção de flex-shrink, onde flex basis é o Main Size inicial do flex item antes de o espaço ser distribuídos segundo os fatores flex.

Por exemplo, é possível distribuir o espaço entre os flex items de maneira tal que 1 destes items tenha o dobro de espaço negativo que os demais usando para a propriedade flex-shrink o valor 2. Um item com flex-shrink: 2 encolherá o dobro que um flex item com flex-shrink: 1 — então, para cada pixel que o segundo item tem, o primeiro encolhe em 2 pixels.

No exemplo de prática abaixo, os items estão num container com Main Size de 500px. Cada um dos 4 items tem uma base de Main Size (ou flex basis) de 200px. Os items (combinados) obviamente tem um tamanho maior que o Main Size do container. Devido ao fato de isso ser um layout Flexbox, os items se adaptam automaticamente para se adequarem ao tamanho do container em que estão; entretanto, usando a propriedade flex-shrink é possível controlar a proporção pela qual os items serão encolhidos. Experimente com valores diferentes para cada item e veja os resultados.


A propriedade flex-shrink é geralmente usada em conjunto com flex-grow e flex-basis, tendo como propriedade de declaração única flex.

flex-basis

flex-basis: auto | <'width'>

A propriedade flex-basis pega os mesmos valores da propriedade width e especifica o flex-basis: o Main Size inicial do flex item antes de o espaço livre ser distribuído segundo os fatores flex (flex-grow e flex-shrink).

Com exceção do valor auto, flex-basis é resolvida da mesma maneira que width em Modos de Escrita horizontais: valores em porcentagem são especificados em relação ao Main Size interno do flex container. flex-basis também determina o tamanho do box de conteúdo do elemento, salvo indicação em contrário usando a propriedade box-sizing.

Se o valor de flex-basis for auto, o flex-basis usado é o valor do Main Size do flex item — isso pode ser, em si, ser a palavra-chave auto, que dimensiona o item flexível baseado em seu conteúdo.

flex-basis é geralmente usada em conjunto com flex-grow e flex-shrink, tendo como propriedade de declaração única flex.

No exemplo de prática a seguir, flex-basis é usado pela declaração única flex. As propriedades flex-grow e flex-shrink são especificadas de modo aos items não crescerem nem escolherem. O valor de flex-basis define o Main Size de cada item. Experimente com valores diferentes para cada item e veja os resultados.


flex

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

A propriedade flex é a declaração única das propriedades flex-grow, flex-shrink e flex-basis.

Quando um elemento é um item flex, flex é usado para determinar o Main Size do elemento. Se um elemento não é um flex item, flex não apresenta quaisquer efeitos.

O valor inicial é 0 1 auto. As propriedades flex-grow e flex-shrink são opcionais e podem ser omitidas da declaração de flex.

Quando o valor de flex-grow é omitido, é como se este fosse 1. Perceba que este 1 não é o valor inicial da propriedade flex-grow! É somente o valor usado quando flex-grow é omitido da propriedade de declaração única.

Quando a propriedade flex-shrink é omitido, é como se esta tivesse o valor de 1. Lembre-se de que o fator de flex-shrink é multiplicado pelo flex-basis quando distribui espaço negativo — veja flex-shrink.

Quando o valor de flex-basis é omitido, considera-se que é 0%.

Veja valores comuns de flex e seu significado:

Atente para o fato de que, por padrão, flex items não encolhem para um tamanho abaixo de seu tamanho mínimo de conteúdo (o comprimento da palavra mais comprida ou elemento de tamanho fixo). Para mudar isso, trabalhe com as propriedades min-width ou min-height.

No exemplo de prática a seguir, troque o valor da propriedade flex para ver como isso afeta os flex items — também é interessante usar um valor diferente de flex para cada item. No código-exemplo, o valor para flex-basis é de 100px e não expande nem encolhe. Experimente com valores diferentes para cada item e veja os resultados.


Flexbox: exemplos de soluções de problemas comuns

Flexbox provê soluções simples para alguns dos problemas que atormentam desenvolvedores front-end há anos! Veja alguns exemplos a seguir.

Centralização horizontal e vertical

Centralização vertical tem sido uma das soluções CSS mais requisitadas ao longo do tempo. Com Flexbox, centralizar um elemento verticalmente dentro de um contêiner é moleza! Para começar, é preciso criar um contêiner flex:

Então, usando a propriedade justify-content, centraliza-se o elemento no Main Axis (horizontal) e, com align-items, no Cross Axis (vertical).

E é só isso! Não importa o tamanho do elemento, ele sempre será alinhado na vertical e horizontal!

Veja:


Layout multicolunas de igual altura

Uma das situações mais comuns que webdevs front-end precisamos fazer mas, até então, não havia maneira simples de se chegar ao resultado, é criar um layout multicoluna — geralmente 2 ou 3 colunas — de modo às colunas terem a mesma altura, não importando seu conteúdo. Usando Flexbox, isso também é moleza!

Na marcação de um blog, por exemplo:

A intenção é que sidebar tenha a mesma altura que main, não importando o conteúdo de cada um. No que antes se costumava usar técnicas como “faux columns“, com Flebox usa-se um código não mais complicado que:

Então, é possível especificar as larguras fatores de expansão/encolhimento (grow/shrink) usando a propriedade flex, tal como mostrado em:


Usando media queries, é possível empilhar estas colunas para viewports menores usando flex-direction:

Como mostrado anteriormente, é possível reordenar a apresentação dos items com a propriedade order, então, se na página houver publicidade em uma das colunas, por exemplo, é possível fazer com ela fique em cima ou em baixo — ou no meio! — em telas de resolução pequena.

Rodapé fixo

Conseguir o efeito de rodapé fixo foi, durante anos, uma verdadeira batalha para desenvolvedores front-end. Provavelmente a técnica que mais funciona é a mostrada no site CSS Stick Footer, mas é preciso ter toda uma estrutura HTML preparada e, se você quer o efeito num site já existente, pode ser bastante desinteressante ter que alterar sua estrutura.

Flexbox permite colocar um rodapé no fim da página de maneira simples — embora não seja fixo. Começa-se por colocar os flex items na vertical com flex-direction, então, expande-se a section com o conteúdo principal usando flex-grow, empurrando o rodapé para o fim da página — é importante que a página tenha uma altura que seja, pelo menos, igual a da viewport.

O CSS é simples:

Que resulta em:


Navegação flexível

Outra coisa que Flexbox ajuda é no layout de itens de navegação. Antes de Flebox, geralmente se fazia isso com display inline, inline-block, ou block ou usando float para colocar os elementos um ao lado do outro. Mas isso traz inconvenientes, seja quando há poucos itens (sobre espaço), seja quando falta espaço (menus multilinhas).

Com Flexbox, é possível distribuir espaço facilmente entre itens de um menu de navegação usando justify-content:

Além disso, é possível fazer uma navegação vertical simplesmente empilhando os itens em viewports menores, simplesmente usando:

Que resulta em:


E muito mais!

Estes foram somente alguns exemplos de soluções para problemas comuns, mas existe muito, muito mais que pode ser feito com Flexbox! Philip Walton criou uma página chamada Solved By Flexbox com exemplos de “problemas difíceis ou impossíveis de se resolver com CSS de antes, agora trivialmente feitos com Flebox”.

Zoe Mickley Gillenwater também tem um material muito bom, “Leveling Up With Flexbox” (pdf), com diversos casos de uso práticos envolvendo Flexbox.

Flexbox: suporte de navegadores (browser support)

Flexbox: Can I Use?

Como pode ser visto na imagem acima — e consultada compartibilidade de Flexbox diretamente no Can I Use –, a compatibilidade atual de Flexbox entre os navegadores já é quase de 100%!

Entretanto, devido à mudanças de sintaxe que Flebox teve ao longo do tempo, caso seja preciso dar suporte a uma ampla gama de navegadores (antigos), leia o artigo “Advanced Cross-Browser Flexbox” no Dev.Opera Blog.

Também é bem interessante consultar o repo no GitHub Flexbugs, que consiste em uma lista com questões delicadas de Flexbox e maneiras cross-browser de contorná-las.

Ah, e brincar no Flexplorer também pode ser bem divertido!

Conclusão

Flexbox é a nova e elegante maneira de se criar e organizar layouts com CSS3. Através de suas várias propriedades/possibilidades, tarefas que desenvolvedores front-end (até então) se descabelavam para fazer tornam-se triviais e podem ser alcançadas com pouquíssimas linhas de código. Atualmente, a compatibilidade de Flebox é excelente, atingindo mais de 90% entre os navegadores mais usados — e, mesmo se for preciso compatibilidade com browsers antigos, isso também é possível.

Sendo o mais direto possível, Flexbox é uma tecnologia que leva a criação de layouts com CSS ao próximo nível e que pode ser usada hoje! Tá esperando o quê?!