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 de10rem
e um máximo de1fr
(a unidadefr
é 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()
:
1 |
grid-template-columns: repeat(auto-fill, minmax(min(10rem, 100%), 1fr)); |
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()
?