CSS Container Queries ainda estão ganhando força e muitos de nós estamos começando a mexer com elas, mesmo que seja para pequenos experimentos ou outros enfeites. Eles estão ótimos, mas não totalmente cheios, suporte ao navegador — o suficiente para justificar o uso deles em alguns projetos, mas talvez não a ponto de ficarmos tentados a começar a substituí-los consultas de mídia de projetos anteriores com novas e brilhantes consultas de tamanho de contêiner.
Eles com certeza são úteis embora! Na verdade, já me deparei com algumas situações em que realmente queria alcançá-los, mas simplesmente não conseguia superar os requisitos de suporte. Se eu pudesse usá-los, seria assim nessas situações.
Todas as demonstrações a seguir serão melhor visualizadas no Chrome ou Safari no momento em que este livro foi escrito. O Firefox planeja suporte de navio na versão 109.
Caso 1: grade de cartas
Você meio que esperava por este, certo? É um padrão tão comum que todos nós parecemos nos deparar com ele em algum momento. Mas o fato é que as consultas de tamanho de contêiner teriam economizado muito tempo para mim com um resultado melhor se eu pudesse usá-las em consultas de mídia padrão.
Digamos que você tenha sido encarregado de construir esta grade de cartão com o requisito de que cada cartão precisa manter sua proporção de 1:1:
É mais difícil do que parece! O problema é que dimensionar o conteúdo de um componente na largura da viewport deixa você à mercê de como o componente responde à viewport — bem como de qualquer outro contêiner ancestral responde a ele. Se, por exemplo, você quiser que o tamanho da fonte de um cabeçalho de cartão reduza quando o cartão atingir um determinado tamanho embutido, não há uma maneira confiável de fazer isso.
Você pode definir o tamanho da fonte em vw
unidades, suponho, mas o componente ainda está vinculado à largura da janela de visualização do navegador. E isso pode causar problemas quando a grade do cartão é usada em outros contextos que podem não ter os mesmos pontos de interrupção.
Em meu projeto do mundo real, cheguei a uma abordagem de JavaScript que:
- Ouça um evento de redimensionamento.
- Calcule a largura de cada cartão.
- Adicione um tamanho de fonte embutido a cada cartão com base em sua largura.
- Estilize tudo dentro usando
em
unidades.
Parece muito trabalho, certo? Mas é uma solução estável para obter o dimensionamento necessário em diferentes tamanhos de tela em diferentes contextos.
As consultas de contêiner teriam sido muito melhores porque nos fornecem unidades de consulta de contêiner, tais como o cqw
unidade. Você provavelmente já entendeu, mas 1cqw
é igual a 1%
da largura de um contêiner. Nós também temos o cqi
unidade que é uma medida da largura em linha de um contêiner e cqb
para a largura do bloco de um contêiner. Então, se tivermos um recipiente de cartão que é 500px
largo, um 50cqw
valor computa para 250px
.
Se eu pudesse usar consultas de contêiner em minha grade de cartão, poderia configurar o .card
componente como um contêiner:
.card {
container: card / size;
}
Então eu poderia ter definido um invólucro interno com padding
que escala em 10%
da .card
largura usando o cqw
unidade:
.card__inner {
padding: 10cqw;
}
Essa é uma boa maneira de dimensionar o espaçamento entre as bordas do cartão e seu conteúdo de forma consistente, independentemente de onde o cartão é usado em qualquer largura da janela de visualização. Não são necessárias consultas de mídia!
Outra ideia? Usar cqw
unidades para o tamanho da fonte do conteúdo interno e, em seguida, aplique preenchimento em em
unidades:
.card__inner {
font-size: 5cqw;
padding: 2em;
}
5cqw
é um valor arbitrário - apenas um que eu estabeleci. Esse preenchimento ainda é igual a 10cqw
uma vez que o em
unidade é relativa ao .card__inner
tamanho da fonte!
Você pegou isso? o 2em
é relativo ao 5cqw
tamanho da fonte definido no mesmo recipiente. Os contêineres funcionam de maneira diferente do que estamos acostumados, pois em
as unidades são relativas ao mesmo elemento font-size value
. Mas o que notei rapidamente é que as unidades de consulta de contêiner se relacionam com o pai mais próximo que também é um contêiner.
Por exemplo, 5cqw
não escala com base no .card
largura do elemento neste exemplo:
.card {
container: card / size;
container-name: card;
font-size: 5cqw;
}
Em vez disso, ele é dimensionado para qualquer pai mais próximo definido como um contêiner. Por isso montei um .card__inner
embrulho.
Caso 2: layout alternado
Eu precisava de outro componente de cartão em um projeto diferente. Desta vez, eu precisava que o cartão fizesse a transição de um layout de paisagem para um layout de retrato… depois de volta para paisagem e de volta para retrato novamente conforme a tela fica menor.
Eu fiz o trabalho sujo de fazer este componente ir para retrato naqueles dois intervalos de viewport específicos (grite para o nova sintaxe de intervalo de consulta de mídia!), mas, novamente, o problema é que ele é bloqueado para as consultas de mídia definidas nele, seu pai e qualquer outra coisa que possa responder à largura da janela de visualização. Queremos algo que funcione em qualquer condição sem nos preocuparmos em saber onde o conteúdo vai quebrar!
Consultas de contêiner teriam facilitado isso, graças ao @container
regra:
.info-card {
container-type: inline-size;
container-name: info-card;
}
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
Uma consulta, fluidez infinita:
Mas espere! Há algo que você pode querer observar. Especificamente, pode ser difícil usar uma consulta de contêiner como essa em um sistema de design baseado em prop. Por exemplo, este .info-card
O componente pode conter componentes filhos que dependem de props para alterar sua aparência.
Por que isso é importante? O layout de retrato do cartão pode exigir o estilo alternativo, mas você não pode alterar os adereços JavaScript com CSS. Assim, você corre o risco de duplicar os estilos necessários. Na verdade, eu toquei nisso e como contornar isso em outro artigo. Se você precisar usar consultas de contêiner para uma quantidade significativa de seu estilo, talvez seja necessário basear todo o seu sistema de design em torno delas, em vez de tentar encaixá-las em um sistema de design existente que é pesado em consultas de mídia.
Caso 3: traços SVG
Aqui está outro padrão super comum que usei recentemente, em que as consultas de tamanho de contêiner resultariam em um produto mais polido. Digamos que você tenha um ícone bloqueado com um título:
Heading
É bastante simples dimensionar o ícone com o tamanho do título, mesmo sem consultas de mídia. O problema, porém, é que os formatos SVG stroke-width
pode ficar muito fino para ser notado tão bem em um tamanho menor e talvez chamar muita atenção com um traço super grosso em um tamanho maior.
Tive que criar e aplicar classes a cada instância de ícone para determinar seu tamanho e largura do traçado. Tudo bem se o ícone estiver ao lado de um cabeçalho estilizado com um tamanho de fonte fixo, eu acho, mas não é tão bom ao trabalhar com tipo fluido que muda constantemente.
O tamanho da fonte do título pode ser baseado na largura da janela de visualização, portanto, o ícone SVG precisa ser ajustado de acordo onde seu traço funciona em qualquer tamanho. Você pode fazer a largura do traço em relação ao cabeçalho font-size
ao configurá-lo em em
unidades. Mas se você tiver um conjunto específico de tamanhos de traçado que precisa seguir, isso não funcionaria porque, de outra forma, é dimensionado linearmente - não há como ajustá-lo a um determinado stroke-width
valor em determinados pontos sem recorrer a consultas de mídia na largura da janela de visualização.
Mas aqui está o que eu teria feito se tivesse o luxo de fazer consultas de contêiner naquela época:
.icon {
container: icon / size;
width: 1em;
height: 1em;
}
.icon svg {
width: 100%;
height: 100%;
fill: none;
stroke: #ccc;
stroke-width: 0.8;
}
@container icon (max-width: 70px) {
.icon svg {
stroke-width: 1.5;
}
}
@container icon (max-width: 35px) {
.icon svg {
stroke-width: 3;
}
}
Compare as implementações e veja como a versão de consulta do contêiner encaixa o traço do SVG nas larguras específicas que desejo com base na largura do contêiner.
Bônus: outros tipos de consultas de tamanho de contêiner
OK, então eu realmente não encontrei isso em um projeto real. Mas enquanto vasculhava as informações sobre consultas de contêiner, notei que há coisas adicionais que podemos consultar em um contêiner relacionadas ao tamanho ou às dimensões físicas do contêiner.
A maioria dos exemplos que vi consultam o width
, max-width
e min-width
, height
, block-size
e inline-size
como tenho feito ao longo deste artigo.
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
BUT MDN descreve mais duas coisas podemos consultar. Um é orientation
o que faz todo o sentido porque o usamos o tempo todo em media queries. Não é diferente com consultas de contêiner:
@media screen (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
@container info-card (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
O outro? Isso é aspect-ratio
, Acredite ou não:
@container info-card (aspect-ratio: 3/2) {
.info-card__inner {
/* Style away! */
}
}
Aqui está uma demonstração editável para brincar com os dois exemplos:
Ainda não encontrei um bom caso de uso para nenhum deles. Se você tiver alguma ideia ou sentir que poderia ter ajudado em seus projetos, deixe-me saber nos comentários!