html tag - Manter a proporção de um div com CSS





in html5 (18)


Se você quiser ajustar um quadrado dentro da janela de visualização na visualização vertical ou horizontal (o mais grande possível, mas nada do lado de fora), alterne entre usar vw / vh na orientação portrait / landscape :

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

Eu quero criar um div que pode alterar sua largura / altura como a largura da janela muda.

Há alguma regra CSS3 que permita que a altura mude de acordo com a largura, mantendo sua proporção ?

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




unidades vw :

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

vw: 1 / 100th da largura da viewport. [ MDN ]

Alternativamente, você também pode usar o vh para a altura da viewport, ou até mesmo o vmin / vmax para usar a menor / maior das dimensões da viewport (discussão here ).

Exemplo: proporção de 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 violino com esta demo e aqui está uma solução para criar uma grade responsiva de quadrados com conteúdo centralizado verticalmente e horizontalmente .

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




Para adicionar à resposta do Web_Designer, o <div> terá uma altura (totalmente composta de preenchimento inferior) de 75% da largura do elemento contendo . Aqui está um bom resumo: http://mattsnider.com/css-using-percent-for-margin-and-padding/ . Eu não tenho certeza porque isso deveria ser assim, mas é assim que é.

Se você quiser que seu div tenha uma largura diferente de 100%, você precisa de outro div de encapsulamento no qual 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;
}

Eu usei algo semelhante ao truque de imagem de Elliot recentemente para permitir que eu usasse consultas de mídia CSS para servir um arquivo de logotipo diferente dependendo da resolução do dispositivo, mas ainda dimensionar proporcionalmente como um <img> faria naturalmente (eu defino o logotipo como imagem de fundo como png transparente com o formato correto). Mas a solução do Web_Designer salvaria uma solicitação http.




Eu tropecei em uma solução inteligente usando <svg> e display:grid .

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

Isso significa que você pode usá-lo como é quando você 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 neste espaço (ou seja, centralizá-lo em ambas as direções display:flex; align-items:center; justify-content:center ).
É praticamente o mesmo que usar um <img> transparente com display:block e ratio predeterminado, exceto que o <svg> é mais leve e consideravelmente mais fácil de modificar (para alterar a proporção de forma responsiva, caso seja necessário).

<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 o que você precisa fazer é alterar a proporção de <svg> s:

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

Veja isso funcionando:

.ratio {
  display: grid;
}
.ratio > * {
  grid-area: 1/1/1/1;
}

/* below code NOT needed for setting the ratio 
 * I just wanted to mark it visually
 * and center contents
 */
.ratio div {
  border: 1px solid red;
  display: flex;
  align-items: center;
  justify-content: center;
}
<div class="ratio">
  <svg viewBox="0 0 7 1"></svg>
  <div>
    Fixed ratio 7:1
  </div>
</div>

Se você precisar de uma solução em que o elemento content não tenha permissão para definir a proporção quando ela é mais alta (com overflow hidden ou auto), você precisa definir position:relative na grade e position:absolute; height:100%; overflow-y: auto; position:absolute; height:100%; overflow-y: auto; no conteúdo. Exemplo:

.ratio {
  display: grid;
  position: relative;
}
.ratio > * {
  grid-area: 1/1/1/1;
}


.ratio > div {
  height: 100%;
  overflow-y: auto;
  position: absolute;
  
  /* the rest is not needed */
  border: 1px solid red;
  padding: 0 1rem;
}
<div class="ratio">
  <svg viewBox="0 0 7 1"></svg>
  <div>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. A scelerisque purus semper eget. Sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum. A cras semper auctor neque vitae tempus quam pellentesque nec. Morbi enim nunc faucibus a pellentesque sit amet porttitor. Arcu odio ut sem nulla. Sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque. Cras tincidunt lobortis feugiat vivamus at augue eget. Laoreet sit amet cursus sit amet. Amet nulla facilisi morbi tempus iaculis urna id volutpat. Leo in vitae turpis massa sed elementum tempus egestas sed. Egestas integer eget aliquet nibh. Dolor sit amet consectetur adipiscing elit.

<p>Ut aliquam purus sit amet. Eget magna fermentum iaculis eu non diam phasellus vestibulum. Diam in arcu cursus euismod quis viverra nibh. Nullam vehicula ipsum a arcu cursus vitae congue. Vel orci porta non pulvinar neque laoreet suspendisse. At tellus at urna condimentum mattis pellentesque. Tristique senectus et netus et malesuada. Vel pretium lectus quam id leo in. Interdum velit euismod in pellentesque. Velit euismod in pellentesque massa placerat duis. Vitae suscipit tellus mauris a diam maecenas sed enim.

<p>Mauris a diam maecenas sed enim ut sem. In hendrerit gravida rutrum quisque. Amet dictum sit amet justo donec enim diam. Diam vulputate ut pharetra sit amet aliquam id. Urna porttitor rhoncus dolor purus non enim praesent. Purus in massa tempor nec feugiat nisl pretium. Sagittis vitae et leo duis ut. Facilisi nullam vehicula ipsum a arcu cursus vitae congue mauris. Volutpat odio facilisis mauris sit amet massa vitae tortor condimentum. Aliquam purus sit amet luctus venenatis lectus magna. Sit amet purus gravida quis blandit turpis. Enim eu turpis egestas pretium aenean. Consequat mauris nunc congue nisi. Nunc sed id semper risus in hendrerit gravida rutrum. Ante metus dictum at tempor. Blandit massa enim nec dui nunc mattis enim ut.
  </div>
</div>




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

aspectratio.png é um arquivo PNG completamente transparente com o tamanho de 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 on caniuse.com ).




Eu me deparei com esse problema algumas vezes, então eu fiz uma solução JS para ele. Isso basicamente ajusta a altura do domElement de acordo com a largura do elemento pela proporção especificada. Você poderia usá-lo como segue:

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

Por favor, esteja ciente de que, como está definindo a altura do elemento, o elemento deve ser um display:block ou display:inline-block .

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




Vamos dizer que você tem 2 divs a div outher é um recipiente e o interior poderia ser qualquer elemento que você precisa para manter sua relação (img ou um iframe youtube ou qualquer outra coisa)

html parece com isso:

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

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

proporçã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, a altura será sempre calculada com base nisso. qual manterá a relação.




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>




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

Quando você usa, seu HTML será apenas

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

Para usá-lo dessa maneira, 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ê simplesmente ajusta a relação data-keep-ratio attr para height / width e é isso.




Digamos que você mantenha Largura: 100px e Altura: 50px (ou seja, 2: 1) Apenas faça isso:

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



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

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

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

Isso depende do fato de que para preenchimento:

A porcentagem é calculada em relação à largura do bloco que contém a caixa gerada [...] (fonte: w3.org , emphasis mine)

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

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

Colocar conteúdo no div:

Para manter a relação de aspecto da div e evitar que o seu conteúdo a estique, você precisa adicionar um filho com posicionamento absoluto e esticá-lo até as bordas do wrapper 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 outra demonstração mais profunda




Você pode usar um svg. Torne a posição do container / wrapper relativa, coloque o svg primeiro como posicionado de forma estática e, em seguida, coloque o conteúdo posicionado absolutamente (top: 0; left: 0; right: 0; bottom: 0;)

Exemplo com proporções 16: 9:

image.svg: (pode ser embutido 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>

Note que o svg inline parece não funcionar, mas você pode urlencode o svg e o integra no atributo img src assim:

<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%;" />



Eu usei uma nova solução.

.squares{
  width: 30vw
  height: 30vw

Para o aspecto principal

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

No entanto, isso é relativo a toda a viewport. Então, se você precisa de um div que é 30% da largura da viewport, você pode usar 30vw em vez disso, e já que você conhece a largura, você os reutiliza em altura usando calc e vw unit.




Como dito aqui no w3schools.com e um pouco reiterado nesta resposta aceita , preencha valores como porcentagens (ênfase minha):

Especifica o preenchimento em porcentagem da largura do elemento contido

Ergo, 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







Como @ 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 de trecho para o retrato 9:16 .

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

translateY manterá este centro na tela. calc(100vw * 16 / 9) é a altura esperada para 9/16. (100vw * 16 / 9 - 100vh) é a altura de transbordamento, então, puxe a overflow height/2 irá mantê-lo centrado na tela.

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

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

A relação 9/16 é fácil de mudar, sem necessidade de 100:56.25 ou 100:75 pré-definidos. Se você deseja garantir a altura primeiro, você deve alternar largura e altura, por exemplo, height:100vh;width: calc(100vh * 9 / 16) para o retrato 9:16.

Se você quiser se adaptar ao tamanho de tela diferente, você também pode interessar

  • capa de background-size / conter
    • Acima estilo é semelhante a conter, depende da largura: relação de altura.
  • object-fit
    • cobrir / conter para tag img / video
  • @media (orientation: portrait) / @media (orientation: landscape)
    • Consulta de mídia para portrait / landscape para alterar a proporção.



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>

source




100% funciona de maneira diferente para largura e altura.

Quando você especifica width: 100% , significa "ocupa 100% da largura disponível do elemento pai ou da largura da janela".

Quando você especifica height: 100% , significa apenas "ocupar 100% da altura disponível do elemento pai". O que isso significa é que, se você não especificar uma altura em um elemento de nível superior, a altura de todos os filhos será 0 ou a altura do pai, e é por isso que você precisa definir o elemento mais alto para ter um valor min-height da min-height da janela.

Eu sempre especifico o corpo para ter uma altura mínima de 100vh e facilitar o posicionamento e os cálculos,

body {
  min-height: 100vh;
}




html css css3 responsive-design aspect-ratio