Mantener la relación de aspecto de un div con CSS

1207

Quiero crear un divque pueda cambiar su ancho / alto a medida que cambia el ancho de la ventana.

¿Existe alguna regla CSS3 que permita que la altura cambie de acuerdo con el ancho, manteniendo su relación de aspecto ?

Sé que puedo hacer esto a través de JavaScript, pero preferiría usar solo CSS.

div manteniendo la relación de aspecto de acuerdo con el ancho de la ventana

7
  • 4
    Escribí sobre diferentes enfoques para esto en mi artículo CSS-Tricks sobre escalado de animaciones receptivas 5 de ene. De 2017 a las 14:45
  • 5
    Llegué a esta sesión de preguntas y respuestas muy tarde, pero debo comentar. Aunque es muy disciplinado y está dentro de las reglas de SO de todos los que responden para hacer todo lo posible para satisfacer la demanda de "solo CSS" de la pregunta, es bastante sorprendente que, con la excepción de la respuesta del usuario007 en la parte inferior de la página, no- uno ha mencionado lo obvio: no existe una solución confiable de solo CSS, este problema requiere Javascript. Un novato que ingrese a esta página podría perder un tiempo valioso cambiando de un conjunto de pros / contras a otro antes de que se apague la bombilla: solo CSS no es suficiente. 13/11/2017 a las 21:24
  • 1
    Escribí una pequeña herramienta que facilita la vista previa y calcular las relaciones de aspecto, aspectrat.io . También genera el código CSS / Sass / Less apropiado que puede copiar y pegar en sus proyectos. Espero que la gente lo encuentre útil. 8 de marzo de 2018 a las 22:41
  • 2
    Esta pregunta es para establecer la altura en función del ancho . Si necesita lo contrario, consulte Configurar el ancho del elemento en función de la altura a través de CSS . 26 ene 2019 a las 14:00
  • 1
    Todas las soluciones CSS sugeridas aquí tienen limitaciones. Actualmente no existe una solución de propósito general sin javascript. @Web_Designer tiene una buena solución, pero solo mantiene la proporción basada en el ancho. Si desea mantener esa proporción para un contenedor donde el ancho Y la altura son importantes, no funcionará. También se encontrará con problemas similares al usar vw y vh, porque debe bloquear uno u otro. Estas limitaciones probablemente no sean un problema para el contenido de desplazamiento, pero otras aplicaciones que dependen de una altura limitada, necesitarán javascript. 27/01/20 a las 1:52
1469

Simplemente cree una envoltura <div>con un valor porcentual para padding-bottom, como este:

.demoWrapper {
  padding: 10px;
  background: white;
  box-sizing: border-box;
  resize: horizontal;
  border: 1px dashed;
  overflow: auto;
  max-width: 100%;
  height: calc(100vh - 16px);
}

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

El resultado será una <div>altura igual al 75% del ancho de su contenedor (una relación de aspecto de 4: 3).

Esto se basa en el hecho de que para el relleno:

The percentage is calculated with respect to the width of the generated box's containing block [...] (source: w3.org, emphasis mine)

Valores de fondo de relleno para otras relaciones de aspecto y 100% de ancho:

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

Colocando contenido en el div:

Para mantener la relación de aspecto del div y evitar que su contenido lo estire, debe agregar un niño absolutamente posicionado y estirarlo hasta los bordes de la envoltura con:

div.stretchy-wrapper {
  position: relative;
}

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

He aquí una demostración y otro más en profundidad de demostración

3
  • 32
    @schellmax, se debe a que el% de relleno se calcula en relación con el ancho del elemento actual, mientras que el% de altura se calcula en relación con la altura del elemento principal. Además, las posiciones absolutas se calculan en relación con el contenedor exterior de un elemento, que incluye el área de relleno. Para obtener más información, Google "CSS Box Model" 17/09/12 a las 20:33
  • 15
    Esto no parece funcionar de forma anidada. Funciona en el primer nivel, pero cuando se intenta hacer lo mismo dentro del div manteniendo la relación de aspecto, el porcentaje de fondo de relleno parece aplicarse al ancho del padre. aquí hay un ejemplo donde el .stretchy-wrap.onethird padding-bottom del 25% es en realidad el 25% del ancho principal. ¿Alguien puede explicar esto? 8 de febrero de 2013 a las 15:53
  • Esta respuesta está desactualizada a partir de 2021, consulte la respuesta de @Tiago.
    Eneko
    hace 2 días
452

vw unidades:

Puede usar vwunidades tanto para el ancho como para el alto del elemento. Esto permite conservar la relación de aspecto del elemento, según el ancho de la ventana gráfica.

vw : 1/100th of the width of the viewport. [MDN]

Alternativamente, también puede usar vhpara la altura de la ventana gráfica, o incluso vmin/ vmaxpara usar la menor / mayor de las dimensiones de la ventana gráfica (discusión aquí ).

Ejemplo: relación de aspecto 1: 1

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

Para otras relaciones de aspecto, puede utilizar la siguiente tabla para calcular el valor de la altura según el ancho del elemento:

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

Ejemplo: cuadrícula 4x4 de divs cuadrados

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>

Aquí hay un violín con esta demostración y aquí hay una solución para hacer una cuadrícula receptiva de cuadrados con contenido centrado vertical y horizontalmente .


La compatibilidad con el navegador para las unidades vh / vw es IE9 + consulte canIuse para obtener más información

1
  • 12
    @ web-tiki, tienes razón. Me he encontrado con un problema: se supone que el ancho del elemento es proporcional al ancho de la ventana gráfica, lo que no será el caso si 1) tienes cosas como canaletas de ancho fijo, o 2) tienes un ancho máximo establecido para algunos de sus elementos. 29/04/15 a las 17:55
50

Me topé con lo que considero una solución inteligente para este problema, usando <svg>y display:grid.

Un display:gridelemento le permite ocupar el mismo espacio con dos (o más) de sus hijos, usando el mismo grid-area.
Esto significa que todos tienen contenido de flujo, se superponen y, fuera de la caja, el más alto establece la proporción .

Uno de ellos será el <svg>encargado de fijar el ratio. El otro contenido real. Si el contenido real es breve y nunca llena la proporción completa (y solo desea que esté centrado en un espacio con esta proporción), simplemente céntrelo (consulte el primer fragmento ejecutable a continuación).

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

Establezca <svg>la relación s en lo que desee:

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

.ratio {
  display: grid;
}
.ratio > * {
  grid-area: 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>

Si necesita una solución en la que el elemento de contenido tiene más contenido que desea confinar en un área desplazable con la proporción deseada, establezca position:relativeen el elemento principal y position:absolute; height:100%; overflow-y: auto;en el contenido, lo que permite que el elemento de contenido de flujo (the <svg>) establezca el tamaño y, por lo tanto, la proporción.

.ratio {
  display: grid;
  position: relative;
}
.ratio > * {
  grid-area: 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 2"></svg>
  <div>
    <h1>Fixed ratio 7:2</h1>
    <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>

Como @emjay señaló en un comentario a continuación, el svg de proporción se puede colocar en uno de los pseudoelementos del padre, siempre que esté codificado correctamente:

.three-squares {
  display: grid;
  border: 1px solid red;
}

.three-squares > *, .three-squares:before {
  grid-area: 1/1;
}

.three-squares:before {
  content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 1'%3E%3C/svg%3E");
  line-height: 0;
}
<div class="three-squares">  
  <div>I'm 3:1</div>
</div>

Cuando se usa dentro de un pseudo-elemento, se <svg>convierte en un elemento reemplazado que, por defecto, se encuentra en una línea de base de altura variable ( 4pxen Chrome, 3.5pxen Firefox). La altura de la línea de base varía según line-height, por lo que debemos establecer line-height: 0el pseudo para obtener una relación precisa. Más detalles aquí .


Personalmente, prefiero la versión en la que <svg>se coloca en el marcado, ya que puedo tener una sola clase ( .ratio) que se ocupe de contenedores de varias proporciones (en lugar de tener una clase para cada proporción individual que pueda necesitar).

0
28

Encontré una manera de hacer esto usando CSS, pero debes tener cuidado ya que puede cambiar dependiendo del flujo de tu propio sitio web. Lo hice para incrustar videos con una relación de aspecto constante dentro de una porción de ancho fluido de mi sitio web.

Supongamos que tiene un video incrustado como este:

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

A continuación, puede colocar todo esto dentro de un div con una clase de "video". Esta clase de video probablemente será el elemento fluido en su sitio web, de modo que, por sí mismo, no tiene restricciones de altura directas, pero cuando cambie el tamaño del navegador, cambiará de ancho de acuerdo con el flujo del sitio web. Este sería el elemento en el que probablemente esté tratando de colocar su video incrustado mientras mantiene una cierta relación de aspecto del video.

Para hacer esto, coloco una imagen antes del objeto incrustado dentro del div de la clase "video".

!!! Lo importante es que la imagen tenga la relación de aspecto correcta que desea mantener. Además, asegúrese de que el tamaño de la imagen sea AL MENOS tan grande como el más pequeño que espera que obtenga el video (o lo que sea que esté manteniendo el AR) según su diseño. Esto evitará problemas potenciales en la resolución de la imagen cuando se cambia de tamaño por porcentaje. Por ejemplo, si desea mantener una relación de aspecto de 3: 2, no use simplemente una imagen de 3 px por 2 px. Puede funcionar en algunas circunstancias, pero no lo he probado y probablemente sería una buena idea evitarlo.

Probablemente ya debería tener un ancho mínimo como este definido para los elementos fluidos de su sitio web. De lo contrario, es una buena idea hacerlo para evitar cortar elementos o superponerse cuando la ventana del navegador se vuelve demasiado pequeña. Es mejor tener una barra de desplazamiento en algún momento. El ancho más pequeño que debe tener una página web es de alrededor de ~ 600 px (incluidas las columnas de ancho fijo) porque las resoluciones de pantalla no son más pequeñas a menos que se trate de sitios compatibles con teléfonos. !!!

Utilizo un png completamente transparente, pero realmente no creo que termine importando si lo haces bien. Como esto:

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

Ahora debería poder agregar CSS similar al siguiente:

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%; }

Asegúrese de eliminar también cualquier declaración explícita de alto o ancho dentro del objeto y las etiquetas de inserción que generalmente vienen con el código de inserción copiado / pegado.

La forma en que funciona depende de las propiedades de posición del elemento de la clase de video y del elemento que desea que mantenga una determinada relación de aspecto. Aprovecha la forma en que una imagen mantendrá su relación de aspecto adecuada cuando se redimensione en un elemento. Dice cualquier otra cosa que esté en el elemento de clase de video para aprovechar al máximo el espacio proporcionado por la imagen dinámica al forzar su ancho / alto al 100% del elemento de clase de video que está siendo ajustado por la imagen.

Bastante bien, ¿eh?

Puede que tengas que jugar un poco con él para que funcione con tu propio diseño, pero esto realmente funciona sorprendentemente bien para mí. El concepto general está ahí.

0
20

Elliot me inspiró a esta solución, gracias:

aspectratio.png es un archivo PNG completamente transparente con el tamaño de su relación de aspecto preferida, en mi caso 30x10 píxeles.

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);
}

Tenga en cuenta: background-size es una función css3 que podría no funcionar con sus navegadores de destino. Puede comprobar la interoperabilidad (fe en caniuse.com ).

0
dieciséis

Para agregar a la respuesta de Web_Designer, <div>tendrá una altura (compuesta en su totalidad por relleno inferior) del 75% del ancho del elemento que lo contiene . Aquí hay un buen resumen: http://mattsnider.com/css-using-percent-for-margin-and-padding/ . No estoy seguro de por qué debería ser así, pero así es.

Si desea que su div tenga un ancho diferente al 100%, necesita otro div de envoltura en el que establecer el ancho:

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;
}

Usé algo similar al truco de imagen de Elliot recientemente para permitirme usar consultas de medios CSS para entregar un archivo de logotipo diferente según la resolución del dispositivo, pero aún así escalar proporcionalmente como lo <img>haría naturalmente (configuré el logotipo como imagen de fondo en un .png transparente con la relación de aspecto correcta). Pero la solución de Web_Designer me ahorraría una solicitud http.

1
  • Gran solucion. En mi caso, conozco el tamaño "natural" de la imagen al colocarla en DOM y necesito tener un marcador de posición de imagen con la altura adecuada para evitar un mayor desplazamiento una vez que el navegador carga las imágenes. En .ar-outside tengo el ancho de la imagen en píxeles, en .ar tengo padding-bottom calculado a partir de la relación de aspecto de la imagen real. En lugar de ar-inner, tengo la imagen en sí (<img>). Sin embargo, tuve que establecer el ancho al 100% en lugar de establecer la parte superior, inferior, izquierda y derecha. Cuando configuro maxWidth en ar-outside, la imagen se escala bien cuando el padre es pequeño, pero no se escala a un tamaño mayor que su tamaño natural.
    Mi-La
    6 feb 2018 a las 17:37
dieciséis

Como se indica aquí en w3schools.com y algo reiterado en esta respuesta aceptada , los valores de relleno como porcentajes (el énfasis es mío):

Specifies the padding in percent of the width of the containing element

Ergo, un ejemplo correcto de un DIV sensible que mantiene una relación de aspecto de 16: 9 es el siguiente:

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>

Demostración en JSFiddle

0
dieciséis

Como @ web-tiki ya muestra una forma de usar vh/ vw, también necesito una forma de centrar en la pantalla, aquí hay un código de fragmento para el retrato 9:16 .

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

translateYmantendrá este centro en la pantalla. calc(100vw * 16 / 9)es la altura esperada para el 16 de septiembre. (100vw * 16 / 9 - 100vh)es la altura de desbordamiento, por lo tanto, tire hacia arriba overflow height/2lo mantendrá en el centro de la pantalla.

Para paisaje, y mantener 16: 9 , muestra uso

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

La relación 9/16 es fácil de cambiar, no es necesario que esté predefinida 100:56.25o 100:75. Si primero desea asegurarse de la altura, debe cambiar la anchura y la altura, por ejemplo, height:100vh;width: calc(100vh * 9 / 16)para el retrato 9:16.

Si desea adaptarse para diferentes tamaños de pantalla, también puede interesar

  • cubierta de tamaño de fondo / contener
    • El estilo anterior es similar a contener, depende de la relación ancho: alto.
  • ajuste de objeto
    • cubrir / contener para etiqueta img / video
  • @media (orientation: portrait)/@media (orientation: landscape)
    • Consulta de medios para portrait/ landscapepara cambiar la proporción.
0
14

Solución 2021: use la aspect-ratiopropiedad CSS

(actualmente compatible con Chromium, Safari Technology Preview y Firefox Nightly)

<div class='demo'></div>
.demo {
  background: black;
  width: 500px;
  aspect-ratio: 4/3;
}
0
13

Esta es una mejora de la respuesta aceptada:

  • Utiliza pseudo elementos en lugar de divs de envoltura
  • La relación de aspecto se basa en el ancho del cuadro en lugar de en su padre
  • La caja se estirará verticalmente cuando el contenido se vuelva más 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>
0
9

Puede utilizar un archivo svg. Haga que la posición del contenedor / envoltorio sea relativa, coloque el svg primero como posicionado estáticamente y luego coloque el contenido absolutamente posicionado (arriba: 0; izquierda: 0; derecha: 0; abajo: 0;)

Ejemplo con proporciones 16: 9:

image.svg: (se puede insertar en 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>

Tenga en cuenta que el svg en línea no parece funcionar, pero puede codificarlo con urlencode el svg e incrustarlo en el atributo img src de esta manera:

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

Basándome en sus soluciones, hice un truco:

Cuando lo use, su HTML será solo

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

Para usarlo de esta manera, haga: CSS:

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

y js (jQuery)

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

Y teniendo esto, simplemente establece attr data-keep-ratioen altura / ancho y eso es todo.

0
8

En realidad, la respuesta más votada es una muy buena solución, pero hay una nueva característica de CSS que se llama aspect-ratio.

Podría usarse así:

.someClass {
  width: 100%;
  aspect-ratio: 4/3;
}

Determina automáticamente su altura, pero consulte la tabla de compatibilidad:

ingrese la descripción de la imagen aquí

Si la compatibilidad con el navegador es importante para su proyecto, no la utilice. utilizar la padding-bottomtécnica.

5
  • @ RaphaëlBalet, gracias por tu actualización. 5 de julio a las 15:16
  • Desafortunadamente, safari no admite esto lo suficiente, y es una verdadera molestia encontrar una alternativa. 18 de agosto a las 16:30
  • 1
    @marsnebulasoup, Sí, Safari es el nuevo IE 🤦‍♂️ 18 de agosto a las 20:12
  • Y es aún peor, porque Safari es el navegador de referencia en iOS. 18 de agosto a las 20:18
  • @marsnebulasoup, sí, tienes razón, muchas cosas son aún peores en iOS Safari. 19 de agosto a las 14:13
7

Si bien la mayoría de las respuestas son geniales, la mayoría de ellas requieren tener una imagen ya dimensionada correctamente ... Otras soluciones solo funcionan para un ancho y no se preocupan por la altura disponible, pero a veces también desea ajustar el contenido a una cierta altura .

Intenté unirlos para brindar una solución totalmente portátil y redimensionable ... El truco es usar el escalado automático de una imagen pero usar un elemento svg en línea en lugar de usar una imagen renderizada previamente o cualquier forma de segunda solicitud 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>

Tenga en cuenta que he usado valores grandes en los atributos de ancho y alto del SVG, ya que debe ser más grande que el tamaño máximo esperado, ya que solo puede encogerse. El ejemplo hace que la relación div sea 10: 5

7

Así es como lo hago:

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

[data-aspect-ratio]:before {
    content: '';
    display: block;
}

[data-aspect-ratio] > * {
    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 ejemplo :

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

fuente

1
  • dieciséis
    Solo para su información ... Puede hacer exactamente esto (usando selectores de atributos) en exactamente la misma cantidad de líneas usando CSS simple. El [data-aspect-ratio]selector de atributos está disponible en CSS.
    rnevius
    23/10/15 a las 16:39
6

Si desea colocar un cuadrado dentro de la ventana gráfica en la vista vertical u horizontal (lo más grande posible, pero nada sobresaliendo afuera), cambie entre usar vw/ vhen la orientación portrait/ landscape:

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

Puede lograrlo usando SVG.

Depende de un caso, pero en algunos es realmente útil. A modo de ejemplo - se puede establecer background-imagesin fijar altura fija o utilizarlo para incrustar youtube <iframe>con una relación 16:9y position:absoluteetc.

Para 3:2establecer la relación viewBox="0 0 3 2"y así sucesivamente.

Ejemplo:

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>
6

Solución 2020: uso de cuadrícula y relleno de pseudoelemento

He encontrado una forma más nueva de resolver este caso. Esta solución es descendiente de cualquier padding-bottommétodo, pero sin position: absolutehijos, solo con un display: grid;pseudo elemento.

Aquí tenemos .ratio::beforecon good old padding-bottom: XX%and grid-area: 1 / 1 / 1 / 1;, que obliga al pseudo elemento a mantener la posición en la cuadrícula. Aunque aquí tenemos width: 0;que evitar que este desborde el elemento principal ( z-indexaquí lo usamos en frío , pero este es más corto).

Y nuestro elemento principal .ratio > *:first-childtiene la misma posición que .ratio::before, es decir grid-area: 1 / 1 / 1 / 1;, ambos comparten el mismo lugar de celda de la cuadrícula. Ahora podemos poner cualquier contenido en nuestro div, y el pseudo elemento es el que determina la relación ancho / alto. Más sobre el área de la cuadrícula .

.ratio {
  display: grid;
  grid-template-columns: 1fr;
  max-width: 200px; /* just for instance, can be 100% and depends on parent */  
}

.ratio::before {
  content: '';
  width: 0;
  padding-bottom: calc(100% / (16/9)); /* here you can place any ratio */
  grid-area: 1 / 1 / 1 / 1;
}

.ratio>*:first-child {
  grid-area: 1 / 1 / 1 / 1; /* the same as ::before */
  background: rgba(0, 0, 0, 0.1); /* just for instance */
}
<div class="ratio">
  <div>16/9</div>
</div>

Aunque puede usar CSS val y colocar su proporción en HTML usando styleatributo. display: inline-gridTambién funciona con .

.ratio {
  display: inline-grid;
  grid-template-columns: 1fr;
  width: 200px; /* just for instance, can be 100% and depends on parent */ 
  margin-right: 10px; /* just for instance */
}

.ratio::before {
  content: '';
  width: 0;
  padding-bottom: calc(100% / (var(--r))); /* here you can place any ratio */
  grid-area: 1 / 1 / 1 / 1;
}

.ratio>*:first-child {
  grid-area: 1 / 1 / 1 / 1; /* the same as ::before */
  background: rgba(0, 0, 0, 0.1); /* just for instance */
}
<div class="ratio" style="--r: 4/3;">
  <div>4/3</div>
</div>

<div class="ratio" style="--r: 16/9;">
  <div>16/9</div>
</div>
5

Me gustaría compartir mi solución, donde tengo una imgetiqueta -etiqueta que llena una determinada relación de aspecto. No podía usar backgrounddebido a la falta de apoyo de la CMS y no me prefiere usar una etiqueta de estilo de esta manera: <img style="background:url(...)" />. Además, el ancho es del 100%, por lo que no es necesario establecer un tamaño fijo como en algunas de las soluciones. ¡Escalará de manera receptiva!

.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>
4

Una forma sencilla de mantener la relación de aspecto, utilizando el elemento lienzo.

Intente cambiar el tamaño del div a continuación para verlo en acción.

Para mí, este enfoque funcionó mejor, así que lo comparto con otros para que ellos también puedan beneficiarse de él.

.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>

¡También funciona con 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>
0
4

digamos que tiene 2 divs, el div externo es un contenedor y el interno podría ser cualquier elemento que necesite para mantener su proporción (img o un iframe de youtube o lo que sea)

html se ve así:

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

digamos que necesita mantener la proporción de la proporción de "elementos" => 4 a 1 o 2 a 1 ...

css se ve así

.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 */
}

el relleno cuando se especifica en% se calcula en función del ancho y no del alto. .. así que básicamente usted, no importa cuál sea su ancho, la altura siempre se calculará en función de eso. que mantendrá la proporción.

4

Bueno, recientemente recibimos la capacidad de usar la aspect-ratiopropiedad en CSS.

https://twitter.com/Una/status/1260980901934137345/photo/1

Nota: El soporte aún no es el mejor ...

https://caniuse.com/#search=aspect-ratio

EDITAR: ¡La relación de aspecto ya está disponible!

https://web.dev/aspect-ratio/

0
3

Solo una idea o un truco.

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>
0
3

Me he encontrado con este problema varias veces, así que hice una solución JS para ello. Básicamente, esto ajusta la altura del elemento domElement de acuerdo con el ancho del elemento según la proporción que especifique. Podrías usarlo de la siguiente manera:

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

Tenga en cuenta que, dado que establece la altura del elemento, el elemento debe ser un display:blocko display:inline-block.

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

2
  • 1
    Aunque no he visto ni probado su código (ya tengo el mío), he votado a favor de su respuesta solo por el hecho de que presenta la única solución confiable, un script JS. 13/11/2017 a las 21:12
  • 2
    La pregunta pedía específicamente una solución que no necesitaba Javascript.
    Flimm
    29 de mayo de 2018 a las 3:02 p.m.
2

Digamos que le gusta mantener el Ancho: 100 px y el Alto: 50 px (es decir, 2: 1) Simplemente haga lo siguiente:

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

La nueva etiqueta de relación de aspecto sería increíble, pero estropeó el posicionamiento de mis divs. La solución tradicional de rellenar un div contenedor funciona, pero solo ajusta el tamaño de acuerdo con el ancho del padre o la ventana gráfica, lo que lo hace problemático cuando la altura es el factor limitante .

Encontré la min()función muy útil y ajusté el método tradicional de esta manera:

body{
    background-image: linear-gradient(to top right, #FFE6B5, #B3CEBF);
    padding: 0;
    margin: 0 auto;
    overflow-y: hidden; /* this is to avoid scrolling when the height of the viewport is less than what the aspect ratio requires */
}

.wrapper {
    position: relative;
    width: 100vw;
    max-height: 100vh;
}
.sixteen-by-nine.aspect-ratio { 
    padding-bottom: 56.25% /* 9:16 ratio */
}
.content {
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
    background-color: green
}

.centered {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    height: 100%;
    width: min(177.8vh, 100%); /* this always keeps a 16:9 ratio within the viewport */
    font-size: min(3vh,1.7vw); /* if you are also interested in scaling the font size */
    background-color: blue
}
<body>
  <div class="wrapper">
    <div class="sixteen-by-nine aspect-ratio"></div>
    <div class="content" >
      <div class="centered">
        <!-- stuff goes here -->
      </div>
    </div>
  </div>
</body>
0
1

Acabo de crear un div 2: 1 que se redimensionó para ocupar el ancho completo, pero luego encoge el ancho si hace que la parte superior o inferior se exceda. Pero tenga en cuenta que esto solo funcionará con el tamaño de la ventana, no con el tamaño del padre.

#scene {
    position: relative;
    top: 50vh;
    left: 50vw;
    width: 100vw;
    height: 50vw;
    max-height: 100vh;
    max-width: calc(100vh * 2);
    transform: translate(-50%, -50%);
}

Estoy seguro de que puede encontrar los% correctos para usar en 4:3lugar de 2:1.

0

Usé una nueva solución.

.squares{
  width: 30vw
  height: 30vw

A la relación de aspecto principal

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

Sin embargo, esto es relativo a toda la ventana gráfica. Entonces, si necesita un div que sea el 30% del ancho de la ventana gráfica, puede usar 30vw en su lugar, y como conoce el ancho, los reutiliza en altura usando calc y vw unit.

0
0

Aquí está mi solución para mantener una relación de aspecto de 16: 9 en vertical u horizontal en un div con márgenes fijos opcionales.

Es una combinación de propiedades width / height y max-width / max-height con unidades vw.

En esta muestra, los márgenes superior e inferior de 50 píxeles se agregan al pasar el mouse.

html {
  height: 100%;
}

body {
  margin: 0;
  height: 100%;
}

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}

.fixedRatio {
  max-width: 100vw;
  max-height: calc(9 / 16 * 100vw);
  width: calc(16 / 9 * 100vh);
  height: 100vh;
  
  /* DEBUG */
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: blue;
  font-size: 2rem;
  font-family: 'Arial';
  color: white;
  transition: width 0.5s ease-in-out, height 0.5s ease-in-out; 
}

.fixedRatio:hover {
  width: calc(16 / 9 * (100vh - 100px));
  height: calc(100vh - 100px);
}
<div class='container'>
  <div class='fixedRatio'>
    16:9
  </div>
</div>

Demostración en JSFiddle

0

Una novedad en Chrome 88 y que pronto seguirá en otros navegadores es la nueva aspect-ratiopropiedad CSS .

The aspect-ratio CSS property sets a preferred aspect ratio for the box, which will be used in the calculation of auto sizes and some other layout functions.

Artículo de trucos CSS

Más información

div {
  background: rebeccapurple;
  height:100px;
  margin:1em auto;
}

.square {
  aspect-ratio: 1 / 1;
  }
<div class="square">
  
</div>