CSS Grid intrinsecamente responsiva com minmax() e min()

Já ouviu falar de intrinsic web design? Veja como é possível fazer CSS Grid intrinsecamente responsiva de maneira (relativamente) fácil!

Ir para o artigo

CSS Grid já é amplamente suportado em navegadores modernos, e muitas pessoas estão trabalhando muito bem com a real tecnologia de layouts para a Web!

Mas, infelizmente, um dos recursos mais úteis da especificação não funciona como anunciado, a intrinsically responsive grid ou grid intrinsecamente responsiva — quer dizer, uma grid responsiva com base no tamanho de seu contêiner, sem o uso de media queries.

Mas, graças a alguns padrões que agora estão disponíveis em alguns navegadores e a caminho de outros, é possível contornar essa limitação!

Mas antes de explicar a solução, vamos revisar o problema. Com CSS Grid, é possível criar uma grid de itens organizados em colunas de tamanhos iguais e solicitar que os tamanhos das colunas sejam ajustados com base na quantidade de espaço disponível:

See the Pen Responsive Grid with Minimum Container Size by Evan (@vamptvo) on CodePen.

Se quiser ter uma visão melhor do quê realmente o exemplo oferece, abra o pen diretamente no seu navegador e redimensione o tamanho da viewport.

Essa técnica usa vários recursos da especificação de CSS Grid:

  • repeat() diz ao Grid para criar várias tracks com os mesmos parâmetros de tamanho (não necessariamente o mesmo tamanho, embora, neste caso, todos acabem sendo os mesmos).
  • auto-fill diz para criar quantas tracks forem necessárias para preencher o espaço.
  • minmax(10rem, 1fr) serve para determinar o tamanho de cada track, encontrando um valor entre um mínimo de 10rem e um máximo de 1fr (a unidade fr é o que garante que as tracks cresçam para preencher qualquer espaço restante).

Graças a tudo isso, o contêiner adiciona novas colunas à medida que cresce. Um recurso principal desta solução é que as colunas mudam com base no tamanho do contêiner, não no tamanho da viewport, sempre parecerá correto, sem a necessidade de media queries substituindo o comportamento padrão em páginas específicas.

Mas, então, qual é o problema?

Responsivo… Mas nem tanto

Como cada grid track tem um tamanho mínimo de 10rem, elas não podem encolher abaixo desse tamanho. Isso significa que, quando o container é menor que esse tamanho, vai ocorrer overflow com seus gris items!

Para arrumar isso, será preciso colocar a declaração de grid-template-columns em uma media query:

See the Pen Responsive Grid with Media Query by Evan (@vamptvo) on CodePen.

Mas, agora que estamos na área de media queries, a grid só muda quando a viewport é pequena. Não seria recomendado colocá-la dentro de um contêiner pequeno ou se entraria novamente no problema de overflow.

Felizmente, com algumas novas adições às especificações de CSS que começaram a chegar nos navegadores, é possível corrigir esse problema, permitindo que CSS Grid aproveite todo o seu potencial como uma ferramenta para intrinsic web design.

Grid intrinsecamente responsiva

O exemplo anterior teve problemas porque acontecia a definição de um valor fixo como o tamanho mínimo da track.Quando o tamanho do contêiner diminuiu, os itens não diminuíram com ele e, portanto: overflow.

Mas e se fosse possível definir um tamanho mínimo que encolheria com base no tamanho do contêiner, garantindo que as tracks nunca fossem grandes demais para o contêiner?

Por sorte, é possível fazer exatamente isso com a ajuda da função min():

min() aceita um ou mais valores e retorna o menor valor. A mágica da função é que, assim como calc(), os argumentos podem usar unidades diferentes, o que permite retornar valores que mudam dinamicamente com base no contexto. Neste caso, retornando a largura atual do contêiner, limitada no valor máximo de 10rem.

min() é uma das 3 novas funções de comparação introduzidas como parte de CSS Values and Units Module Level 4. Também há max() — que, naturalmente, faz o inverso de min() — e clamp() — uma função de conveniência que aplica ambos um mínimo e um máximo para um único valor.

Neste exemplo, há 2 casos com os quais é preciso atenção, e min() resolve ambos.

Quando o contêiner é menor que 10rem, o valor mínimo na expressão minmax() é definido como a largura total do contêiner, fornecendo uma bela exibição de coluna única sem overflow.

Quando o contêiner é maior que 10rem, o valor mínimo é definido como 10rem, que garante uma grid responsiva com tracks iguais a pelo menos 10rem cada.

CSS Grid intrinsecamente responsiva no mundo real

Se você está pensando “Isso parece legal e tudo mais, mas ainda não é possível usar em projetos de verdade”, você tem apenas metade da razão.

min() não é muito bem suportado, mas está disponível em pelo menos um navegador: o Safari implementou silenciosamente min() e max() algumas versões anteriores! Infelizmente, ainda não há nada sobre clamp() ainda, mas é possível simulá-la usando as outras duas.

Além disso, a Tab Atkins anunciou recentemente que o suporte ao Chrome está a caminho. Se você deseja acompanhar o suporte ao navegador, o CanIUse possui uma página para as 3 funções.

Contadas as boas novas, aqui está uma versão funcional do código acima (abra no Safari para ver funcionando direitinho):

See the Pen Fully Responsive Grid (Safari-Only) by Evan (@vamptvo) on CodePen.

Com essa falta de suporte amplo, por enquanto, é possível colocá-lo em camadas no código existente usando progressive enhancement. Algo mais ou menos como:

See the Pen Fully Responsive Grid (with Fallback) by Evan (@vamptvo) on CodePen.

Aqui, usou-se calc() como fallback. A parte principal é o calc(10% + 7.5rem), que combina um mínimo fixo com uma largura percentual. Ao calcular o mínimo com base em ambos, o limite é reduzido para disparar o overflow. Agora, ele será acionado quando o contêiner for um pouco maior que 7.5rem, enquanto, na solução anterior, ele seria acionado a 10rem.

Essa solução é um pouco complicada, portanto, convém ajustar a porcentagem e os valores fixos para se adequar ao design de suas próprias grids.

Com isso como alternativa, é possível tirar proveito da capacidade do CSS de substituir declarações de propriedade duplicadas, declarando novamente grid-template-columns. Browsers que suportam min() — na data de publicação deste artigo, o Safari — obterão a solução totalmente responsiva, enquanto Chrome, Firefox, Edge e outros receberão o fallback.

À medida que mais navegadores adicionam suporte a min(), eles alternam automaticamente para o novo layout.

Conclusão

As funções min(), max() e clamp() são ferramentas realmente poderosas, permitindo alternar entre valores em tempo real com base nas condições de mudança.

Ser capaz de testá-los em um navegador real abre muitas oportunidades de exploração, e tudo indica que essa pequena correção para o CSS Grid está apenas arranhando a superfície das muitas maneiras pelas quais os desenvolvedores poderemos esses recursos daqui para frente.

E você, já viu algum exemplo incrível de CSS Grid intrinsecamente responsiva que usa min(), max() e clamp()?

E-book com 10 dicas para montar seu portfolio altamente eficiente e conseguir muito mais clientes e projetos!

Download GRÁTIS