CSS grid: isso muda tudo de novo

CSS grid: isso muda tudo de novo

Atenção, se você tem problemas cardíacos, melhor não ler este post, pois seu conteúdo é altamente empolgante e pode ser perigoso principalmente para pessoas hipertensas.

Este conteúdo foi abordado em nossa palestra CSS Layout: o ontem, o hoje e o depois, juntamente com o Flexbox, as Exclusions, as Shapes, as Regions, o Box Model e as Tabelas.

Não confundir

Quando falo de CSS Grid Layout, não estou falando sobre como desenvolver sistemas de grids, tais como o do Bootstrap ou Foundation. CSS Grid Layout é uma novíssima  especificação W3C (ainda em andamento) que propõe uma nova maneira de “leiautar” na Web. Dentre suas várias vantagens, CSS grid é muito mais simples e fácil de usar que o atual e mais conhecido modelo Box model.

Quem se lembra?

Quem é das antigas lembra que os layouts de páginas eram feitos geralmente com <table>, ou seja, o site inteiro era um grande tabelão, e isso sem contar com as tabelas aninhadas.

Algo como o site da BOL em 2000 (olhem o código fonte, eu mesmo achei tabelas aninhadas em 3 níveis).

Depois das tabelas, surgiu o Tableless, que é uma metodologia de construção de layouts que sugere a utilização do box model — e não mais as tabelas — para layouts. Mas isso tudo, é claro que vocês já sabiam.

CSS Grid

Com as grids CSS será possível definir o nosso espaço em tela em regiões. Estas regiões poderão ser flexíveis de várias maneiras, de acordo com a situação.

Independência estrutural = liberdade

Similarmente às tabelas, as regiões de uma grid são definidas através de linhas e colunas, mas diferente das tabelas, não dependemos de elementos HTML para isto, ou seja, toda a definição da grid e de como seu conteúdo deverá se organizar no layout é feito apenas via CSS — tornando enfim a apresentação de conteúdo independente de marcações estruturais.

Crie a grid

Antes de tudo, é preciso declarar que um elemento em seu CSS será uma grid. Podemos fazer isso definindo a propriedade display com o valor grid. Simples.

OBS.: Irei utilizar IDs para o CSS apenas porque acho mais didático, mas não façam isso em casa, usem classes (se não, o titio Bernard briga).

display: grid
#container {
    display: grid;
}

Depois, só precisamos executar 2 passos:

  1. Definir as regiões da grid;
  2. Associar o conteúdo à grid.

1. Defina as regiões

Para definir as regiões da nossa grid, utilizaremos as novas propriedades grid-template-rows e grid-template-columns, que definem nada mais nada menos que as linhas e colunas da nossa grid.

regiões da grid
#container {
    display: grid;
    grid-template-rows: auto auto;
    grid-template-columns: auto auto auto;
}

No trecho acima, estamos definindo 2 linhas de altura automática (auto auto) e 3 colunas também de largura automática (auto auto auto). Com isso teremos como resultado uma grid com 6 regiões — exatamente da mesma maneira que seria com as tabelas. Podemos também definir as dimensões com qualquer unidade CSS (px, em, %, ex, pt, etc).

Regiões flexíveis com fr

Eis uma nova unidade CSS: fr (free space) é uma unidade flexível, e que representa uma determinada fração do espaço livre de uma grid. fr funciona de forma similar às unidades flexíveis da especificação Flexbox.

Para que uma região possa ocupar todo o espaço horizontal livre, por exemplo, podemos especificar sua coluna com 1fr — que nesse caso representará 100% do espaço horizontal livre:

regiões flexíveis
#container {
    /* ... */
    grid-template-columns: auto auto 1fr;
}

A mesma coisa para a coluna do meio:

regiões flexíveis 2
#container {
    /* ... */
    grid-template-columns: auto 1fr auto;
}

Se quisermos que o espaço livre seja dividido igualmente entre mais colunas, basta atribuir o mesmo valor a elas (1fr):

regiões flexíveis 3
#container {
    /* ... */
    grid-template-columns: auto 1fr 1fr;
}

Para que uma coluna tenha o dobro da outra (ou qualquer outra proporção), os valores serão calculados proporcionalmente de acordo com suas definições. No exemplo abaixo, as colunas 2 e 3 ocupam todo o espaço livre, de modo que a coluna 3 tenha o dobro da largura da coluna 2.

regiões flexíveis 4
#container {
    /* ... */
    grid-template-columns: auto 1fr 2fr;
}

E é claro, tudo isso pode também ser aplicado às alturas das linhas:

regiões flexíveis 5
#container {
    /* ... */
    grid-template-rows: 1fr 1fr;
}

2. Associe o conteúdo

Até aqui, tudo bem, grid definida e pronta para uso, mas não está faltando algo? Sim, falta algo bem importante: o conteúdo. Tudo isso que fizemos até agora foi apenas a definição de uma grid vazia. Agora é preciso jogar nosso conteúdo lá dentro.

Preste atenção neste HTML

Vamos utilizar este mesmo trecho de HTML abaixo durante todo o resto deste post, isto é, sem modificá-lo.

<div id="page-container">
    <header id="page-header"> ... </header>
    <nav id="page-menu"> ... </nav>
    <section id="page-content"> ... </section>
    <footer id="page-footer"> ... </footer>
</div>

Seja a grid definida da seguinte maneira:

grid content
#page-container {
    display: grid;
    grid-template-columns: 300px 500px;
    grid-template-rows: 150px auto 200px;
}

É preciso decidir qual conteúdo X vai estar localizado na região Y, e para isso vamos utilizar as novas propriedades grid-row, grid-row-start, grid-row-end, grid-column, grid-column-start e grid-column-end.

grid content
#page-header {
    grid-row: 1;
    grid-column-start: 1;
    grid-column-end: 2;
}

#page-menu {
    grid-row: 2;
    grid-column: 1;
}

#page-content {
    grid-row: 2;
    grid-column: 2;
}

#page-footer {
    grid-row: 3;
    grid-column: 1 / 2;
}

grid-row-start|end e grid-column-start|end

Podemos especificar como um determinado conteúdo vai se comportar numa grid fazendo span entre suas regiões (colspan feelings?).

  • grid-row-start e grid-row-end: linhas de onde começa e termina o conteúdo.
  • grid-column-start e grid-column-end: colunas de onde começa e termina o conteúdo.

No trecho CSS acima, #page-header está localizado na linha 1, começando na coluna 1 e se estendendo pela coluna 2.

grid-row e grid-column

Há duas possibilidades para utilizar estas propriedades:

  1. Definir a linha/coluna;
  2. Definir o começo e término da linha/coluna (sendo assim um atalho para start e end).

Por exemplo, no trecho CSS acima, #page-footer está localizado na linha 3 (começo e término), começando na coluna 1 e se estendendo pela coluna 2.

É importante notar que aqui fizemos apenas associações de 1 para 1. Mas nada impede de termos associações de N para 1, ou seja, vários conteúdos sendo colocados na mesma região.

Templates nomeados, a cereja do bolo

Já que vimos como criar grids e como associar conteúdo, agora vamos aprender a fazer tudo isso novamente, só que de uma maneira mais bonita, por assim dizer.

Com o intuito de facilitar nossa vida (ainda mais), é possível definir uma grid com nomes — em vez de números — através da propriedade grid-template-areas.

grid template
#container {
    display: grid;
    grid-template-areas: "cabecalho cabecalho"
                         "menu conteudo"
                         "rodape rodape";
}

O uso de grid-template-areas é bem simplificado, basta definirmos uma string para cada linha, e dentro de cada string definimos um identificador para cada região, separados por espaço em branco.

Dessa maneira, definimos uma grid de forma mais visual e sem a necessidade de usar as duas propriedades grid-template-rows e grid-template-columns.

O legal dessa abordagem é que ela já torna mais fácil de fazer span de regiões, perceba que as regiões cabecalho e rodape fazem span nas duas colunas presentes da grid. E isso é facilmente alcançado apenas repetindo o mesmo nome da região em suas adjacências.

Associando conteúdo like a boss

Para associar o conteúdo com esta abordagem de templates nomeados, usaremos a propriedade grid-area, e não precisaremos mais das propriedades grid-row e grid-column:

#page-header  { grid-area: cabecalho; }
#page-menu    { grid-area: menu; }
#page-content { grid-area: conteudo; }
#page-footer  { grid-area: rodape; }

Muito simples, não?

Templates responsivos

Que tal tornar responsivo o layout de uma aplicação do jeito mais fácil possível? Com os templates nomeados e media queries, isso se torna muito fácil. Vamos implementar agora um layout mobile simples para nossa grid:

grid template responsivo
/* definição normal da grid */
#container {
    display: grid;
    grid-template-areas: "cabecalho cabecalho"
                         "menu conteudo"
                         "rodape rodape";
}

#page-header  { grid-area: cabecalho; }
#page-menu    { grid-area: menu; }
#page-content { grid-area: conteudo; }
#page-footer  { grid-area: rodape; }

/* definição responsiva da grid */
@media screen and (max-device-width: 800px), screen and (max-width: 800px) {
    #container {
        grid-template-areas: "cabecalho"
                             "conteudo"
                             "rodape";
    }

    #page-menu { grid-area: cabecalho; } /* reassocia o conteúdo a outra região */
}

E voilà! Mudamos praticamente todo o layout sem precisar mexer numa cacetada de propriedades. Perceba que a região menu deixou de existir, então se ainda quisermos exibir o conteúdo de #page-menu, será preciso associá-lo a outra região — no nosso caso, o menu foi para a região cabecalho.

Acredite, é apenas isso. Não esqueça que o resto do conteúdo já está associado às suas respectivas regiões, de modo que não precisamos mais nos preocupar com isso.

Quer mais? Então pega!

Há ainda muita coisa sobre esta especificação, como alinhamento vertical e horizontal automático de conteúdo, regiões fluidas, reordenação de conteúdo com order, grids implícitas com linhas e colunas automáticas, subgrids, inline grids, etc. Decidi não discorrer sobre nenhum desses assuntos pois o post já se encontra demasiado grande, mas caso queira saber mais, clique aqui.

Suporte

Grid Layout box model------10* -ms---
* parcialmente implementado

Esse é o momento em que todo mundo fala: Só o IE? O que será que está acontecendo com este mundo? Pois é, amigos, apenas o IE é que dá suporte à partir da sua versão 10 (ainda que seja parcial). E se você usa Windows e tem o IE10 — ou IE11 —, pode testar a CSS Grid com esse experimento!

#54