Curso de CSS / Imagens e vídeos responsivos com aspect-ratio e object-fit
Mídia responsiva precisa tanto de um dimensionamento sensato do elemento quanto de uma regra deliberada para ajustar seu conteúdo. aspect-ratio ajuda a estabelecer as proporções de uma caixa, enquanto object-fit: cover ou contain determina se uma imagem ou vídeo preenche ou se ajusta dentro dessa caixa.
Separe dimensões intrínsecas e tamanho de exibição
Se o original é 400×300, a proporção é 4:3. Se a largura de exibição é 288px e mantendo as mesmas proporções, a altura de exibição é 216px. Os atributos width e height do HTML fornecem informações sobre o tamanho e a proporção da imagem, e o CSS controla o tamanho a ser exibido na página. Em vez de resolver o problema removendo os atributos de dimensão do HTML, verifique qual valor está sendo sobrescrito no CSS.
img { max-width: 100%; height: auto; }
/* Instead of forcing the small original size to grow, it is reduced to fit the parent. */
max-width: 100% é um limite máximo que impede que fique mais largo que seu elemento pai e não aumenta incondicionalmente o tamanho original pequeno. width: 100% é uma especificação que preenche a largura do elemento pai, portanto, pode ser ampliada além do tamanho original. Clareza da foto e tamanho do arquivo para download são questões separadas. Você pode baixar arquivos grandes mesmo que pareçam pequenos com CSS, e quando você usar srcset · sizes, o navegador seleciona uma imagem entre as candidatas, então você deve verificar o tamanho de exibição na tela e o arquivo realmente selecionado.
Use aspect-ratio para dimensionamento automático
aspect-ratio: 16 / 9 usa a proporção de 16 de largura para 9 de altura para calcular o tamanho. Se a largura for 288px, a altura será 162px. Pelo menos um tamanho deve ser automático para que os cálculos proporcionais possam ser feitos, e se tanto a largura quanto a altura forem fixas, esse tamanho fixo terá precedência, mesmo se você inserir essa propriedade. Você também pode verificar as condições de cálculo de tamanho da proporção de aspecto do MDN.
.thumbnail { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }
O alinhamento do Flexbox, quebra de linha, espaço entre elementos (gap), crescimento (grow) e encolhimento (shrink) podem igualar a altura das imagens na mesma linha. Para calcular automaticamente a altura ao posicionar imagens com proporções originais diferentes lado a lado, verifique também o align-items: flex-start do elemento pai ou o align-self do item. Se a proporção parecer a mesma após alterar apenas a altura para auto, a regra de alinhamento do pai pode ser a causa.
Na prática, o box-sizing é unificado como border-box. Ao adicionar bordas ou padding, torna-se importante medir o tamanho e as proporções da caixa. As imagens nos exemplos de comparação abaixo não têm bordas nem padding para evitar confusão.
Compare o comportamento de ajuste e recorte
| valor do atributo | proporção original | área de exibição | detalhe |
|---|---|---|---|
| fill | Pode ser expandido para caber na área | Preenche a caixa | Distorção possível dependendo do original |
| cover | manter | Preencher sem espaço vazio | Se a proporção for diferente, algumas partes são cortadas. |
| contain | manter | Ajustar para caber tudo | Se a proporção for diferente, espaço vazio é deixado |
Ajustar uma imagem 4:3 em uma caixa 16:9 com cover corta suas partes superior e inferior. O posicionamento central divide o corte entre elas; object-position: center top preserva a parte superior e corta mais a parte inferior. Verifique o conteúdo importante nas bordas antes de escolher um corte. Fundos CSS usam escolhas de ajuste relacionadas, mas têm um papel diferente de conteúdo e acessibilidade em relação às imagens HTML. Veja Cores e imagens de fundo: cover e contain.
O esquema a seguir ilustra a mesma imagem de prática geométrica em sua proporção original, com cover, com contain e com cover alinhado ao topo. Compare as bordas verdes e vermelhas e o espaço vazio nas laterais. O círculo central permanece visível nesses exemplos, tornando as bordas mais fáceis de identificar. O exemplo completo em HTML abaixo permite que você reproduza a comparação.
Execute a comparação das quatro imagens
Salve como image-ratio.html e abra o arquivo. A imagem original está incluída como dados SVG dentro do arquivo, portanto nenhuma imagem externa é necessária. Os atributos width e height de cada imagem informam as dimensões originais de 400×300; o CSS define o tamanho e a proporção da caixa exibida.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>image-ratio.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 65rem); margin-inline: auto; padding: 1rem; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }
.sample { width: min(100%, 18rem); margin: 0; }
.sample img { display: block; width: 100%; height: auto; background: #e2e2e2; }
.sample p { margin: .5rem 0 0; } .cover, .contain { aspect-ratio: 16 / 9; }
.cover { object-fit: cover; } .contain { object-fit: contain; }
.top { object-position: center top; }
</style>
</head>
<body>
<main><h1>Compare the size and cropping of the same picture</h1><div class="gallery"><div class="sample"><img class="" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>Original 4:3</p></div>
<div class="sample"><img class="cover" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 cover, center</p></div>
<div class="sample"><img class="contain" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 contain</p></div>
<div class="sample"><img class="cover top" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 cover, top</p></div>
</div></main>
</body>
</html>
- Em telas largas, garanta que a largura de cada imagem seja limitada a 18rem. Com uma fonte raiz de 16px, isso equivale a 288px de largura, o original tem 216px de altura e as caixas 16:9 tem 162px de altura.
- Altere somente a altura de
.sample imgpara 300px. Mesmo que a proporção 16:9 seja aplicada, verifique se a área é 288×300px devido à altura fixa e restaure para auto. - Altere apenas o align-items de
.gallerypara stretch. Certifique-se de que a altura do contêiner da mesma linha seja a mesma, mas que as proporções da imagem dentro do contêiner sejam mantidas, e retorne para flex-start. Neste exemplo, o item Flex é um contêiner de exemplo, não uma imagem. Em configurações onde imagens são colocadas diretamente como itens Flex, a altura automática pode aumentar, então o alinhamento deve ser verificado. - Altere apenas object-position de
.toppara center bottom. Desta vez, certifique-se de que a faixa vermelha permaneça e a faixa verde seja cortada, e então restaure-a para center top.
O SVG no exemplo também tem a característica de manter as proporções das formas. Se a área de exibição de um elemento de imagem estiver incorreta e criar espaço vazio, o círculo não será necessariamente distorcido. Em vez de apenas olhar a forma, verifique a largura e altura do elemento img nas ferramentas de desenvolvedor.
Ajuste o tamanho do conteúdo de vídeo dentro da sua caixa de exibição
No exercício abaixo, um vídeo silencioso de 400×300 criado para esta lição é exibido com object-fit: contain em uma área 16:9. Não há informações de áudio ou legenda no vídeo, apenas o movimento do círculo laranja, que é usado para verificar os espaços superior, inferior e laterais, bem como as operações de reprodução. O endereço do arquivo de vídeo WebM para prática está incluído no exemplo. Para usar o exemplo depois sem rede, baixe antes este arquivo e coloque-o na mesma pasta do HTML, substituindo o endereço de origem pelo nome do arquivo.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>video-ratio.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 34rem); margin-inline: auto; padding: 1rem; }
video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; background: #111; }
</style>
</head>
<body>
<main><h1>Video display ratio</h1>
<p id="video-description">This silent sample video shows an orange circle moving on a blue background. Play and pause it to compare aspect ratios.</p>
<video controls preload="metadata" width="400" height="300" aria-describedby="video-description">
<source src="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm" type="video/webm">
<a href="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm">Download the sample video</a>
</video></main>
</body>
</html>
controls permite que o usuário use operações do navegador, como play/pause, e preload="metadata" é uma dica que solicita que as informações de metadados sejam lidas antes da reprodução. O método de download real é determinado pelo seu navegador. Como não incluímos autoplay, pressione o botão de play para confirmar. Se você mudar apenas object-fit para cover, poderá ver a diferença, pois a área permanece a mesma e o conteúdo na parte superior e inferior é cortado. Após a confirmação, restaure para contain.
object-fit ajusta o conteúdo em elementos substituídos, como imagens e vídeos. Ele não dimensiona o conteúdo do iframe de um vídeo incorporado da mesma maneira: dê a esse iframe um contêiner com proporção adequada e dimensione-o dentro do contêiner. Ao contrário deste exemplo decorativo silencioso, um vídeo com áudio significativo precisa de alternativas apropriadas, como legendas. Veja MDN: object fit, MDN: video.





