Manter a proporção de uma div com CSS

1058

Quero criar um divque possa alterar sua largura / altura conforme a largura da janela for alterada.

Existem regras CSS3 que permitam alterar a altura de acordo com a largura, mantendo a proporção ?

Eu sei que posso fazer isso via JavaScript, mas eu preferiria usar apenas CSS.

div mantendo a proporção de acordo com a largura da janela

jackb
fonte
3
Eu escrevi sobre diferentes abordagens para esse em meu artigo CSS-Tricks em escala animações sensíveis
Zach Saucier
2
Cheguei a esta sessão de perguntas e respostas muito tarde, mas devo comentar. Embora seja muito disciplinado e dentro das regras de SO de todos que responderem para fazer o possível para atender à demanda "única CSS" da pergunta, é bastante surpreendente que, com a exceção da resposta do usuário007 , na parte inferior da página, alguém mencionou o óbvio: não existe uma solução confiável apenas para CSS, esse problema requer Javascript. Um novato que chega a esta página pode perder um tempo valioso alternando de um conjunto de prós / contras para outro antes que a lâmpada se apague: apenas o CSS não funciona.
Theo d'Or
1
Eu escrevi uma pequena ferramenta que facilita a visualização e o cálculo de proporções, aspectrat.io . Ele também gera o código CSS / Sass / Less apropriado que você pode copiar e colar em seus projetos. Espero que as pessoas achem útil.
Ryan Hefner
veja este exemplo: w3schools.com/howto/howto_css_aspect_ratio.asp ..... que me funcionou
Cristian Agudelo
1
Esta pergunta é para definir a altura com base na largura . Se você precisar do contrário, consulte Configuração da largura do elemento com base na altura via CSS .
John Mellor

Respostas:

1353

Basta criar um wrapper <div>com um valor percentual para padding-bottom, assim:

div {
  width: 100%;
  padding-bottom: 75%;
  background: gold; /** <-- For the demo **/
}

/* demonstration purposed only : non-essential */
.demoWrapper {
  padding: 10px;
  background: white;
  box-sizing: border-box;
  resize: horizontal;
  border: 1px dashed;
  overflow: auto;
  max-width: 100%;
  height: calc(100vh - 16px);
}
<div class="demoWrapper">
  <div></div>
</div>

Isso resultará em uma <div>altura igual a 75% da largura do seu contêiner (uma proporção de 4: 3).

Isso se baseia no fato de que, para o preenchimento:

A porcentagem é calculada com relação à largura do bloco contendo as caixas geradas (fonte: w3.org , ênfase minha)

Valores do fundo de preenchimento para outras proporções e largura de 100%:

aspect ratio  | padding-bottom value
--------------|----------------------
    16:9      |       56.25%
    4:3       |       75%
    3:2       |       66.66%
    8:5       |       62.5%

Colocando conteúdo na div:

Para manter a proporção da div e impedir que seu conteúdo a estique, é necessário adicionar um filho absolutamente posicionado e esticá-lo às bordas do invólucro com:

div.stretchy-wrapper {
  position: relative;
}

div.stretchy-wrapper > div {
  position: absolute;
  top: 0; bottom: 0; left: 0; right: 0;
}

Aqui está uma demonstração e outro mais em profundidade de demonstração

Web designer
fonte
29
@schellmax, é porque o% de preenchimento é calculado em relação à largura do elemento atual, enquanto que% em altura é calculado em relação à altura do elemento pai. Além disso, as posições absolutas são calculadas em relação ao contêiner externo de um elemento, o que inclui a área de preenchimento. Para mais informações: Google "CSS Box Model"
Anson Kao
11
Isso não parece funcionar de maneira aninhada. Ele funciona no primeiro nível, mas ao tentar fazer a mesma coisa dentro da div, mantendo a proporção, a porcentagem de preenchimento parece ser aplicada à largura do pai. Aqui está um exemplo em que a parte inferior do preenchimento .stretchy-wrap.onethird de 25% é na verdade 25% da largura pai. Alguém pode explicar isso?
Misterparker
4
Totalmente incrível. Está me matando que essa técnica não funcione quando você quiser fixar a altura em 100%. @Misterparker, a técnica baseia-se nos cálculos de largura e preenchimento sendo executados na mesma referência; você não pode usar uma largura menor que 100%, como no seu exemplo.
Steveuscher
2
@Misterparker Sim, o percentual de preenchimento é calculado proporcionalmente à largura do elemento pai. Veja o exemplo mais detalhado que publiquei em uma edição da minha resposta. Minha demo atualizada demonstra uma 'moda aninhada' como você estava falando.
Web_Designer
3
o fato de ele ter demonstrado que isso funciona é suficiente para me convencer de que esta é a melhor resposta já vista no SO. gritar para o meu homem @Web_Designer
410

vw unidades:

Você pode usar vwunidades para a largura e a altura do elemento. Isso permite que a proporção do elemento seja preservada, com base na largura da janela de exibição.

vw: 1/100 da largura da janela de visualização. [ MDN ]

Como alternativa, você também pode usar vhpara a altura da janela de exibição, ou mesmo vmin/ vmaxpara usar as dimensões menor / maior da janela de visualização (discussão aqui ).

Exemplo: proporção de aspecto 1: 1

div {
  width: 20vw;
  height: 20vw;
  background: gold;
}
<div></div>

Para outras proporções, você pode usar a tabela a seguir para calcular o valor da altura de acordo com a largura do elemento:

aspect ratio  |  multiply width by
-----------------------------------
     1:1      |         1
     1:3      |         3
     4:3      |        0.75
    16:9      |       0.5625

Exemplo: grade 4x4 de divs quadrados

body {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
div {
  width: 23vw;
  height: 23vw;
  margin: 0.5vw auto;
  background: gold;
}
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>

Aqui está um Fiddle com esta demonstração e aqui está uma solução para criar uma grade de quadrados responsiva com conteúdo centralizado na vertical e na horizontal .


O suporte do navegador para unidades vh / vw é o IE9 +, consulte canIuse para obter mais informações

web-tiki
fonte
14
Essa deve ser a resposta aceita. Talvez não agora, mas no futuro. As unidades vw são suportadas na maioria dos navegadores agora .
agosto
3
@vivekmaharajh ambas as técnicas são boas, cada uma tem seus próprios prós e contras. Usar um ou outro depende muito da situação.
Web-tiki
11
@ web-tiki, você está certo. Eu deparei com um problema - ele assume que a largura do elemento é proporcional à largura da janela de visualização, o que não será o caso se 1) você tiver coisas como calhas de largura fixa ou 2) você tiver a largura máxima definida para alguns de seus elementos.
Vivek Maharajh
1
Talvez seja apenas o Chrome v47beta, mas quando defino a div como width:50%e height:50vwa altura é um pouco mais alta que a largura, portanto não é exatamente uma proporção de 1: 1. Alguma ideia?
thdoan
2
@ 10basetom é um comportamento normal. unidades vw contêm a largura da barra de rolagem, enquanto% width não. A diferença entre altura e largura dependerá do tamanho da barra de rolagem, que será diferente dependendo do navegador.
Web-tiki
26

Encontrei uma maneira de fazer isso usando CSS, mas você deve ter cuidado, pois isso pode mudar dependendo do fluxo do seu próprio site. Eu fiz isso para incorporar vídeo com uma proporção constante dentro de uma parte de largura de fluido do meu site.

Digamos que você tenha um vídeo incorporado como este:

<object>
     <param ... /><param ... />...
     <embed src="..." ...</embed>
</object>

Você pode colocar tudo isso dentro de uma div com uma classe "video". Essa classe de vídeo provavelmente será o elemento fluido em seu site, de modo que, por si só, não possui restrições diretas de altura, mas quando você redimensiona o navegador, sua largura muda de acordo com o fluxo do site. Esse seria o elemento em que você provavelmente está tentando obter o vídeo incorporado, mantendo uma certa proporção do vídeo.

Para fazer isso, coloquei uma imagem antes do objeto incorporado na classe "video" div.

!!! O importante é que a imagem tenha a proporção correta que você deseja manter. Além disso, verifique se o tamanho da imagem é PELO MENOS do tamanho mínimo que você espera que o vídeo (ou seja o que você estiver mantendo o AR) seja baseado no seu layout. Isso evitará possíveis problemas na resolução da imagem quando ela for redimensionada em porcentagem. Por exemplo, se você deseja manter uma proporção de 3: 2, não use apenas uma imagem de 3 x 2 x. Pode funcionar em algumas circunstâncias, mas ainda não testei, e provavelmente seria uma boa ideia evitar.

Você provavelmente já deve ter uma largura mínima como essa definida para elementos fluidos do seu site. Caso contrário, é uma boa idéia fazê-lo para evitar o corte de elementos ou a sobreposição quando a janela do navegador ficar muito pequena. É melhor ter uma barra de rolagem em algum momento. A menor largura que uma página da Web deve ter fica em torno de ~ 600px (incluindo qualquer coluna de largura fixa) porque as resoluções de tela não são menores, a menos que você esteja lidando com sites amigáveis ​​por telefone. !!!

Eu uso um png completamente transparente, mas eu realmente não acho que isso acabe importando se você fizer certo. Como isso:

<div class="video">
     <img class="maintainaspectratio" src="maintainaspectratio.png" />
     <object>
          <param ... /><param ... />...
          <embed src="..." ...</embed>
     </object>
</div>

Agora você deve poder adicionar CSS semelhante ao seguinte:

div.video { ...; position: relative; }
div.video img.maintainaspectratio { width: 100%; }
div.video object { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; }
div.video embed {width: 100%; height: 100%; }

Também remova qualquer declaração explícita de altura ou largura no objeto e nas tags de incorporação que geralmente vêm com o código de incorporação de copiar / colar.

A maneira como funciona depende das propriedades de posição do elemento da classe de vídeo e o item que você deseja manter uma certa proporção. Aproveita a maneira como uma imagem mantém sua proporção adequada quando redimensionada em um elemento. Ele informa o que mais estiver no elemento de classe de vídeo para tirar o máximo proveito do espaço fornecido pela imagem dinâmica, forçando sua largura / altura a 100% do elemento de classe de vídeo sendo ajustado pela imagem.

Muito legal, né?

Talvez você precise brincar um pouco para fazer funcionar com seu próprio design, mas isso realmente funciona surpreendentemente bem para mim. O conceito geral está lá.

renunciar
fonte
17

Elliot me inspirou a esta solução - obrigado:

aspectratio.png é um arquivo PNG completamente transparente com o tamanho da sua proporção preferida, no meu caso, 30x10 pixels.

HTML

<div class="eyecatcher">
  <img src="/img/aspectratio.png"/>
</div>

CSS3

.eyecatcher img {
  width: 100%;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-image: url(../img/autoresized-picture.jpg);
}

Observe: background-size é um recurso css3 que pode não funcionar com os navegadores de destino. Você pode verificar a interoperabilidade (fe em caniuse.com ).

Florian Breisch
fonte
14

Para adicionar à resposta do Web_Designer, <div>ele terá uma altura (totalmente composta pelo preenchimento inferior) de 75% da largura do elemento que o contém . Aqui está um bom resumo: http://mattsnider.com/css-using-percent-for-margin-and-padding/ . Não sei por que isso deve ser assim, mas é assim que é.

Se você deseja que sua div tenha uma largura diferente de 100%, você precisa de outra div de quebra automática para definir a largura:

div.ar-outer{
    width: 60%; /* container; whatever width you want */
    margin: 0 auto; /* centered if you like */
}
div.ar {
    width:100%; /* 100% of width of container */
    padding-bottom: 75%; /* 75% of width of container */
    position:relative;
}
div.ar-inner {
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
}

Recentemente, usei algo semelhante ao truque de imagem de Elliot para me permitir usar consultas de mídia CSS para exibir um arquivo de logotipo diferente, dependendo da resolução do dispositivo, mas ainda dimensionar proporcionalmente como <img>faria naturalmente (defino o logotipo como imagem de plano de fundo em um arquivo transparente .png com a proporção correta). Mas a solução do Web_Designer me salvaria de uma solicitação http.

nabrown
fonte
Ótima solução. No meu caso, conheço o tamanho da imagem "natural" ao colocá-lo no DOM e preciso ter um espaço reservado para a imagem com a altura adequada para evitar rolagem adicional assim que o navegador carregar as imagens. Em .ar-outer eu tenho a largura da imagem em pixels, em .ar eu tenho o fundo de preenchimento calculado a partir da proporção real da imagem. Em vez de ar-inner, tenho a própria imagem (<img>). No entanto, tive que definir a largura para 100% em vez de definir a parte superior, inferior, esquerda e direita. Quando defino maxWidth como ar-outer, a imagem é dimensionada perfeitamente quando o pai é pequeno, mas não é dimensionado para um tamanho maior que o tamanho natural.
Mi-La
13

Conforme declarado aqui no w3schools.com e um pouco reiterado nesta resposta aceita , preenchimento de valores como porcentagens (ênfase minha):

Especifica o preenchimento em porcentagem da largura do elemento que contém

Portanto, um exemplo correto de um DIV responsivo que mantém uma proporção de 16: 9 é o seguinte:

CSS

.parent {
    position: relative;
    width: 100%;
}
.child {
    position: relative;
    padding-bottom: calc(100% * 9 / 16);
}
.child > div {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}

HTML

<div class="parent">
    <div class="child">
        <div>Aspect is kept when resizing</div>
    </div>
</div>

Demo no JSFiddle

Marc A
fonte
13

Como o @ web-tiki já mostra uma maneira de usar vh/ vw, eu também preciso de uma maneira de centralizar na tela, aqui está um código para o retrato 9:16 .

.container {
  width: 100vw;
  height: calc(100vw * 16 / 9);
  transform: translateY(calc((100vw * 16 / 9 - 100vh) / -2));
}

translateYmanterá esse centro na tela. calc(100vw * 16 / 9)altura prevista para 16/09. (100vw * 16 / 9 - 100vh)é a altura do estouro, portanto, puxe para cima overflow height/2o manterá centralizado na tela.

Para paisagem, e mantenha 16: 9 , você mostra uso

.container {
  width: 100vw;
  height: calc(100vw * 9 / 16);
  transform: translateY(calc((100vw * 9 / 16 - 100vh) / -2));
}

A proporção 9/16 é fácil de alterar, sem necessidade de predefinições 100:56.25ou 100:75. Se você deseja garantir a altura primeiro, deve alterar a largura e a altura, por exemplo, height:100vh;width: calc(100vh * 9 / 16)para 9:16 em retrato.

Se você deseja se adaptar a diferentes tamanhos de tela, também pode interessar

  • capa em tamanho de plano de fundo / conter
    • O estilo acima é semelhante a conter, depende da proporção largura: altura.
  • ajuste de objeto
    • cobrir / conter para tag img / video
  • @media (orientation: portrait)/@media (orientation: landscape)
    • Consulta de mídia para portrait/ landscapepara alterar a proporção.
Wener
fonte
11

Esta é uma melhoria na resposta aceita:

  • Usa pseudo-elementos em vez de divs de wrapper
  • A proporção é baseada na largura da caixa em vez de no pai
  • A caixa se estenderá verticalmente quando o conteúdo ficar mais alto

.box {
  margin-top: 1em;
  margin-bottom: 1em;
  background-color: #CCC;
}

.fixed-ar::before {
  content: "";
  float: left;
  width: 1px;
  margin-left: -1px;
}
.fixed-ar::after {
  content: "";
  display: table;
  clear: both;
}

.fixed-ar-16-9::before {
  padding-top: 56.25%;
}
.fixed-ar-3-2::before {
  padding-top: 66.66%;
}
.fixed-ar-4-3::before {
  padding-top: 75%;
}
.fixed-ar-1-1::before {
  padding-top: 100%;
}

.width-50 {
  display: inline-block;
  width: 50%;
}
.width-20 {
  display: inline-block;
  width: 20%;
}
<div class="box fixed-ar fixed-ar-16-9">16:9 full width</div>
<hr>
<div class="box fixed-ar fixed-ar-16-9 width-50">16:9</div>
<hr>
<div class="box fixed-ar fixed-ar-16-9 width-20">16:9</div>
<div class="box fixed-ar fixed-ar-3-2 width-20">3:2</div>
<div class="box fixed-ar fixed-ar-4-3 width-20">4:3</div>
<div class="box fixed-ar fixed-ar-1-1 width-20">1:1</div>
<hr>
<div class="box fixed-ar fixed-ar-16-9 width-20">16:9</div>
<div class="box fixed-ar fixed-ar-16-9 width-50">16:9</div>

Salman A
fonte
como desativar o alongamento vertical da caixa? Estritamente falando uma div alongamento não manter sua relação de aspecto
Florian
Se o conteúdo for mais alto que a altura esperada, a caixa será esticada verticalmente. Essa idéia é melhor usada com conteúdo que pode se estender para corresponder às dimensões de seus pais, por exemplo, vídeo e imagens.
Salman A
10

Eu me deparei com uma solução inteligente usando <svg>e display:grid.

O elemento de grade permite que você ocupe o mesmo espaço com dois (ou mais) elementos, sem precisar especificar qual define a altura. O que significa que, fora da caixa, o mais alto define a proporção .

Isso significa que você pode usá-lo como está quando sabe que o conteúdo nunca será alto o suficiente para preencher toda a "proporção" e você está simplesmente procurando uma maneira de posicionar o conteúdo nesse espaço (ou seja, para centralizá-lo nas duas direções) display:flex; align-items:center; justify-content:center)
É praticamente o mesmo que usar um transparente <img>com display:blocke proporção pré-determinada, exceto o <svg>é mais leve e consideravelmente mais fácil de modificar (para alterar a relação responsavelmente, caso você precise).

<div class="ratio">
  <svg viewBox="0 0 1 1"></svg>
  <div>
    I'm square
  </div>
</div>
.ratio {
  display: grid;
}
.ratio > * {
  grid-area: 1/1/1/1;
}

Tudo que você precisa fazer é alterar a <svg>proporção s:

  • <svg viewBox="0 0 4 3"></svg>
  • <svg viewBox="0 0 16 9"></svg>

Veja trabalhando:


Se você precisar de uma solução em que o elemento de conteúdo não tenha permissão para definir a proporção quando for mais alto (com estouro oculto ou automático), será necessário definir position:relativena grade e position:absolute; height:100%; overflow-y: auto;no conteúdo. Exemplo:

tao
fonte
9

Baseando-se em suas soluções, fiz alguns truques:

Quando você o usa, seu HTML será apenas

<div data-keep-ratio="75%">
    <div>Main content</div>
</div>

Para usá-lo desta forma, faça: CSS:

*[data-keep-ratio] {
    display: block;
    width: 100%;
    position: relative;
}
*[data-keep-ratio] > * {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
}

e js (jQuery)

$('*[data-keep-ratio]').each(function(){ 
    var ratio = $(this).data('keep-ratio');
    $(this).css('padding-bottom', ratio);
});

E tendo isso, você acabou de definir attr data-keep-ratiopara height / width e pronto .

pie6k
fonte
3
você deve usar data-keep-rationão keep-ratioe obtê-lo de valor usando$(this).data('keep-ratio');
Robert
seu código está funcionando agora e talvez funcione para sempre, mas não é padrão, e os navegadores podem parar de suportá-lo a qualquer momento no futuro #
Robert Robert
1
Usar JS aqui causará más notícias!
Amir Hossein Ahmadi
8

Você pode usar um svg. Torne a posição do contêiner / invólucro relativa, coloque o svg primeiro como estático e depois coloque o conteúdo absolutamente posicionado (em cima: 0; esquerda: 0; direita: 0; embaixo: 0;)

Exemplo com proporções 16: 9:

image.svg: (pode ser destacado em src)

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 9" width="16" height="9"/>

CSS:

.container {
  position: relative;
}
.content {
  position: absolute;
  top:0; left:0; right:0; bottom:0;
}

HTML:

<div class="container">
  <img style="width: 100%" src="image.svg" />
  <div class="content"></div>
</div>

Observe que o svg embutido não parece funcionar, mas você pode codificar o svg com url e incorporá-lo no atributo img src da seguinte forma:

<img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%209%22%20width%3D%2216%22%20height%3D%229%22%2F%3E" style="width: 100%;" />
Maciej Krawczyk
fonte
7

SCSS é a melhor solução no meu caso; usando um atributo de dados:

[data-aspect-ratio] {
    display: block;
    max-width: 100%;
    position: relative;

    &:before {
        content: '';
        display: block;
    }

    > * {
        display: block;
        height: 100%;
        left: 0;
        position: absolute;
        top: 0;
        width: 100%;
    }
}
[data-aspect-ratio="3:1"]:before {
    padding-top: 33.33%;
}
[data-aspect-ratio="2:1"]:before {
    padding-top: 50%;
}
[data-aspect-ratio="16:9"]:before {
    padding-top: 56.25%;
}
[data-aspect-ratio="3:2"]:before {
    padding-top: 66.66%;
}
[data-aspect-ratio="4:3"]:before {
    padding-top: 75%;
}
[data-aspect-ratio="1:1"]:before {
    padding-top: 100%;
}
[data-aspect-ratio="3:4"]:before {
    padding-top: 133.33%;
}
[data-aspect-ratio="2:3"]:before {
    padding-top: 150%;
}
[data-aspect-ratio="9:16"]:before {
    padding-top: 177.77%;
}
[data-aspect-ratio="1:2"]:before {
    padding-top: 200%;
}
[data-aspect-ratio="1:3"]:before {
    padding-top: 300%;
}

Por exemplo :

<div data-aspect-ratio="16:9"><iframe ...></iframe></div>

fonte

gordie
fonte
15
Apenas para sua informação ... Você pode fazer exatamente isso (usando seletores de atributos) exatamente na mesma quantidade de linhas usando CSS simples. O [data-aspect-ratio]seletor de atributos está disponível para você em CSS.
Rnevius 23/10/2015
6

Embora a maioria das respostas seja muito interessante, a maioria delas exige que uma imagem já esteja dimensionada corretamente ... Outras soluções funcionam apenas com uma largura e não se importam com a altura disponível, mas às vezes você também deseja ajustar o conteúdo em uma determinada altura. .

Eu tentei juntá-los para criar uma solução totalmente portátil e redimensionável ... O truque é usar o dimensionamento automático de uma imagem, mas usar um elemento svg embutido em vez de usar uma imagem pré-renderizada ou qualquer forma de segunda solicitação HTTP ...

div.holder{
  background-color:red;
  display:inline-block;
  height:100px;
  width:400px;
}
svg, img{
  background-color:blue;
  display:block;
  height:auto;
  width:auto;
  max-width:100%;
  max-height:100%;
}
.content_sizer{
  position:relative;
  display:inline-block;
  height:100%;
}
.content{
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  right:0;
  background-color:rgba(155,255,0,0.5);
}
<div class="holder">
  <div class="content_sizer">
    <svg width=10000 height=5000 />
    <div class="content">
    </div>
  </div>
</div>

Observe que eu usei grandes valores nos atributos width e height do SVG, pois ele precisa ser maior que o tamanho máximo esperado, pois só pode encolher. O exemplo faz com que a proporção da div 10: 5

Salketer
fonte
4

Apenas uma ideia ou um truque.

div {
  background-color: blue;
  width: 10%;
  transition: background-color 0.5s, width 0.5s;
  font-size: 0;
}

div:hover {
  width: 20%;
  background-color: red;
}
  
img {
  width: 100%;
  height: auto;
  visibility: hidden;
}
<div>
  <!-- use an image with target aspect ratio. sample is a square -->
  <img src="http://i.imgur.com/9OPnZNk.png" />
</div>

orlland
fonte
Esta não é uma solução apenas para CSS ... Agora, se você usasse uma imagem codificada em base64 em um pseudo-elemento, essa seria uma solução interessante.
Rnevius
1
Realmente não existe uma solução apenas para CSS. HTML é o componente básico da web. Acredito que o objetivo da pergunta é abster-se de usar o JS, talvez, para economizar recursos / processamento.
orlland
Não tenho certeza se o pseudo elemento funcionará. Utilizei a propriedade de elemento img para manter sua proporção para que esta solução funcionasse.
orlland
Bom, mas calcula uma altura apenas quando a largura muda. Deve ser feito nos dois sentidos; assim, quando reduzo a altura, a largura também é recalculada. Caso contrário, é inútil ..
egamega 29/01
4

digamos que você tenha 2 divs, a div externa é um contêiner e o interno pode ser qualquer elemento necessário para manter sua proporção (img ou iframe do youtube ou o que for)

html é assim:

<div class='container'>
  <div class='element'>
  </div><!-- end of element -->

digamos que você precise manter a proporção do "elemento"

relação => 4 para 1 ou 2 para 1 ...

css se parece com isso

.container{
  position: relative;
  height: 0
  padding-bottom : 75% /* for 4 to 3 ratio */ 25% /* for 4 to 1 ratio ..*/

}

.element{
  width : 100%;
  height: 100%;
  position: absolute; 
  top : 0 ;
  bottom : 0 ;
  background : red; /* just for illustration */
}

preenchimento, quando especificado em%, é calculado com base na largura e não na altura. .. então basicamente você não importa qual a sua largura e altura será sempre calculada com base nisso. o que manterá a proporção.

Ahmed Eid
fonte
4

Eu já tive esse problema algumas vezes, então criei uma solução JS para ele. Isso basicamente ajusta a altura do domElement de acordo com a largura do elemento pela proporção que você especificar. Você pode usá-lo da seguinte maneira:

<div ratio="4x3"></div>

Esteja ciente de que, uma vez que está definindo a altura do elemento, o elemento deve ser um display:blockou display:inline-block.

https://github.com/JeffreyArts/html-ratio-component

user007
fonte
1
Embora eu não tenha visto ou tentado seu código (já tenho o meu), votei sua resposta apenas pelo fato de você apresentar a única solução confiável, um script JS.
Theo d'Or
A pergunta pediu especificamente uma solução que não precisasse de Javascript.
Flimm
4

Se você deseja ajustar um quadrado dentro da viewport na vista retrato ou paisagem (o maior possível, mas nada aparecendo lá fora), alterne entre usar vw/ vhna orientação portrait/ landscape:

@media (orientation:portrait ) {
  .square {
    width :100vw;
    height:100vw;
  }
} 
@media (orientation:landscape) {
  .square {
    width :100vh;
    height:100vh;
  }
} 
MoonLite
fonte
4

Gostaria de compartilhar minha solução, na qual tenho uma imgtag preenchendo uma determinada proporção. Eu não poderia usar backgroundpor causa da falta de apoio da CMS e eu não prefiro usar uma marca de estilo assim: <img style="background:url(...)" />. Além disso, a largura é 100%, portanto, não precisa ser definida em um tamanho fixo, como em algumas das soluções. Ele será dimensionado responsivamente!

.wrapper {
  width: 50%;
}

.image-container {
  position: relative;
  width: 100%;
}

.image-container::before {
  content: "";
  display: block;
}

.image-container img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ratio-4-3::before {
  padding-top: 75%;
}

.ratio-3-1::before {
  padding-top: calc(100% / 3);
}

.ratio-2-1::before {
  padding-top: 50%;
}
<div class="wrapper"> <!-- Just to make things a bit smaller -->
  <p>
  Example of an 4:3 aspect ratio, filled by an image with an 1:1 ratio.
  </p>
  <div class="image-container ratio-4-3"> <!-- Lets go for a 4:3 aspect ratio -->
    <img src="https://placekitten.com/1000/1000/" alt="Kittens!" />
  </div>
  <p>
  Just place other block elements around it; it will work just fine.
  </p>
</div>

LaVomit
fonte
3

Você pode conseguir isso usando SVG.

Depende de um caso, mas em alguns é realmente útil. Como exemplo - você pode definir background-imagesem definir a altura fixa ou usá-lo para incorporar o youtube <iframe>com proporção 16:9e position:absoluteetc.

Para a 3:2relação definida viewBox="0 0 3 2"e assim por diante.

Exemplo:

div{
    background-color:red
}
svg{
    width:100%;
    display:block;
    visibility:hidden
}

.demo-1{width:35%}
.demo-2{width:20%}
<div class="demo-1">
  <svg viewBox="0 0 3 2"></svg>
</div>

<hr>

<div class="demo-2">
  <svg viewBox="0 0 3 2"></svg>
</div>

Jakub Muda
fonte
3

Uma maneira simples de manter a proporção, usando o elemento canvas.

Tente redimensionar a div abaixo para vê-la em ação.

Para mim, essa abordagem funcionou melhor, por isso estou compartilhando com outras pessoas para que elas também possam se beneficiar.

.cont {
  border: 5px solid blue;
  position: relative;
  width: 300px;
  padding: 0;
  margin: 5px;
  resize: horizontal;
  overflow: hidden;
}

.ratio {
  width: 100%;
  margin: 0;
  display: block;
}

.content {
  background-color: rgba(255, 0, 0, 0.5);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
}
<div class="cont">
  <canvas class="ratio" width="16" height="9"></canvas>
  <div class="content">I am 16:9</div>
</div>

Também funciona com altura dinâmica!

.cont {
  border: 5px solid blue;
  position: relative;
  height: 170px;
  padding: 0;
  margin: 5px;
  resize: vertical;
  overflow: hidden;
  display: inline-block; /* so the div doesn't automatically expand to max width */
}

.ratio {
  height: 100%;
  margin: 0;
  display: block;
}

.content {
  background-color: rgba(255, 0, 0, 0.5);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
}
<div class="cont">
  <canvas class="ratio" width="16" height="9"></canvas>
  <div class="content">I am 16:9</div>
</div>

Gbr22
fonte
yup ajudou-me, agora posso usá-lo para configurar a imagem div div altura)
Alex
2

Diga que você gosta de manter Width: 100px e Height: 50px (ou seja, 2: 1) Basta fazer este cálculo:

.pb-2to1 {
  padding-bottom: calc(50 / 100 * 100%); // i.e., 2:1
}
Syed
fonte
0

Eu usei uma nova solução.

.squares{
  width: 30vw
  height: 30vw

Para proporção principal

.aspect-ratio
  width: 10vw
  height: 10vh

No entanto, isso é relativo a toda a janela de exibição. Portanto, se você precisar de uma div que seja 30% da largura da janela de exibição, poderá usar 30vw e, desde que saiba a largura, reutilize-as em altura usando a unidade calc e vw.

Eshwaren Manoharen
fonte
7
Não é exatamente isso que a segunda resposta mais bem classificada já descreveu?
Rnevius 29/01
-4

Se toda a estrutura do contêiner fosse baseada em porcentagem, esse seria o comportamento padrão. Você pode fornecer um exemplo mais específico?

Abaixo está um exemplo do que quero dizer, se toda a hierarquia pai fosse baseada em%, qualquer ajuste da janela do navegador funcionaria sem nenhum js / css adicional. Isso não é uma possibilidade no seu layout?

<div style="width: 100%;">
   <div style="width: 50%; margin: 0 auto;">Content</div>
</div>
Nick Craver
fonte
1
Veja minha edição da pergunta original. Não vejo onde essa técnica manteria a proporção, a altura não mudaria.
jackb