CSS - Grid

Se você pensa que só o bootstrap tem esse recurso, se enganou...a CSS é a fonte dele não o bootstrap.

Outro detalhe importante é seja qual for o recurso ele tem que ser responsivo, ou seja, obedecer ao tamanho da tela de exibição do browser.

Para que serve o Grid

Se você é um dos brontossauros da internet como eu deve se lembrar que na pré-história remota quando a gente precisava alinhar múltiplos itens verticalmente a gente usava a tag table e ela fazia esse serviço. Uma simples página de login a gente precisava usar uma table para alinhar os itens verticalmente.

Felizmente tanto o HTML quanto a CSS agora fazem isso de uma maneira muito melhorada, menos código e mais recursos de formatação. O complicado hoje é manter esses recursos na memória...são tantos.

O que é o Grid

O Grid é um recurso de 'fatiamento' horizontal da linha corrente de renderização do browser onde podemos dividir ela em partes iguais ( para que a exibição fique homogênea ) e ainda podemos definir o espaçamento ou 'esticar' o elemento por n espaços, como mesclar 'mesclando' coluna2 como no excel. O mais loco é que ao expandirmos verticalmente o item de uma linha o item da linha seguinte pode ser impactado pelo tamanho do item da linha anterior/superior. Vamos ver esse recurso abaixo neste documento.

A gente costuma usar muito o recurso flex-grid para fazer essa tarefa de dividir a linha de exibição horizontalmente, mas o grid é mais fácil de ser usado e por esse motivo tem ganhado a preferência dos programadores. Contudo há circunstâncias, como um barra de navegação, que o flexbox leva vantagens sobe o grid.

Modelo básico

A primeira coisa é que o grid atual numa tag container. Para dizer que nesse container usaremos o grid usamos o estilo 'display: grid;'. Note que a aplicação apenas do estilo 'display: grid;' não faz nada porque não definimos divisões ou as partes que cada elemento ocuparão. Por default os elementos ocupam todo o espaço se nada for definido.

Coloquei no estilo 'border: 1px solid black;' para que as regiões ocupadas por cada elemento fiquem bem claras.

Para definir 'quanto' que o elemento deve ocupar devemos definir as propriedades colunas (col) e linhas (row).

Grid - Colunas

A propriedade coluna do grid é o estilo Grid-Template-Columns.

Importante : Grid-Template-Columns define a largura dos itens no grid.

Inicialmente no container definimos quantas colunas terão os itens contidos. Por exemplo, se no estilo colocarmos 'grid-template-columns: repeat(1fr,1fr,1fr);' a linha será divida em 3 partes horizontalmente e igualmente.

Podemos definir quantas colunas o elemento deverá ocupar. Lembre-se coluna é definida de cima para baixo. O default é uma fração da linha, ou seja 'grid-template-columns:1fr'. Agora você deve estar perguntando o que significa essa 'fração' ou 1fr. A fração é em quantas partes a linha foi dividida. Se só tem um elemento na linha esse 1fr ocupará a linha inteira. Se houver 2 elementos na linha, 1fr ocupará metade da linha e assim por diante . O espaço é dividido igualitariamente para cada elemento da linha.

No exemplo abaixo temos um grid simples com 3 elementos dividindo igualitariamente uma linha.

Código

<div style="display:grid;grid-template-columns: 1fr 1fr 1fr;">
   <div class="item">Item 1</div>
   <div class="item">Item 2</div>
   <div class="item">Item 3</div>
</div>

Como é exibido

Item 1
Item 2
Item 3

No elemento container quando definimos '<div style="display:grid;grid-template-columns: 1fr 1fr 1fr;">' informamos que a linha deverá ser 'dividida' em 3 partes. Colocamos a seguir 3 itens e eles foram exibidos conforme demonstrado acima.

Note que o estilo display:grid não define o formato exato que deve ser dado as colunas do grid e quem faz isso são os parâmetros da tag que definem exatamente como o grid deve ser dividido.

Grid - Colunas - Desobedecendo as definições - A mais

Agora no exemplo acima uma quarta coluna... lembre-se que no container definimos 3 colunas. Como ela será exibida ?

Como é exibido

Item 1
Item 2
Item 3
Item 4

Como previsto, se o elemento não cabe na linha corrente ele é automaticamente deslocado para a linha de baixo. Este comportamento também irá acontecer caso a largura da tela do browser seja insuficiente para abrigar a largura mínima de cada elemento definido no grid. Por exemplo, defino que cada coluna tem 400 pixels de comprimento e ao exibir na tela o browser descobre que é um celular na vertical que só cabe 576 pixels de largura. Sendo assim ele colocará o primeiro elemento na linha corrente e os demais na linha seguinte.

Grid - Colunas - Desobedecendo as definições - A menos

Agora no exemplo lá de acima com 3 colunas retiramos uma coluna. Vai ficar um buraco ?

Como é exibido

Item 1
Item 2

Note como o tamanho das colunas fica constante sempre. Com isto vimos que uma vez definida na tag container o número de colunas a serem exibidas isto será obedecido a risca e sempre, cada coluna terá um tamanho fixo igual as demais colunas.

Definindo as linhas do Grid

Como dissemos acima a propriedade coluna do grid é o estilo Grid-Template-Columns. E o estilo que define as linhas é o Grid-Template-Rows.

Importante : Grid-Template-Rows define a altura dos itens no grid. Note que se não for definido a altura da linha será exatamente a necessária para o elemento ser exibido, ou seja, terá a altura do maior elemento da linha do grid.

O estilo mais usado na formatação do grid horizontalmente (rows) é a sua altura. Vamos supor que queremos que a altura seja de 100 px. Note também que manteremos a definição de colunas para podermos comparar o que o estilo row influência na tag.

Código

<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows:100px">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
</div>

Como é exibido

Item 1
Item 2
Item 3

O estilo grid-template-rows é muito importante quando colocamos imagens ou mesmo alinhar os itens ao centro do box do elemento.


Diferenciando uma linha da outra no mesmo Grid

Suponha agora que você tenha mais de uma linha no grid. A primeira linha tem um texto e a altura boa seria uns 50 pixels mas a segunda linha contém imagens e a altura ideal seria 150 pixels. Note que ambas as linhas terão o mesmo número de colunas (largura) mas a altura da primeira será menor que o da segunda. Vejamos como fica.

Código

<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows:50px 150px">
            <div class="item">Linha 1-Item 1</div>
            <div class="item">Linha 1-Item 2</div>
            <div class="item">Linha 1-Item 3</div>
            <div class="item">Linha 2-Item 1</div>
            <div class="item">Linha 2-Item 2</div>
            <div class="item">Linha 3-Item 3</div>
</div>

Como é exibido

Linha 1-Item 1
Linha 1-Item 2
Linha 1-Item 3
Linha 2-Item 1
Linha 2-Item 2
Linha 3-Item 3

O exemplo acima é muito utilizado quando desejamos 'alturas' diferentes para os elementos do mesmo grid. Note que se você colocar 2 grids juntos um com uma altura e outro com outra ficaria um espaçamento entre eles.

Linha 1-Item 1
Linha 1-Item 2
Linha 1-Item 3
Linha 1-Item 1
Linha 1-Item 2
Linha 1-Item 3

Temos jeitos de contornar esta questão de separação entre grids, mas não seria a maneira correta.


Espaçando elementos do Grid

Nos exemplos acima como eu defini border: 1px solid black; a região ocupada por cada elemento é bem definida. Pode ser que em certas ocasiões você deseje uma 'margem' ou 'espaçamento' entre cada elemento. Se desejar use o parâmetro gap.

Código

<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows:50px;gap:10px;">
            <div class="item">Linha 1-Item 1</div>
            <div class="item">Linha 1-Item 2</div>
            <div class="item">Linha 1-Item 3</div>
            <div class="item">Linha 2-Item 4</div>
            <div class="item">Linha 2-Item 5</div>
            <div class="item">Linha 3-Item 6</div>
</div>

Como é exibido

Linha 1-Item 1
Linha 1-Item 2
Linha 1-Item 3
Linha 2-Item 4
Linha 2-Item 5
Linha 3-Item 6

Note que o gap é retirado do espaço da segunda linha e isso torna o gap inimigo do segundo item. Se o gap é de 10 pixels é dada uma margem de 5px em volta de todo elemento. Sendo assim vamos contornar o problema aumentando a altura da segunda linha exatamente a metade do tamanho do gap.

Código

<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows:50px 55px;gap:10px;">
            <div class="item">Linha 1-Item 1</div>
            <div class="item">Linha 1-Item 2</div>
            <div class="item">Linha 1-Item 3</div>
            <div class="item">Linha 2-Item 4</div>
            <div class="item">Linha 2-Item 5</div>
            <div class="item">Linha 3-Item 6</div>
</div>

Como é exibido

Linha 1-Item 1
Linha 1-Item 2
Linha 1-Item 3
Linha 2-Item 4
Linha 2-Item 5
Linha 3-Item 6

No exemplo acima as 2 linhas agora tem a mesma altura graças ao aumento dado a altura da segunda linha...a primeira tem 50 pixels e a segunda 55 pixels. Raramente a gente usa isso, mas é bem conveniente saber dessa questão.


Simplificando a definição do Grid

A definição do grid até aqui não está complicada, mas você há de convir que 'style="display:grid;grid-template-columns: 1fr 1fr 1fr;"' parece meio repetitivo e não é o padrão do grid.

Sendo assim, o jeito comum de fazer isso é trocar o parâmetro 1fr pelo parâmetro repeat. O parâmetro repeat possui dois valores, o primeiro é o número de vezes e o segundo é a altura de cada coluna do grid. Vejamos como fica.

Código

<div style="display: grid; grid-template-columns: repeat(3,1fr);">
            <div class="item">Linha 1-Item 1</div>
            <div class="item">Linha 1-Item 2</div>
            <div class="item">Linha 1-Item 3</div>
</div>

Como é exibido

Linha 1-Item 1
Linha 1-Item 2
Linha 1-Item 3

Colocando o parâmetro 'grid-template-columns: repeat(3,1fr)' a exibição fica igual ao grid-template-columns: 1fr 1fr 1fr, mais sucinto quando a altura das colunas é a mesma para todos elementos do grid.


Definindo particularidades dentro de um elemento de um Grid - Largura

Até agora falamos do container do grid que define como seus elementos serão exibidos, mas e se quisermos que um elemento do grid seja exibido diferentemente do outro, ou seja, 'mesclado' como falamos no Excel ou que ocupe 2 ou mais colunas, 2 ou mais linhas, como isso será possível ?

Existe um parâmetro chamado 'grid-column' que permite 'mesclar' as colunas. No exemplo abaixo exibo 2 linhas..a primeira com 3 colunas como nos exemplos anteriores e a segunda 'expandindo a primeira coluna' por 2 colunas. Veja como fica.

Código

<div style="display: grid; grid-template-columns: repeat(3,1fr); grid-template-rows:50px;">
            <div class="item">Linha 1-Item 1</div>
            <div class="item">Linha 1-Item 2</div>
            <div class="item">Linha 1-Item 3</div>
            <div class="item" style="grid-column:1/3">Linha 2-Item 4</div>
            <div class="item">Linha 2-Item 5</div>
            <div class="item">Linha 2-Item 6</div>
</div>

Como é exibido

Linha 1-Item 1
Linha 1-Item 2
Linha 1-Item 3
Linha 2-Item 4
Linha 2-Item 5
Linha 2-Item 6

No exemplo acima na linha 2 definimos que o item 4 da linha 2 deveria começar na primeira coluna e terminar na terceira coluna e por esse motivo ele ocupou 2 itens do grid. O próximo item-5 coube na linha, mas o item-6 não coube na linha e por esse motivo foi exibido logo abaixo.

Como ficaria de ao invés de colocar no parâmetro style="grid-column:1/3 ( começa na coluna 1 e termina na 3) se eu colocasse na 2 e terminasse na 3 ???

Como é exibido

Linha 1-Item 1
Linha 1-Item 2
Linha 1-Item 3
Linha 2-Item 4
Linha 2-Item 5
Linha 2-Item 6

Doidera mas funciona. O item-4 começou na segunda coluna e foi até a terceira. O item-5 ainda coube na linha e foi exibido na linha o item-6 não coube e foi colocado na linha de baixo.


Definindo particularidades dentro de um elemento de um Grid - Altura

Acima vimos como o estilo style="grid-column:x/y" define a largura de um item do grid. Ainda temos o estilo style="grid-row:x/y" que pode 'mesclar' os itens do grid verticalmente definindo alturas diferenciadas para cada um deles.

Abaixo vou definir 2 linhas sendo que na primeira linha vou definir que o item1 ocupe 2 colunas e os demais nada de especial. Veja como fica.

Código

<div style="display: grid; grid-template-columns: repeat(3,1fr)">
            <div class="item" style="grid-column:1/3;grid-row:1/2">Linha 1-Item 1</div>
            <div class="item">Linha 1-Item 2</div>
            <div class="item">Linha 2-Item 1</div>
            <div class="item">Linha 2-Item 2</div>
            <div class="item">Linha 2-Item 3</div>
</div>

Como é exibido

Linha 1-Item 1
Linha 1-Item 2
Linha 2-Item 1
Linha 2-Item 2
Linha 2-Item 3

Note que para o estilo grid-row:1/2 funcionar você obrigatoriamente precisa do estilo grid-column:1/3; no mesmo item do grid.


Finalizando

Você pode combinar esses estilos do grid praticamente para fazer o mosaico que quiser, contudo raramente precisará fazer isso. Veja abaixo um exemplo interessante mixando todos esses 'estilos'.

Código

<style>
.item1 {
            grid-column: 1/3;
            grid-row: 1/2;
        }

        .item2 {
            grid-column: 3/4;
            grid-row: 1/3;
        }

        .item6 {
            grid-column: 2/4;
        }
</style>
<div class="grid-container">
            <div class="item item1">Item 1</div>
            <div class="item item2">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
            <div class="item item6">Item 6</div>
</div>

Como é exibido

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6

Imagine imagens e vídeos em cada um desses itens do grid...ficaria muito bom né ?