Bento Grid layout responsivo em 40 linhas de CSS🥢 🍱
Tags: css, tutorial, webdev, codenewbie
Published: 2023-11-17 14:56:35

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.

![Grid complexo com diversas linhas e colunas e células ocupando diferentes proporções de espaço vertical e horizontal, lembrando uma caixa de bento que tem seções diferentes pra cada ingrediente. ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44t5lyqdvtnxes261xz8.png)


Nesse artigo vamos fazer desenhar o layout de 2023 do Apple Watch Ultra que eu peguei do [bentogrids.com](https://bentogrids.com/). Faremos de forma crítica, e que fique fácil implementar os conceitos em qualquer tipo de bento.

&nbsp;

**Sumário**

- [O conceito](#concept)
- [Planejando a implementação do grid](#implementation)
- [Definindo as colunas](#cols)
- [Definindo as linhas](#rows)
- [Agora sim, o CSS](#css)
- [Código fonte no Codepen](#pen)
- [Fontes e recursos](#resources)

<br />

---

<br />

## O conceito <a id="concept" href="#concept">&#128279;</a>

Diferente de layouts baseados em cards, a área e posição de cada célula define uma ilha de funcionalidade.


![Uma caixa pra bentô contendo 4 espaços, 3 pequenos na parte superior com milho, brócolis e morango e um espaço grande ocupando toda área vertical da caixa com batata cozida, vagem e camarão. É possível relacionar o formato dos dois layouts](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7z2sgt8r0t66pmidyjrv.png)

&nbsp;

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 |
| :---: | :---: |
| ![Layout bentô apresentando as diferentes funcionalidades de um celular](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ht0v71nx3kowt9k007k.png) | ![O mesmo layout com direção de leitura e as áreas focais destacadas de acordo com o peso visual gradando do vermelho ao amarelo, do escuro ao claro](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5qc42yos8mgobojogun.png) |

&nbsp;

Fez sentido?

<br />

---

<br />

## Planejando a implementação do grid <a id="implementation" href="#implementation">&#128279;</a>
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.

![O layout bento separado em 3 colunas com uma seta indicando que cada uma é lida da esquerda pra direita de cima pra baixo individualmente
](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pcynyz8li7fua3usuyxx.png)

No layout de 3 colunas a ordem de leitura parte da experiência de leitura mobile dos itens, empilhando as colunas de conteúdo.

&nbsp;

![Layout com as 3 colunas empilhadas na ordem em que estavam
](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rgf7vf0akfy3rxpriura.png)


Na minha opinião isso faz sentido pois olhando pra cada elemento individualmente não é possível estabelecer uma hierarquia clara.

<br />

---

<br />

## Definindo as colunas <a id="cols" href="#cols">&#128279;</a>

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?


![Um overlay foi colocado em cada coluna organizando seus itens em sub-colunas.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztreq80d11vk6afede6j.png)

&nbsp;

`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 | 

&nbsp;

As outras colunas seguem proporções similares, veja como fica quando a gente agrupa as colunas por tamanho:


![Todas as sub-colunas foram organizadas pra mostrar que suas proporções se repetem de forma consistente](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cswjd31s81133ss8rl60.png)

<br />

---

<br />

## Definindo as linhas <a id="rows" href="#rows">&#128279;</a>

Sobre as linhas, temos algumas opções.
Podemos tratar cada grid individualmente ou usar o mesmo layout de linhas pra todos.

| Individualmente | Geral |
| :---: | :---: |
| ![Exemplo de definição de linhas de grid pra cada coluna individualmente. Pra cada coluna as linhas seguem uma lógica própria](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tuqyol0w0gs3k6v49lql.png) | ![O mesmo layout, só que usando as mesmas linhas pra todas as colunas. Elas seguem uma proporção parecida com as colunas](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3o71ugnanrd5i8leo0tr.png) |

&nbsp;

> 💡 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.

&nbsp;

Não por acaso, as linhas seguem a mesma lógica de proporção que as colunas.


![Demonstração da proporção das linhas em que as duas linhas menores cabem dentro da maior](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c56wclxuikbypb22yrxh.png)

&nbsp;

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:

{% embed https://dev.to/lixeletto/responsividade-css-101-breakpoints-1c06 %}


<br />

---

<br />

## Agora sim, o CSS <a id="css" href="#css">&#128279;</a>

Cê já tava achando que não ia ter código né?

```css
.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".

&nbsp;

```css
.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`.

![Layout com 3 colunas contendo parte do bento layout, duas em cima e uma embaixo posicionada pelo flex-wrap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i0frldfsoj4eumo71w7b.png)

&nbsp;

> 📝 No código usei o _shorthand_ `flex` que é, na ordem, `flex-grow`, `flex-shrink` e `flex-basis`. O `flex-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. O `flex-basis: 320px` faz com que nenhuma coluna `.bento-container` fique menor que 320px.

&nbsp;

```css
.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.

&nbsp;

```css
.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.

```html
<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?

<br />

---

<br />

## Código fonte no Codepen <a id="pen" href="#pen">&#128279;</a>

Fim do post e codepenzinho, sintam-se livres pra fuçar, fazer forks e elaborar melhor o layout.

{% codepen https://codepen.io/camilo-micheletto/pen/YzBYPvv %}

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?

<br />

---

<br />

## Fontes e recursos <a id="resources" href="#resources">&#128279;</a>

- Recomendo demais o site do bentogrids como inspiração - [Link externo, em inglês](https://bentogrids.com/)

- 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 ✨](https://x.com/MikeleGuedes/status/1725471493797097946?s=20) - [Link externo, em inglês](https://bento.me/en/home)