Bora aprender a lançar esse layout com apenas com CSS grid e dois copos d'agua?
web | mobile |
---|---|
Vai ser um pouco complexo, então tem Codepen comentado no final do post.
Nesse artigo vou falar de:
- grid (duh)
- padrões de layout
- unidades relativas
- variáveis CSS
O resultado final vai ser isso aqui:
Estrutura HTML
A estrutura de conteúdo HTML que vou utilizar vai ser de uma tag <main>
pra conter o layout, uma <section>
pra conter o título e a lista, um <header>
pra conter os dois títulos e uma lista ordenada (<ol>
) pra conter os cards.
<main class="layout">
<section class="benefits">
<heading class="benefits__heading">
<h1>App Headline</h1>
<h2>App subtext</h2>
</heading>
<ol class="benefits__list">
<li class="benefits__list-item">
<span class="circle">1.</span>
</li>
<li class="benefits__list-item">
<span class="circle">2.</span>
</li>
<li class="benefits__list-item">
<span class="circle">3.</span>
</li>
</ol>
</section>
</main>
Não vou me aprofundar nisso pq o foco é o CSS.
Grid principal - Holy Grail 🙏
E vamos pro nosso primeiro grid!
O container principal é o que chamamos de layout holy grail. Ele consiste no layout em 3colunas, com a coluna de conteúdo no centro do site, muito popular até hoje.
A imagem da direita eu roubei desse post maravilhoso do Josh Comeau sobre o assunto (link externo).
Holy grail | Nosso layout |
---|---|
Nesse primeiro grid precisamos de:
- No mínimo, 30px de padding vertical
- 60px de padding lateral quando o viewport tiver 400px de largura
- O container dos cards ter até 720px de largura na web, e quase 100% de largura no mobile, só que na vertical
Perceba que no layout mobile, quando em 400px de largura, o padding horizontal está com 60px, MAS se o layout fosse 300px de largura, manteríamos o padding?
Não. Opadding
decrescer proporcionalmente garante a legibilidade do conteúdo, se mantivéssemos opadding
, o card ia ficar espremido demais pra permanecer legível. Percebe-se que forçar pixel perfect é PIOR pra responsividade, pois se a gente mantivesse opadding
pra reforçar o layout, perderíamos em qualidade em todos os dispositivos menores que 400px de largura.
Como o layout é de página inteira, definimos que o tamanho-mínimo-vertical (min-block-size) vai ser de 100% da altura do viewport (100vh).
O padding vertical vai ser de 30px e o horizontal vai ser o menor valor entre 60px (3.75rem) e 5vmin (5% do tamanho do menor lado da tela).
.layout {
--spacing: 3.75rem;
min-block-size: 100vh;
padding: 30px min(var(--spacing), 5vmin);
}
Esse hack do padding faz com que o padding vá até 60px em larguras maiores, mas em viewports menores ele diminua proporcionalmente, sempre tentando fazer os cards caberem. Pra quem quiser saber mais, recomendo esse post do Tárcio Zemel sobre o assunto (link externo).
Já para o grid, temos uma linha de 1fr e 3 colunas.
.layout {
--spacing: 3.75rem;
min-block-size: 100vh;
display: grid;
grid-template: 1fr / 1fr min(720px, 100%) 1fr;
place-items: center;
padding: 30px min(var(--spacing), 5vmin);
}
O min()
da segunda coluna diz basicamente o seguinte:
"Entre 100% e 720px, me retorna o menor valor"
O place-items: center;
alinha os elementos tanto vertical, quanto horizontalmente (ele é justify-items
e align-items
juntos!).
Com essa configuração, quando a largura do navegador for maior que 720px, o bloco do meio vai ter 720px e a primeira e última coluna vão ficar com o espaço que sobrar, quando for menor que 720px, a coluna do meio vai ter 100% de largura, sobrando 0px pras colunas nas extremidades.
Visualmente:
>720px | <720px |
---|---|
Se liguem nas linhas pontilhadas! Elas que mostram onde cada coluna se separa.
Pra finalizar, um detalhe - precisamos colocar todos os itens dentro de main.layout (o heading e a lista de cards) na coluna do meio do nosso grid.
.layout {
--spacing: 3.75rem;
min-block-size: 100vh;
display: grid;
grid-template: 1fr / 1fr min(720px, 100%) 1fr;
place-items: center;
padding: 30px min(var(--spacing), 5vmin);
}
.layout > * { grid-column: 2; }
Ufa, primeiro grid finalizado, hora do primeiro copo d'agua!
2º e 3º grids - empilhamentos
Os dois próximos grids são bem mais simples.
Eu precisava colocar o <header>
e a lista de cards em uma coluna, o CSS grid já faz isso pra mim direto de fábrica, é como se ele já viesse com o flex-direction: row;
do flexbox. Tanto o grid quanto o flex possuem a propriedade row-gap, que é o espaçamento interno entre linhas.
.benefits {
--items-width: clamp(200px, 100%, 280px);
display: grid;
row-gap: 0.75rem;
height: max-content; width: 100%;
}
.benefits__heading {
display: grid;
row-gap: 0.25rem;
justify-self: center;
width: var(--width, var(--items-width));
}
Grid da lista de cards - o RAM
E por último, o grid da nossa lista de cards. Geralmente se usaria flexbox pra esse layout, mas prefiro grid pelo seguinte motivo:
Então porque usei grid?
No grid o container<ol>
controla o tamanho dos filhos, já no flexbox o conteúdo dos filhos que define o tamanho deles. O grid obriga os elementos filhos a manterem seu aspecto, ficando com os filhos a responsabilidade de reorganizar o conteúdo p caber.
Esse post do Jake Archibald (link externo) explica melhor esse e mais conceitos do pq a gente só usa flexbox apenas quando não der pra usar grid.
Nesse layout criamos uma linha com altura de max-content
. O max-content
faz com que o elemento mantenha sempre a altura ideal pra todos os seus filhos caibam confortavelmente
Mais sobre max-content nesse post da MDN (link externo, em inglês ☹).
.benefits__list {
display: grid;
grid-template: max-content / repeat(auto-fit, minmax(200px, 1fr));
place-items: center;
gap: var(--spacing);
}
Mas que porra é essa de repeat, auto o que?!
Vou explicar:
A função repeat() é apenas do CSS grid, ela recebe como primeiro parâmetro uma quantidade e como segundo parâmetro o tamanho da coluna.
.elemento {
display: grid;
grid-template-columns: repeat(<quantidade>, <largura>);
}
Quando a gente passa o valor auto-fit
no primeiro parâmetro, a gente tá dizendo:
"o quanto couber" 😏
Já o minmax()
retorna um valor entre um mínimo e um máximo que vai caber naquele contexto. Traduzindo:
"Crie quantas colunas couberem entre 200px e (n)"
Essa técnica é conhecida como RAM (repeat, auto-fit, minmax) e esse texto do Juan Martín Garcia no CSS Tricks (link externo, em inglês) é o melhor artigo que eu conheço sobre.
Codepen de exemplo 💻
Ufa 😪
Altas tretas até aqui, mas espero que tenha conseguido demonstrar formas de criar layouts bacanas apenas com Grid usando padrões que pessoas devs descobriram futricando por ai. Dicas, correções, sugestões ou salves, sintam-se livres pra deixar um comentário ou me mandar DM no meu Twitter.
Thread que originou o artigo, no twitter (humildes darão um salve 👀)
Top comments (4)
mago do CSS! vou usar esse artigo como base na implementacao de grid que terei que fazer, ajudou demais!
Que honra! Qualquer coisa minha DM lá do TT tá abertíssima também
Cara que conteúdo fenomenal, meu olho brilha lendo seu código e vendo que tenho muuito a aprender ainda, adorei, muito obrigado por compartilhar seu conhecimento 🦤.
Que honraaaaa!