Bento grid é uma forma de organizar a UI em pequenas caixas ocupando quantidades diferentes de células, na horizontal, vertical ou ambas, de acordo com o conteúdo.
Nesse artigo vamos fazer desenhar o layout de 2023 do Apple Watch Ultra que eu peguei do bentogrids.com. Faremos de forma crítica, e que fique fácil implementar os conceitos em qualquer tipo de bento.
Sumário
- O conceito
- Planejando a implementação do grid
- Definindo as colunas
- Definindo as linhas
- Agora sim, o CSS
- Código fonte no Codepen
- Fontes e recursos
O conceito 🔗
Diferente de layouts baseados em cards, a área e posição de cada célula define uma ilha de funcionalidade.
Dessa forma é possível brincar com a hierarquia visual - no exemplo abaixo é possível enxergar um agrupamento natural entre itens que possuem layout compatível, mesmo ocupando espaços e posições diferentes.
Grid | Legibilidade |
---|---|
Fez sentido?
Planejando a implementação do grid 🔗
A construção do grid começa na ordem de leitura, que impacta completamente a construção do layout mobile. Temos duas opções pra esse layout ao meu ver:
- Layout de 3 colunas
- Layout denso
Pra esse exemplo pensaremos esse layout como o de 3 colunas.
No layout de 3 colunas a ordem de leitura parte da experiência de leitura mobile dos itens, empilhando as colunas de conteúdo.
Na minha opinião isso faz sentido pois olhando pra cada elemento individualmente não é possível estabelecer uma hierarquia clara.
Definindo as colunas 🔗
E como pensar as colunas do grid? Pegue lápis e papel e desenhe áreas ao redor dos itens tentando agrupá-los. Lembre-se que tem itens que podem ocupar mais de uma coluna, no exemplo abaixo, no layout à direita (em roxo) foram criadas 3 colunas - percebe como a coluna menor que fica no meio serve como uma coluna auxiliar pra elementos ocupem um espaço diferenciado no layout?
fr
é uma ferramenta poderosíssima nesse caso. Se eu colocar as colunas menores dentro da maior, podemos ver que elas ocupam 1/3 e 2/3 dela, respectivamente.
Logo, nesse layout, as colunas podem ser expressas por:
Unidade | Coluna 1 | Coluna 2 | Coluna 3 |
---|---|---|---|
Fração | 3/6 | 1/6 | 2/6 |
Proporção | 3fr | 1fr | 2fr |
As outras colunas seguem proporções similares, veja como fica quando a gente agrupa as colunas por tamanho:
Definindo as linhas 🔗
Sobre as linhas, temos algumas opções.
Podemos tratar cada grid individualmente ou usar o mesmo layout de linhas pra todos.
Individualmente | Geral |
---|---|
💡 Viram que nem mostrei nada de código ainda?
Se você fizer esse layout sem pensar, você vai escrever pelo menos 3x mais CSS ou mais containers no HTML.
Não por acaso, as linhas seguem a mesma lógica de proporção que as colunas.
As pessoas designers também usam grid, mas no handoff deles não vem em proporção, vem em px. Se você se ater ao conceito de "pixel perfect" vai encher seu layout de media query e ele ainda vai quebrar em viewports específicos. Se quiser saber mais sobre essa visão de media query e pixel perfect, escrevi um artigo bacana sobre:
Agora sim, o CSS 🔗
Cê já tava achando que não ia ter código né?
.bento {
min-block-size: 100vh;
display: flex;
flex-wrap: wrap;
gap: 1ch;
padding: 1ch;
}
Primeiro o container. Optei por flex pois só ele é capaz de alterar a quantidade de "colunas" que um elemento ocupa sem o uso de uma media query.
min-block-size: 100vh
vai garantir que independente do viewport as colunas mantenham seu aspecto de "tela inteira".
.bento__container {
display: grid;
grid-template-rows: 3fr 1fr 1fr 2fr 2fr 3fr;
gap: 1ch;
min-height: inherit;
flex: 2 0 320px;
}
Lembra que eu falei que dava pra usar as mesmas linhas pra todos os grids? Foi o que eu fiz.
O min-height: inherit;
herda o 100vh do pai, fazendo com que no mobile cada coluna ocupe a tela toda verticalmente.
O flex-grow: 2;
faz com que as colunas cresçam pra caber, já que sem o flex-grow
, no primeiro wrap a coluna ia se manter da largura do flex-basis: 320px
.
📝 No código usei o shorthand
flex
que é, na ordem,flex-grow
,flex-shrink
eflex-basis
. Oflex-grow
define uma taxa de crescimento pros flex-items, como quero que ao quebrar pra linha de baixo a coluna ocupe toda a largura, ele é perfeito. Oflex-basis: 320px
faz com que nenhuma coluna.bento-container
fique menor que 320px.
.bento__container[variant-1] {
--bg: #837AED;
grid-template-columns: 3fr 1fr 2fr;
}
.bento__container[variant-2] {
--bg: #F272AC;
grid-template-columns: 2fr 3fr 1fr 2fr;
}
.bento__container[variant-3] {
--bg: #72F286;
grid-template-columns: 1fr 1fr;
}
Criei uma classe variante pra aplicar um esquema de colunas pra cada coluna e um background diferente também.
O variant-1
é um atributo que coloquei diretamente no HTML, isso é CSS válido. É HTML válido? Se você quiser um adesivo da W3C não é não lkkkkkkkkkkk, mas esse é o único problema dessa abordagem.
.bento__item {
height: 100%; width: 100%;
grid-column: var(--columns, span 1);
grid-row: var(--rows, span 1);
background-color: var(--bg);
border-radius: 1rem;
}
Cada item tá recebendo a linha e a coluna via variável, porque?
Pra não ficar escrevendo milhares de nth-child
eu vou injetar essas informações via variável CSS diretamente no template.
Como as variáveis são escopadas no elemento, você pode as colocar na tag style sem medo de aumentar a especificidade.
<main class="bento">
<div class="bento__container" variant-1>
<div class="bento__item" style="--rows: span 2; --columns: 1 / -1;"></div>
<div class="bento__item" style="--rows: span 2;"></div>
<div class="bento__item" style="--rows: span 2; --columns: span 2;"></div>
<div class="bento__item" style="--columns: 1 / -1;"></div>
<div class="bento__item" style="--columns: span 2;"></div>
<div class="bento__item"></div>
</div>
<div class="bento__container" variant-2>
<div class="bento__item" style="--columns: span 2;"></div>
<div class="bento__item" style="--columns: span 2;"></div>
<div class="bento__item" style="--rows: span 4; --columns: 1 / -1"></div>
<div class="bento__item"></div>
<div class="bento__item" style="--columns: span 2;"></div>
<div class="bento__item"></div>
</div>
<div class="bento__container" variant-3>
<div class="bento__item" style="--rows: span 2; --columns: 1 / -1;"></div>
<div class="bento__item" style="--rows: span 2;"></div>
<div class="bento__item" style="--rows: span 2;"></div>
<div class="bento__item" style="--columns: 1 / -1;"></div>
<div class="bento__item" style="--columns: 1 / -1;"></div>
</div>
</main>
🤔 Percebe como isso é quase que equivalente a uma "prop" em frameworks JS?
Código fonte no Codepen 🔗
Fim do post e codepenzinho, sintam-se livres pra fuçar, fazer forks e elaborar melhor o layout.
Dá pra pensar esse layout de outras formas também, sem separar em 3 colunas ou agrupando em mais <div>
no HTML.
Como você faria?
Fontes e recursos 🔗
Recomendo demais o site do bentogrids como inspiração - Link externo, em inglês
O serviço bento.me é uma ótima fonte de inspiração também, além de possibilitar agregar seus links de forma lindíssima (não é publi, mas podia), recomendado pela Mikele Guedes lá no Twitter ✨ - Link externo, em inglês
Top comments (5)
Muito bom! Só alguns comentários:
Acredito que aqui você estava se referindo ao conjunto da esquerda, ficou um pouco confuso
Acredito que aqui você quis dizer linhas, ao invés de colunas
No mais, parabens pelo post!
Ótima dica, corrigi o que tu apontou e dei uma mudada no primeiro texto que tu apontou, quando puder me diga o que achou!
Sempre perplexo com suas abordagens claras e de fácil compreensão, uma coisa que vejo em você, e que almejo muito, é que você é tão bom, que parece fácil.
isso assusta KKKKKMuito obrigado por compartilhar seu conhecimento sempre aprendo bastante com seus artigos 🦤.
Muito bom,este tópico abordado por você, muito obrigado.
uma vez eu tentei fazer um grid e fiquei HORAS procurando alguma explicação simples (no final eu desisti e fiz com flex, risos)
VOCÊ É BRABO DEMAIS