Miniaturas simplificadas com CSS3

Miniaturas simplificadas com CSS3

Perambulando pelos padrões da W3C, encontrei uma coisa bem interessante na especificação de imagens CSS3 — a mesma que define os gradientes. Trata-se do modo de definição de tamanhos para imagens com as propriedades CSS object-fit e object-position, o que achei bastante útil principalmente para quando precisamos construir miniaturas (thumbnails) para visualizar imagens. Abaixo temos uma mini galeria com algumas imagens.

OBS.: Para visualizar os resultados experimentados neste post, é preciso utilizar um navegador baseado na engine do Blink (Google Chrome ou Opera) — caso contrário, não fará o menos sentido ler este material sem ver os resultados.

Imagem 1Imagem 2Imagem 3Imagem 4Imagem 5Imagem 6Imagem 7Imagem 8

As miniaturas acima foram compostas apenas com o elemento <img>, ou seja, não foi preciso fazer uso de um elemento pai para servir de empacotador para a imagem — coisa que é muito comum na construção de miniaturas, costuma-se utilizar uma <div> com overflow: hidden e fazer o redimensionamento da imagem para acompanhar o tamanho da <div>.

<!-- Isso -->
<img class="galeria-img" src="einstein.jpg" alt="Einstein" />

<!-- Não isso -->
<div class="galeria-thumb">
    <img  class="galeria-img" src="einstein.jpg" alt="Einstein" />
</div>

Note que as quatro primeiras imagens são a mesma imagem, assim como as quatro últimas. A imagem do Einstein tem uma orientação de retrato (altura maior que largura), enquanto que a imagem do Chico Science tem uma orientação de paisagem (largura maior que altura).

object-fit

Cada uma das quatro ocorrências dessas imagens tem um comportamento diferente. Esse comportamento é definido através da propriedade object-fit, e com o uso dessa propriedade, fica visível que há uma separação entre o elemento invólucro (pai) e o conteúdo (bitmap) da imagem — o que já dá para perceber se utilizarmos a propriedade padding em uma imagem.

Então, o elemento <img> não é apenas um elemento, afinal de contas; mas pelo menos dois — assim como a maioria dos elementos HTML, afinal, a Shadow DOM está aí.

A propriedade object-fit define como o conteúdo da imagem é apresentado em relação ao seu elemento invólucro (elemento pai), e pode ter seu valor igual a fill, none, cover, contain ou scale-down. Para notar as diferenças do uso dessa propriedade, é necessário que a imagem em questão tenha altura e largura definidas. No nosso exemplo acima temos ambas as dimensões com 140 pixels:

.galeria-img {
    width: 140px;
    height: 140px;
}

Agora, vamos ao que interessa.

fill

Este é o valor padrão para object-fit. Para uma imagem com com altura e largura definidas, sua forma será achatada se a proporção resultante for diferente da original (comportamento padrão das imagens até então).

Imagem Original
Imagem original
Imagem com fill
140x140px com fill
.galeria-img {
    width: 140px;
    height: 140px;
    object-fit: fill;
}

none

Com none, não é realizado nenhum processamento na imagem, mas ela será “cropada” (crop) pelas dimensões definidas, ou seja, será renderizada com seu bitmap inalterado, porém cortado. Com um exemplo fica mais fácil de entender:

Imagem Original
Imagem original
Imagem com none
140x140px com none
.galeria-img {
    width: 140px;
    height: 140px;
    object-fit: none;
}

Agora, vejamos o que acontece quando uma das dimensões definidas excede sua correspondente original:

Imagem Original
Imagem original
Imagem com none
220x140px com none
.galeria-img {
    width: 220px;
    height: 140px;
    object-fit: none;
}

Como dito, nenhum processamento foi feito na imagem, e ela mantém seu tamanho original. Pode-se perceber também que, nesses dois exemplos, a imagem resultante foi posicionada de forma centralizada. Veremos isso mais adiante com a propriedade object-position.

cover

Igualmente a none, mantém a proporção original da imagem, porém faz um redimensionamento na imagem para que esta possa preencher toda a área definida pelas dimensões especificadas. A seguir temos o mesmo exemplo do caso anterior, a única coisa que muda é o valor de object-fit para cover.

Imagem Original
Imagem original
Imagem com cover
220x140px com cover
.galeria-img {
    width: 220px;
    height: 140px;
    object-fit: cover;
}

contain

Mantém a proporção original como em cover, mas faz um redimensionamento na imagem de modo que esta não seja cortada e seja mostrada completamente dentro da área definida pelas dimensões especificadas.

Imagem Original
Imagem original
Imagem com contain
140x140px com contain
.galeria-img {
    width: 140px;
    height: 140px;
    object-fit: contain;
}

scale-down

Esse é um valor que pode causar um pouco de confusão. Ele fará com que a imagem se comporte de dois jeitos diferentes, dependendo do seu tamanho. scale-down irá sempre se comportar igual a none ou contain. O comportamento resultante sempre será o que representar um menor tamanho de imagem desenhada — e isso dependerá das dimensões originais da imagem e das dimensões definidas para o elemento <img>. De novo, com um exemplo fica mais fácil:

Imagem Original
Imagem original
Imagem com scale-down
120x250px scale-down
Imagem com scale-down
200x250px com scale-down
.einstein-fit-1 {
    width: 120px;
    height: 250px;
    object-fit: scale-down;
}

.einstein-fit-2 {
    width: 200px;
    height: 250px;
    object-fit: scale-down;
}

Podemos perceber que nas duas imagens temos a mesma altura, e apenas mudamos a largura de um para o outro. No primeiro caso, scale-down se comporta como contain, pois none resultaria numa imagem maior. Já no segundo caso, temos o oposto, scale-down se comporta como none, pois contain resultaria numa imagem maior. Simples, não é?

object-position

O propósito de object-position é bem simples: posicionar o conteúdo da imagem dentro do emento <img>. O seu valor é definido exatamente da mesma maneira que a propriedade background-position. No exemplo a seguir temos imagens definidas com object-fit: cover e modificamos seu alinhamento vertical.

Imagem com cover
140x140px com cover
Imagem com cover
140x140px com cover no topo
Imagem com cover
140x140px com cover na base
.einstein-fit-1 {
    object-fit: cover;
    object-position: 50% 50%; /* valor padrão */
}

.einstein-fit-2 {
    object-fit: cover;
    object-position: 50% 0%; /* alinhada ao topo */
}

.einstein-fit-3 {
    object-fit: cover;
    object-position: 50% 100%; /* alinhada à base */
}

Agora, para ilustrar o alinhamento horizontal, no exemplo a seguir temos imagens definidas com object-fit: contain.

Imagem com contain
140x140px com contain
Imagem com contain
140x140px com contain no topo
Imagem com contain
140x140px com contain na base
.einstein-fit-1 {
    object-fit: contain;
    object-position: 50% 50%; /* valor padrão */
}

.einstein-fit-2 {
    object-fit: contain;
    object-position: 0% 50%; /* alinhada à esquerda */
}

.einstein-fit-3 {
    object-fit: contain;
    object-position: 100% 50%; /* alinhada à direita */
}

Claro que também é possível utilizar outras unidades como px, em, etc. e valores negativos também.

Ah, e mais uma coisinha…

As propriedades object-fit e object-position podem ser utilizadas também no elemento <video>, nos possibilitando realizar exatamente as mesmas configurações de estilos tanto para imagens quanto para vídeos.

Suporte

object-fit31------19
object-position31------19

Informações segundo o caniuse. Apenas o Google Chrome e o Opera dão suporte atualmente (logicamente, agora que o Opera também usa o Blink).

#65