Zoom de imagens em um layout de grade PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

Zoom de imagens em um layout de grade

Criar uma grade de imagens é fácil, graças ao CSS Grid. Mas fazer a grade fazer coisas extravagantes depois de as imagens foram colocadas pode ser difícil de retirar.

Digamos que você queira adicionar algum efeito de foco sofisticado às imagens onde elas crescem e ampliar além das linhas e colunas onde elas ficam? Nós podemos fazer isso!

Legal certo? Se você verificar o código, não encontrará nenhum JavaScript, seletores complexos ou mesmo números mágicos. E este é apenas um exemplo entre muitos que iremos explorar!

Construindo a grade

O código HTML para criar a grade é tão simples quanto uma lista de imagens dentro de um container. Não precisamos mais do que isso.

<div class="gallery">
  <img>
  <img>
  <img>
  <!-- etc. -->
</div>

Para o CSS, primeiro começamos definindo a grade usando o seguinte:

.gallery {
  --s: 150px; /* controls the size */
  --g: 10px;  /* controls the gap */

  display: grid;
  gap: var(--g);
  width: calc(3*var(--s) + 2*var(--g)); /* 3 times the size plus 2 times the gap */
  aspect-ratio: 1;
  grid-template-columns: repeat(3, auto);
}

Resumindo, temos duas variáveis, uma que controla o tamanho das imagens e outra que define o tamanho do gap entre as imagens. aspect-ratio ajuda a manter as coisas em proporção.

Você pode estar se perguntando por que estamos definindo apenas três colunas, mas nenhuma linha. Não, eu não esqueci as linhas - nós simplesmente não precisamos defini-las explicitamente. CSS Grid é capaz de colocar itens automaticamente em linhas e colunas implícitas, o que significa que obtemos quantas linhas forem necessárias para qualquer número de imagens que lançarmos nele. Podemos definir explicitamente as linhas, mas precisamos adicionar grid-auto-flow: column para garantir que o navegador crie as colunas necessárias para nós.

Aqui está um exemplo para ilustrar ambos os casos. A diferença é que um flui em um row direção um o outro em um column direção.

Dê uma olhada na este outro artigo que escrevi para saber mais sobre as grades implícitas e o algoritmo de posicionamento automático.

Agora que temos nossa grade, é hora de estilizar as imagens:

.gallery > img {
  width: 0;
  height: 0;
  min-height: 100%;
  min-width: 100%;
  object-fit: cover;
}

O efeito hover que estamos fazendo depende desse CSS. Provavelmente parece estranho para você que estamos fazendo imagens que não têm largura ou altura, mas têm largura e altura mínimas de 100%. Mas você verá que é um truque bem legal para o que estamos tentando alcançar.

O que estou fazendo aqui é dizer ao navegador que as imagens precisam ter 0 largura e altura, mas também precisam ter uma altura mínima igual a 100%… mas 100% sobre o que? Ao usar porcentagens, o valor é em relação a outra coisa. Neste caso, nossa imagem é colocada dentro de um célula de grade e precisamos saber esse tamanho para saber o que é 100% é relativo a.

O navegador irá primeiro ignorar min-height: 100% para calcular o tamanho das células da grade, mas usará o height: 0 em seu cálculo. Isso significa que nossas imagens não contribuirão para o tamanho das células da grade... porque tecnicamente elas não têm tamanho físico. Isso resultará em três colunas e linhas iguais baseadas no tamanho da grade (que definimos no .gallerylargura e aspect-ratio). A altura de cada célula da grade nada mais é do que a variável --s definimos (o mesmo para a largura).

Zoom de imagens em um layout de grade

Agora que temos as dimensões das células da nossa grade, o navegador irá usá-la com min-height: 100% (E min-width: 100%) que forçará as imagens a preencherem completamente o espaço de cada célula da grade. A coisa toda pode parecer um pouco confusa, mas a ideia principal é garantir que a grade defina o tamanho das imagens e não o contrário. Não quero que a imagem defina o tamanho da grade e você entenderá o porquê após adicionar o efeito hover.

Criando o efeito de foco

O que precisamos fazer é aumentar a escala das imagens ao passar o mouse. Podemos fazer isso ajustando a imagem width e height on :hover:

.gallery {
  --f: 1.5; /* controls the scale factor */
}

.gallery img:hover{
  width:  calc(var(--s) * var(--f));
  height: calc(var(--s) * var(--f));
}

Eu adicionei uma nova variável personalizada, --f, à mistura como um fator de escala para controlar o tamanho ao passar o mouse. Observe como estou multiplicando a variável size, --s, por ele para calcular o novo tamanho da imagem.

Mas você disse que o tamanho da imagem precisa ser 0. O que está acontecendo? Eu estou perdido…

O que eu disse ainda é verdade, mas estou abrindo uma exceção para a imagem pairada. Estou dizendo ao navegador que apenas uma imagem terá um tamanho diferente de zero - portanto, contribuirá para a dimensão da grade - enquanto todas as outras permanecerão iguais a 0.

Zoom de imagens em um layout de grade PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.
Zoom de imagens em um layout de grade

O lado esquerdo mostra a grade em seu estado natural sem nenhuma imagem em foco, que é o que o lado direito está mostrando. Todas as células da grade do lado esquerdo são iguais em tamanho, pois todas as imagens não têm dimensões físicas.

No lado direito, a segunda imagem na primeira linha passa o mouse, o que lhe dá dimensões que afetam o tamanho da célula da grade. O navegador tornará essa célula de grade específica maior ao passar o mouse, o que contribui para o tamanho geral. E como o tamanho de toda a grade está definido (porque definimos um valor fixo width na .gallery), as outras células da grade responderão logicamente tornando-se menores para manter a .gallerytamanho total do 's no tato.

Esse é o nosso efeito de zoom em ação! Ao aumentar o tamanho de apenas uma imagem, afetamos toda a configuração da grade, e dissemos antes que a grade define o tamanho das imagens para que cada imagem se estique dentro de sua célula da grade para preencher todo o espaço.

Para isso, adicionamos um toque de transition E use object-fit para evitar a distorção da imagem e a ilusão é perfeita!

Eu sei que a lógica por trás do truque não é fácil de entender. Não se preocupe se você não entender completamente. O mais importante é entender a estrutura do código usado e como modificá-lo para obter mais variações. É o que faremos a seguir!

Adicionando mais imagens

Criamos uma grade 3×3 para explicar o truque principal, mas você provavelmente adivinhou que não precisaríamos parar por aí. Podemos tornar variáveis ​​o número de colunas e linhas e adicionar quantas imagens quisermos.

.gallery {
  --n: 3; /* number of rows*/
  --m: 4; /* number of columns */
  --s: 150px; /* control the size */
  --g: 10px;  /* control the gap */
  --f: 1.5;   /* control the scale factor */

  display: grid;
  gap: var(--g);
  width:  calc(var(--m)*var(--s) + (var(--m) - 1)*var(--g));
  height: calc(var(--n)*var(--s) + (var(--n) - 1)*var(--g));
  grid-template-columns: repeat(var(--m),auto);
}

Temos duas novas variáveis ​​para o número de linhas e colunas. Em seguida, simplesmente definimos a largura e a altura de nossa grade usando-os. O mesmo para grid-template-columns que usa o --m variável. E, assim como antes, não precisamos definir explicitamente as linhas, pois o recurso de posicionamento automático do CSS Grid fará o trabalho para nós, não importa quantos elementos de imagem estamos usando.

Por que não valores diferentes para a largura e a altura? Nós podemos fazer isso:

.gallery {
  --n: 3; /* number of rows*/
  --m: 4; /* number of columns */
  --h: 120px; /* control the height */
  --w: 150px; /* control the width */
  --g: 10px;  /* control the gap */
  --f: 1.5;   /* control the scale factor */

  display: grid;
  gap: var(--g);
  width:  calc(var(--m)*var(--w) + (var(--m) - 1)*var(--g));
  height: calc(var(--n)*var(--h) + (var(--n) - 1)*var(--g));
  grid-template-columns: repeat(var(--m),auto);
}

.gallery img:hover{
  width:  calc(var(--w)*var(--f));
  height: calc(var(--h)*var(--f));
}

Nós substituímos --s com duas variáveis, uma para a largura, --w, e outro para a altura, --h. Então ajustamos todo o resto de acordo.

Então, começamos com uma grade com tamanho e número de elementos fixos, mas depois criamos um novo conjunto de variáveis ​​para obter qualquer configuração que desejarmos. Tudo o que temos a fazer é adicionar quantas imagens quisermos e ajustar as variáveis ​​CSS de acordo. As combinações são ilimitadas!

Que tal uma versão em tela cheia? Sim, isso também é possível. Tudo o que precisamos é saber quais valores precisamos atribuir às nossas variáveis. Se nós quisermos N linhas de imagens e queremos que nossa grade seja em tela cheia, primeiro precisamos resolver para uma altura de 100vh:

var(--n) * var(--h) + (var(--n) - 1) * var(--g) = 100vh

Mesma lógica para a largura, mas usando vw em vez de vh:

var(--m) * var(--w) + (var(--m) - 1) * var(--g) = 100vw

Fazemos as contas para obter:

--w: (100vw - (var(--m) - 1) * var(--g)) / var(--m)
--h: (100vh - (var(--n) - 1) * var(--g)) / var(--n)

Feito!

É exatamente o mesmo HTML, mas com algumas variáveis ​​atualizadas que alteram o tamanho e o comportamento da grade.

Observe que omiti a fórmula que definimos anteriormente no .gallery's width e height e os substituiu por 100vw e 100vh, respectivamente. A fórmula nos dará o mesmo resultado, mas como sabemos o valor que queremos, podemos descartar toda essa complexidade adicional.

Também podemos simplificar a --h e --w removendo a lacuna da equação em favor disso:

--h: calc(100vh / var(--n)); /* Viewport height divided by number of rows */
--w: calc(100vw / var(--m)); /* Viewport width divided by number of columns */

Isso fará com que a imagem pairada cresça um pouco mais do que no exemplo anterior, mas não é grande coisa, pois podemos controlar a escala com o --f variável que estamos usando como multiplicador.

E como as variáveis ​​são usadas em um só lugar, ainda podemos simplificar o código removendo-as completamente:

É importante observar que essa otimização se aplica apenas ao exemplo de tela inteira e não aos exemplos que abordamos. Este exemplo é um caso particular em que podemos tornar o código mais leve removendo parte do trabalho de cálculo complexo que precisávamos nos outros exemplos.

Na verdade, temos tudo o que precisamos para criar o padrão popular de painéis expansíveis:

Vamos cavar ainda mais fundo

Você notou que nosso fator de escala pode ser menor que 1? Podemos definir o tamanho da imagem pairada para ser menor do que --h or --w mas a imagem fica maior ao passar o mouse.

O tamanho inicial da célula da grade é igual a --w e --h, então por que valores menores tornam a célula da grade maior? A célula não deveria ficar menor, ou pelo menos manter seu tamanho inicial? E qual é o tamanho final da célula da grade?

Precisamos nos aprofundar em como o algoritmo CSS Grid calcula o tamanho das células da grade. E isso envolve entender o padrão do CSS Grid esticar alinhamento.

Aqui está um exemplo para entender a lógica.

No lado esquerdo da demo, defini duas colunas com auto largura. Obtemos o resultado intuitivo: duas colunas iguais (e duas células de grade iguais). Mas a grade que montei no lado direito da demo, onde estou atualizando o alinhamento usando place-content: start, parece não ter nada.

O DevTools ajuda a nos mostrar o que realmente está acontecendo em ambos os casos:

Zoom de imagens em um layout de grade PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.
Zoom de imagens em um layout de grade

Na segunda grade, temos duas colunas, mas suas larguras são iguais a zero, então obtemos duas células de grade que são recolhidas no canto superior esquerdo do contêiner da grade. Isto é não um bug, mas o resultado lógico do alinhamento da grade. Quando dimensionamos uma coluna (ou linha) com auto, significa que seu conteúdo determina seu tamanho — mas temos um vazio div sem conteúdo para abrir espaço.

Mas desde stretch é o alinhamento padrão e temos espaço suficiente dentro de nossa grade, o navegador irá esticar ambas as células da grade igualmente para cobrir toda essa área. É assim que a grade à esquerda termina com duas colunas iguais.

De a especificação:

Observe que alguns valores de justify-content e align-content pode fazer com que as faixas fiquem espaçadas (space-around, space-between, space-evenly) ou para ser redimensionado (stretch).

Observe o “a ser redimensionado” que é a chave aqui. No último exemplo, usei place-content que é a abreviatura para justify-content e align-content

E isso está enterrado em algum lugar o algoritmo de dimensionamento de grade especificações:

Esta etapa expande as faixas que têm um auto função de dimensionamento máximo da faixa dividindo qualquer positivo restante, definido espaço livre igualmente entre eles. Se o espaço livre for indeterminado, Mas o recipiente de grade tem uma definição min-largura/altura, use esse tamanho para calcular o espaço livre para esta etapa.

“Igualmente” explica por que acabamos com células de grade iguais, mas se aplica ao “espaço livre”, que é muito importante.

Vamos pegar o exemplo anterior e adicionar conteúdo a um dos divs:

Adicionamos um quadrado 50px imagem. Aqui está uma ilustração de como cada grade em nosso exemplo responde a essa imagem:

Zoom de imagens em um layout de grade PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.
Zoom de imagens em um layout de grade

No primeiro caso, podemos ver que a primeira célula (em vermelho) é maior que a segunda (em azul). No segundo caso, o tamanho da primeira célula muda para se ajustar ao tamanho físico da imagem enquanto a segunda célula permanece sem dimensões. O espaço livre é dividido igualmente, mas a primeira célula tem mais conteúdo dentro, o que a torna maior.

Esta é a matemática para descobrir nosso espaço livre:

(grid width) - (gap) - (image width) = (free space)
200px - 5px - 50px = 145px 

Dividido por dois - o número de colunas - obtemos uma largura de 72.5px para cada coluna. Mas adicionamos o tamanho da imagem, 50px, para a primeira coluna que nos deixa com uma coluna em 122.5px e o segundo igual a 72.5px.

A mesma lógica se aplica à nossa grade de imagens. Todas as imagens têm um tamanho igual a 0 (sem conteúdo) enquanto a imagem em foco contribui para o tamanho - mesmo que seja apenas 1px – tornando sua célula de grade maior que as outras. Por esta razão, o fator de escala pode ser qualquer valor maior que 0 mesmo decimais entre 0 e 1.

Para obter a largura final das células da grade, fazemos o mesmo cálculo para obter o seguinte:

(container width) - (sum of all gaps) - (hovered image width) = (free space)

A largura do contêiner é definida por:

var(--m)*var(--w) + (var(--m) - 1)*var(--g)

… e todas as lacunas são iguais a:

(var(--m) - 1)*var(--g)

… e para a imagem pairada temos:

var(--w)*var(--f)

Podemos calcular tudo isso com nossas variáveis:

var(--m)*var(--w) - var(--w)*var(--f) = var(--w)*(var(--m) - var(--f))

O número de colunas é definido por --m , então dividimos esse espaço livre igualmente para obter:

var(--w)*(var(--m) - var(--f))/var(--m)

…o que nos dá o tamanho das imagens não suspensas. Para imagens pairadas, temos isso:

var(--w)*(var(--m) - var(--f))/var(--m) + var(--w)*var(--f)
var(--w)*((var(--m) - var(--f))/var(--m) + var(--f))

Se quisermos controlar o tamanho final da imagem em foco, consideramos a fórmula acima para obter o tamanho exato que desejamos. Se, por exemplo, queremos que a imagem seja duas vezes maior:

(var(--m) - var(--f))/var(--m) + var(--f) = 2

Então, o valor do nosso multiplicador de escala, --f, deve ser igual a:

var(--m)/(var(--m) - 1)

Para três colunas teremos 3/2 = 1.5 e esse é o fator de escala que usei na primeira demonstração deste artigo porque queria tornar a imagem duas vezes maior ao passar o mouse!

A mesma lógica se aplica ao cálculo da altura e, caso queiramos controlar os dois de forma independente, precisaremos considerar dois fatores de escala para garantir que tenhamos uma largura e uma altura específicas ao passar o mouse.

.gallery {
  /* same as before */
   --fw: 1.5; /* controls the scale factor for the width */
   --fh: 1.2; /* controls the scale factor for the height */

  /* same as before */
}

.gallery img:hover{
  width:  calc(var(--w)*var(--fw));
  height: calc(var(--h)*var(--fh));
}

Agora, você conhece todos os segredos para criar qualquer tipo de grade de imagem com um efeito de foco legal e, ao mesmo tempo, controlar o tamanho desejado usando a matemática que acabamos de abordar.

Resumindo

Na nossa último artigo, criamos uma grade de aparência complexa com algumas linhas de CSS que usam a grade implícita e os recursos de posicionamento automático do CSS Grid. Neste artigo, contamos com alguns truques de dimensionamento de CSS Grid para criar uma grade sofisticada de imagens que ampliam o foco e fazem com que a grade se ajuste de acordo. Tudo isso com um código simplificado e fácil de ajustar usando variáveis ​​CSS!

No próximo artigo, vamos brincar com formas! Combinaremos a grade CSS com a máscara e o caminho do clipe para obter uma grade de imagens sofisticada.

Carimbo de hora:

Mais de Truques CSS