Grid para layout, flexbox para componentes
Emanuel Gonçalves
Posted on June 26, 2020
Imagem de fundo por Halacious on Unsplash
Compartilho com você a tradução autorizada deste excelente artigo escrito por Ahmad Shadeed.
Título original - Grid for layout, Flexbox for components
Meu irmão é recém-formado em engenharia da computação e ele está atualmente finalizando seu estágio em desenvolvimento front-end. Ele aprendeu sobre CSS grid e flexbox, mas eu notei um padrão que eu vi muito na web. Ele não conseguia decidir quando usar grid ou flexbox. Por exemplo, ele usou CSS grid para fazer o layout do cabeçalho de um site e mencionou que o processo não foi tranquilo, pois ele brincava com a propriedade grid-column
e tentava ajustá-la até se parecer com o design.
Para ser sincero, não gosto disso, e também pesquisei sobre um recurso que ele pode usar para aprender as diferenças entre grid e flexbox, com exemplos de ambos, mas não consegui encontrar nenhum. Decidi escrever um artigo profundo que cubra tudo sobre aquele tópico. Espero que você ache claro!
Introdução
Antes de entrar de cabeça nos conceitos e exemplos, eu quero me certificar que você entende a diferença entre CSS grid e flexbox. CSS grid é um módulo multi-dimensional de layout, que significa que ele possui colunas e linhas. Flexbox pode dispor seus itens filhos como colunas ou linhas, mas não ambos.
Se você não conhece CSS grid e flexbox, eu recomendo ler este artigo visual. Se você os conhece, que legal, vamos mergulhar nas diferenças entre eles e quando usar cada um e o porquê.
A diferença entre Grid e Flexbox
Deixe-me ser claro a respeito disso, não há uma maneira direta de decidir entre CSS grid e flexbox. Além disso, não há uma forma correta e incorretá de usá-los. Este artigo é um tipo de guia que recomenda usar uma técnica para um específico caso de uso. Eu explicarei o conceito geral, e então ir aos exemplos, e o resto é você que explora e experimenta mais.
/* Flexbox wrapper */
.wrapper {
display: flex;
}
/* Grid wrapper */
.wrapper {
display: grid;
grid-template-columns: 2fr 1fr;
grid-gap: 16px;
}
Você notou alguma coisa? O Flexbox apresenta uma lista in-line de elementos, enquanto o CSS grid os torna os transforma em um grid de colunas e linhas. Flexbox está alinhando o alinhamento em uma linha. Isso pode ser uma coluna, se quisermos.
/* Flexbox wrapper */
.wrapper {
display: flex;
flex-direction: column;
}
Como decidir qual usar
Decidir entre CSS grid e flexbox pode ser um pouco difícil (às vezes), especialmente se você é novo em CSS. Eu posso ouvir você! Aqui estão algumas perguntas iniciais que eu faço ao escolher entre eles:
- Como os itens filho do componente são exibidos? Em linha ou em colunas e linhas?
- Como o componente deve funcionar em diferentes tamanhos de tela?
Na maioria das vezes, se o componente que você está vendo tiver todos os itens filhos exibidos em linha, provavelmente o flexbox é a melhor solução. Considere o seguinte exemplo:
Contudo, se você ver colunas e linhas, o CSS grid é a solução para o seu caso.
Agora que expliquei a principal diferença entre eles, passemos a exemplos mais específicos e vejamos como decidir.
Casos de uso e exemplos
Na seção a seguir, discutirei em detalhes sobre os diferentes casos de uso para flexbox e grid.
CSS Grid
Main e Sidebar
Quando você tem uma barra lateral e seção principal (main
), o CSS Grid é uma solução perfeita para construí-los. Considere a seguinte modelo:
Aqui está como eu faria isso em CSS:
<div class="wrapper">
<aside>Sidebar</aside>
<main>Main</main>
</div>
@media (min-width: 800px) {
.wrapper {
display: grid;
grid-template-columns: 200px 1fr;
grid-gap: 16px;
}
aside {
align-self: start;
}
}
Se align-self
não for usado para o elemento aside
, a altura dele será igual ao do elemento main
, não importa o tamanho do conteúdo.
Cards em Grid
Conforme discutido no início do artigo, o CSS grid é auto-explicativo a partir do nome, portanto, usá-lo para criar uma grade de cartões é um uso perfeito dele.
Aqui está como eu implementaria o layout:
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 16px;
}
A largura da coluna será de pelo menos 200px
, e se o espaço não for suficiente, ele irá colocar os cards em uma nova linha. Vale ressaltar que o código acima pode causar rolagem horizontal se a largura do viewport for menor que 200px
.
Uma solução simples é adicionar a definição de grid somente quando a largura do viewport for suficiente. Veja abaixo:
@media (min-width: 800px) {
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 16px;
}
}
Layout de seção
No design a seguir, podemos usar o grid duas vezes, o primeiro uso é dividir a área em outras duas áreas (a barra lateral "Contact us", e o formulário) e o segundo uso é no próprio grid do formulário.
Não consigo enfatizar o quanto CSS grid é perfeito para isso. Aqui está como fazer no CSS:
@media (min-width: 800px) {
.wrapper {
display: grid;
grid-template-columns: 200px 1fr;
}
.form-wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 16px;
}
.form-message,
.form-button {
grid-column: 1 / 3; /* deixe que eles tomem toda a largura */
}
}
Este exemplo é emprestado do meu artigo na Envanto sobre a construção de layouts para formulários web com CSS grid. Eu recomendo que você leia.
CSS Flexbox
Navegação do website
90% das vezes, a navegação do website deverá ser feita com Flexbox. O padrão mais comum é ter a logo à esquerda e a navegação à direita. Isso é perfeito para flexbox.
No exemplo acima, tudo que você precisa definir é o seguinte:
.site-header {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
O mesmo conceito também pode funcionar no seguinte design também.
Note como a estrutura de navegação ficou um pouco diferente, mas o espaçamento entre os itens ainda é feito com a propriedade justify-content
.
Lista de ações
Quando você ouve falar de uma lista, a primeira coisa que você pensa é uma lista vertical. No entanto, uma lista pode ser exibida em linha, então eu só queria ter certeza de que isso está claro.
Um exemplo de uma lista de ações é algo que podemos pegar emprestado do Facebook ou Twitter. A lista de ações consiste em botões de ação que o usuário pode executar. Veja as imagens abaixo:
Como você vê, os itens são exibidos um ao lado do outro e são distribuídos horizontalmente. Flexbox é perfeito para isso! Esse é um dos principais usos dele.
.actions-list {
display: flex;
}
.actions-list__item {
flex: 1; /* expande os items para que tomem todo o espaço disponível igualmente entre eles */
}
Outra variação disso é um botão de ação de uma modal ou um cabeçalho de uma modal.
Tanto o cabeçalho da modal como o rodapé têm elementos filhos que são exibidos em linha. Como você vê, o espaçamento entre eles é feito como abaixo.
Para o cabeçalho da modal, fica assim:
.modal-header {
display: flex;
justify-content: space-between;
}
E para o rodapé, é um pouco diferente. A ação "Cancel" usa uma margem automática para se empurrar para a direita. Eu escrevi um artigo detalhado sobre isso.
.cancel__action {
margin-left: auto;
}
O nome da classe .cancel__action
pode não ser perfeito aqui, mas não quero entrar em convenções de nomenclatura de CSS para este artigo.
Elementos de formulário
Uma combinação de um input
com um botão ao lado é um caso de uso perfeito para o Flexbox. Considere a figura abaixo:
No primeiro formulário, o input
está ocupando todo o espaço restante, fazendo com que ele tenha uma largura dinâmica. O mesmo se aplica ao segundo formulário (Facebook Messenger), o campo de texto ocupa todo o espaço restante. Vamos olhar mais de perto.
.input { flex: 1 1 auto; }
Observe que, sem usar flex: 1 1 auto
no campo de texto, ele não se expandirá e preencherá o espaço restante.
Threads e comentários
Outro caso de uso comum para o flexbox são as threads de comentários. Considere o seguinte exemplo.
Temos a foto do usuário e o próprio comentário. O comentário está ocupando o espaço restante de seu elemento pai. Esse é um uso perfeito para o flexbox.
Componentes de card
Um componente de card tem muitas variações, mas o design mais comum é semelhante ao modelo abaixo.
À esquerda, o ítens filhos do card são empilhados pois a direção definida na propriedade flex-wrapper
é column
. Enquanto que à direita é o oposto. A direção usada é row
, e tenha em mente que row
é o default para flexbox.
.card {
display: flex;
flex-direction: column;
}
@media (min-width: 800px) {
.card {
flex-direction: row;
}
}
Outra variação comum para um cartão é ter um ícone com um label de texto abaixo dele. Pode ser um botão, link ou apenas para decoração. Considere o seguinte modelo:
Note como o ícone e o label do texto estão centralizados na horizontal e na vertical. Graças ao flexbox, isso é fácil de fazer.
.card {
display: flex;
flex-direction: column;
align-items: center;
}
O estilo em linha será o padrão, basta remover a declaração flex-direction: column
e deixá-la no valor padrão (row
).
Tabs e Menus de botão
Quando se trata de elementos que ocupam toda a largura da tela e têm itens que devem preencher todo o espaço disponível, o flexbox é a ferramenta perfeita aqui.
No exemplo acima, cada item deve preencher o espaço disponível e deve ter largura igual. Ao configurar a exibição do wrapper para flex, isso pode ser feito facilmente.
.tabs__item {
flex-grow: 1;
}
Essa técnica é usada no React Native para criar a barra de guias para aplicativos mobile. Aqui está um exemplo de código que faz o mesmo que o descrito acima em React Native. O código é emprestado deste local.
import React from 'react';
import { View } from 'react-native';
export default FlexDirectionBasics = () => {
return (
<View style=>
<View style= />
<View style= />
<View style= />
</View>
);
};
Lista de características
O que eu mais gosto no flexbox é a capacidade de reverter a direção dos elementos. A direção padrão no flexbox é row
, mas podemos revertê-la como abaixo.
.item {
flex-direction: row-reverse;
}
Na modelo abaixo, observe como o item par é revertido, isso é feito com a técnica acima. É muito útil.
Centralizando uma seção de conteúdo
Vamos considerar que temos uma seção hero
, e o conteúdo precisa estar centralizado horizontalmente e verticalmente. A centralização horizontal pode ser fácil pois poderia ser feito com o alinhamento de texto.
.hero {
text-align: center;
}
Mas como podemos usar o flexbox para centralizar os elementos verticalmente? Aqui está o que precisamos.
.hero {
display: flex;
flex-direction: column;
align-items: center; /* centralizar os elementos horizontalmente */
justify-content: center; /* centralizar os elementos verticalmente */
text-align: center;
}
Combinando CSS grid e Flexbox
Não apenas cada módulo de layout possui seu caso de uso, mas podemos usar ambos. Quando penso sobre combinar eles, o primeiro uso que eu vejo é uma lista de cards. Grid é usado para dispor os cards, e flexbox é usado para o componente card em si.
Aqui estão os requisitos para o layout:
- A altura dos cards para cada linha deve ser igual
- O link "Read more" deve ser posicionado no final do card, independentemente da sua altura.
- O grid deve usar a função
minmax()
<div class="wrapper">
<article class="card">
<img src="sunrise.jpg" alt="">
<div class="card__content">
<h2><!-- Title --></h2>
<p><!-- Desc --></p>
<p class="card_link"><a href="#">Read more</a></p>
</div>
</article>
</div>
@media (min-width: 500px) {
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-gap: 16px;
}
}
.card {
display: flex; /* [1] */
flex-direction: column; /* [2] */
}
.card__content {
flex-grow: 1; /* [3] */
display: flex; /* [4] */
flex-direction: column;
}
.card__link {
margin-top: auto; /* [5] */
}
Deixe-me explicar o CSS acima:
- Faz o card um wrapper flexbox.
- A direção usado é
column
, o que significa que os elementos cards estão empilhados - Deixa o conteúdo do card expandido e preencher o espaço restante.
- Faz o conteúdo do card um wrapper flexbox.
- Finalmente, usando
margin-top:auto
para empurrar o item para baixo. Isto irá mantê-lo posicionado ao final do card independente da altura.
Como você viu, combinar CSS grid e flexbox não é difícil. Essas duas ferramentas podem nos dar várias maneiras de implementar layouts na web. Vamos usá-los corretamente e combiná-los somente quando necessário, como acima.
Fallback e suporte a navegadores antigos
Usando CSS @supports
Há alguns meses, recebi um tweet dizendo que meu site estava quebrado no IE11. Depois de verificar, notei um comportamento muito estranho. Todo o conteúdo do site estava recolhido na área superior esquerda. Meu site não estava navegável!
Sim, este é o meu site - um site de um desenvolvedor front-end, no IE11. No começo, fiquei confuso, por que isso está acontecendo? Lembrei que o CSS grid é suportado no IE11, mas essa é a versão antiga lançada pela Microsoft. A solução é muito simples, que é usar o @supports
para usar somente a grade CSS em novos navegadores.
@supports (grid-area: auto) {
body {
display: grid;
}
}
Deixe-me explicar isso. Eu usava grid-area
porque ela era suportada apenas na nova especificação do CSS grid, de março de 2017 até hoje. Uma vez que o IE não suporta a query @supports
, toda a regra será ignorada. Como resultado, o novo CSS grid será usado apenas em navegadores que o suportam.
Usando o flexbox para suporte ao CSS grid
Se o flexbox não é adequado para exibir uma grade de itens, isso não significa que não seja bom como fallback. Você pode usar o flexbox como substituto do CSS grid para navegadores não compatíveis. Eu trabalhei em uma ferramenta que faz exatamente isso.
@mixin grid() {
display: flex;
flex-wrap: wrap;
@supports (grid-area: auto) {
display: grid;
grid-gap: 16px 16px;
}
}
@mixin gridAuto() {
margin-left: -16px;
> * {
margin-bottom: 16px;
margin-left: 16px;
}
@media (min-width: 320px) {
> * {
width: calc((99% / #{2}) - 16px);
flex: 0 0 calc((99% / #{2}) - 16px);
}
}
@media (min-width: 768px) {
> * {
width: calc((99% / #{3}) - 16px);
flex: 0 0 calc((99% / #{3}) - 16px);
}
}
@supports (grid-area: auto) {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
margin-left: 0;
> * {
width: auto;
margin-left: 0;
margin-bottom: 0;
}
}
}
O código de fallback acima funciona da seguinte maneira:
- Adiciona
display: flex
eflex-wrap: wrap
ao elemento wrapper. - Verifica se CSS grid é suportado, se sim, então
display: grid
será usado. - Usando o seletor
> *
, podemos selecionar os elementos filhos diretos do wrapper. Ao selecioná-los, podemos adicionar uma largura ou tamanho específico a cada um. - Obviamente, a margem entre cada uma é necessária e será substituída por
grid-gap
, caso CSS grid seja suportado.
Aqui está um exemplo de como usar este mixin do Sass.
.wrapper {
@include grid();
@include gridAuto();
}
Quando as coisas dão errado para o Grid e o Flexbox
Enquanto fazia uma revisão de código para o meu irmão, notei alguns usos incorretos para o CSS grid ou o flexbox e achei que seria útil se eu destacasse alguns deles.
Usar CSS grid para um cabeçalho de site
Uma das motivações deste artigo foi esse erro. Notei que meu irmão está usando CSS Grid para implementar um cabeçalho de site.
Ele mencionou coisas como "era complexo, CSS Grid é difícil... etc". Como resultado do uso de um método de layout incorreto, ele teve uma ideia de que o CSS grid é complexo. Não é, e toda a sua confusão veio do fato de usá-lo para algo que não é adequado.
Considere o seguinte exemplo que eu notei.
.site-header {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
}
.site-nav {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
O CSS grid foi usada duas vezes, a primeira vez foi para todo o cabeçalho e a segunda para a navegação. Ele usou grid-column
para ajustar o espaçamento entre os elementos e outras coisas estranhas que não me lembro, mas você entendeu!
Usando CSS Grid para tabs
Outro uso incorreto do CSS Grid é aplicá-lo em um componente de tabs. Considere o seguinte modelo.
O código CSS incorreto se parece com o seguinte:
.tabs-wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
Pelo código acima, posso ver que o desenvolvedor assumiu que a contagem de tabs é de apenas três. Como resultado, ele usou 1fr 1fr 1fr
para organizar as colunas. Isso pode ser quebrado facilmente se a contagem de colunas for alterada.
Uso excessivo de Flexbox ou Grid
Lembre-se de que o antigo método de layout pode ser perfeito para o trabalho. O uso excessivo de flexbox ou grid pode aumentar a complexidade do seu CSS com o tempo. Não estou dizendo que eles são complexos, mas usá-los corretamente e no contexto certo, conforme explicado nos exemplos deste artigo, é muito melhor.
Por exemplo, você tem a seguinte seção hero
com uma solicitação para centralizar horizontalmente todo o conteúdo dela.
Isso pode ser feito simplesmente usando text-align: center
. Porque usar flexbox quando há uma solução mais fácil?
Conclusão
Ufa, isso foi muito sobre as diferenças entre o uso de grid CSS e flexbox. Este tópico estava em minha mente por muito tempo, e eu fico feliz que eu tive a chance de escrever sobre ele. Por favor, não hesite de dar um feedback tanto por email ou twitter @shadeed9!
Obrigado pela leitura.
E é isso, espero que tenha gostado. Não deixe de seguir Ahmad Shadeed no Twitter. Ele sempre vem com textos bem completos sobre CSS e Design. E se você gostou deste post, não esqueça de curtir ele e compartilhá-lo em suas redes sociais.
Até o próximo post!
Posted on June 26, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.