Mantener la relación de aspecto de div pero llenar el ancho y alto de la pantalla en CSS?


Tengo un sitio para armar que tiene una relación de aspecto fija de aproximadamente 16:9 paisaje, como un video.

Quiero tenerlo centrado y expandirlo para llenar el ancho disponible y la altura disponible, pero nunca para crecer más en ambos lados.

Por ejemplo:

  1. Una página alta y delgada tendría el contenido estirando el ancho completo mientras mantiene una altura proporcional.
  2. Una página corta y ancha tendría el contenido estirando el altura completa, con un ancho proporcional.

Hay dos métodos que he estado mirando:

  1. Use una imagen con la relación de aspecto correcta para expandir un contenedor div, pero no pude lograr que se comporte de la misma manera en los principales navegadores.
  2. Establecer un relleno inferior proporcional, pero que solo funciona relativamente a la anchura e ignora la altura. Simplemente se hace más grande con el ancho y muestra barras de desplazamiento verticales.

Lo sé usted podría hacer esto con JS con bastante facilidad, pero me gustaría una solución CSS pura.

¿Alguna idea?

Author: web-tiki, 2013-12-15

7 answers

Utilice las nuevas unidades de ventana CSS vw and vh (viewport width / viewport height)

FIDDLE

Cambie el tamaño vertical y horizontalmente y verá que el elemento siempre llenará el tamaño máximo de la ventana sin romper la relación y sin barras de desplazamiento!

(PURO) CSS

div
{
    width: 100vw; 
    height: 56.25vw; /* height:width ratio = 9/16 = .5625  */
    background: pink;
    max-height: 100vh;
    max-width: 177.78vh; /* 16/9 = 1.778 */
    margin: auto;
    position: absolute;
    top:0;bottom:0; /* vertical center */
    left:0;right:0; /* horizontal center */
}

* {
  margin: 0;
  padding: 0;
}
div {
  width: 100vw;
  height: 56.25vw;
  /* 100/56.25 = 1.778 */
  background: pink;
  max-height: 100vh;
  max-width: 177.78vh;
  /* 16/9 = 1.778 */
  margin: auto;
  position: absolute;
  top: 0;
  bottom: 0;
  /* vertical center */
  left: 0;
  right: 0;
  /* horizontal center */
}
<div></div>

Si desea utilizar un máximo de 90% de ancho y alto de la ventana: FIDDLE

* {
  margin: 0;
  padding: 0;
}
div {
  width: 90vw;
  /* 90% of viewport vidth */
  height: 50.625vw;
  /* ratio = 9/16 * 90 = 50.625 */
  background: pink;
  max-height: 90vh;
  max-width: 160vh;
  /* 16/9 * 90 = 160 */
  margin: auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
<div></div>

Además, el soporte del navegador también es bastante bueno: IE9+, FF, Chrome, Safari - caniuse

 227
Author: Danield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-12 09:46:19

Simplemente reformulando la respuesta de Danield en una mezcla MENOR, para su uso posterior:

// Mixin for ratio dimensions    
.viewportRatio(@x, @y) {
  width: 100vw;
  height: @y * 100vw / @x;
  max-width: @x / @y * 100vh;
  max-height: 100vh;
}

div {

  // Force a ratio of 5:1 for all <div>
  .viewportRatio(5, 1);

  background-color: blue;
  margin: 0;
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
}
 15
Author: Christophe Marois,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-22 18:00:14

Mi pregunta original para esto fue cómo ambos tienen un elemento de un aspecto fijo, pero para encajar eso dentro de un contenedor especificado exactamente, lo que lo hace un poco complicado. Si simplemente desea un elemento individual para mantener su relación de aspecto es mucho más fácil.

El mejor método que he encontrado es darle a un elemento cero altura y luego usar porcentaje de relleno-fondo para darle altura. El relleno de porcentaje es siempre proporcional al ancho de un elemento, y no a su altura, incluso si su relleno superior o inferior.

W3C Padding Properties

Así que utilizando que se puede dar a un elemento un ancho porcentual para sentarse dentro de un contenedor, y luego relleno para especificar la relación de aspecto, o en otros términos, la relación entre su ancho y alto.

.object {
    width: 80%; /* whatever width here, can be fixed no of pixels etc. */
    height: 0px;
    padding-bottom: 56.25%;
}
.object .content {
    position: absolute;
    top: 0px;
    left: 0px;
    height: 100%;
    width: 100%;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    padding: 40px;
}

Así que en el ejemplo anterior el objeto toma el 80% del ancho del contenedor, y luego su altura es el 56.25% de ese valor. Si su ancho era 160px entonces el relleno inferior, y por lo tanto la altura sería sea 90px-un aspecto 16:9.

El pequeño problema aquí, que puede no ser un problema para usted, es que no hay espacio natural dentro de su nuevo objeto. Si necesita poner algo de texto, por ejemplo, y ese texto necesita tomar sus propios valores de relleno, debe agregar un contenedor dentro y especificar las propiedades allí.

Además, las unidades vw y vh no son compatibles con algunos navegadores antiguos, por lo que la respuesta aceptada a mi pregunta podría no ser posible para usted y podría tener que usar algo más lo-fi.

 7
Author: Henry Gibson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-20 11:58:08

Use una consulta de medios CSS @media junto con las unidades de ventana CSS vw y vh para adaptarse a la relación de aspecto de la vista. Esto tiene la ventaja de actualizar otras propiedades, como font-size, también.

Este violín muestra la relación de aspecto fija para el div y el texto que coincide exactamente con su escala.

El tamaño inicial se basa en el ancho completo:

div {
  width: 100vw; 
  height: calc(100vw * 9 / 16);

  font-size: 10vw;

  /* align center */
  margin: auto;
  position: absolute;
  top: 0px; right: 0px; bottom: 0px; left: 0px;

  /* visual indicators */
  background:
    url(data:image/gif;base64,R0lGODlhAgAUAIABAB1ziv///yH5BAEAAAEALAAAAAACABQAAAIHhI+pa+EPCwA7) repeat-y center top,
    url(data:image/gif;base64,R0lGODlhFAACAIABAIodZP///yH5BAEAAAEALAAAAAAUAAIAAAIIhI8Zu+nIVgEAOw==) repeat-x left center,
    silver;
}

Luego, cuando la vista sea más ancha que la relación de aspecto deseada, cambie a altura como medida de base:

/* 100 * 16/9 = 177.778 */
@media (min-width: 177.778vh) {
  div {
    height: 100vh;
    width: calc(100vh * 16 / 9);

    font-size: calc(10vh * 16 / 9);
  }
}

Esto es muy similar en la vena a la max-width y max-height approach por @Danield, simplemente más flexible.

 6
Author: Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:36

Entiendo que usted pidió que le gustaría una CSS solución específica. Para mantener la relación de aspecto, tendría que dividir la altura por la relación de aspecto deseada. 16:9 = 1.777777777778.

Para obtener la altura correcta para el contenedor, tendría que dividir el ancho actual por 1.777777777778. Dado que no se puede comprobar el width del contenedor con solo CSS o dividir por un porcentaje es CSS, esto no es posible sin JavaScript (que yo sepa).

He escrito un script de trabajo que mantendrá la relación de aspecto deseada.

HTML

<div id="aspectRatio"></div>

CSS

body { width: 100%; height: 100%; padding: 0; margin: 0; }
#aspectRatio { background: #ff6a00; }

JavaScript

window.onload = function () {
    //Let's create a function that will scale an element with the desired ratio
    //Specify the element id, desired width, and height
    function keepAspectRatio(id, width, height) {
        var aspectRatioDiv = document.getElementById(id);
        aspectRatioDiv.style.width = window.innerWidth;
        aspectRatioDiv.style.height = (window.innerWidth / (width / height)) + "px";
    }

    //run the function when the window loads
    keepAspectRatio("aspectRatio", 16, 9);

    //run the function every time the window is resized
    window.onresize = function (event) {
        keepAspectRatio("aspectRatio", 16, 9);
    }
}

Puede utilizar el function de nuevo si desea mostrar algo más con una relación diferente mediante el uso de

keepAspectRatio(id, width, height);
 5
Author: MCSharp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-23 03:38:39

Ahora hay una nueva propiedad CSS especificada para abordar esto: object-fit.

Http://docs.webplatform.org/wiki/css/properties/object-fit

El soporte del navegador todavía carece de algo ( http://caniuse.com/#feat=object-fit ) - actualmente funciona hasta cierto punto en la mayoría de los navegadores excepto Microsoft-pero dado el tiempo es exactamente lo que se requiere para esta pregunta.

 1
Author: Henry Gibson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-24 23:35:50

La respuesta de Danield es buena, pero solo se puede usar cuando el div llena todo el viewport, o usando un poco de calc, se puede usar si se conoce el ancho y la altura del otro contenido en el viewport.

Sin embargo, al combinar el truco margin-bottom con el método en la respuesta mencionada anteriormente, el problema se puede reducir a solo tener que conocer la altura del otro contenido. Esto es útil si tiene un encabezado de altura fija, pero el ancho de la barra lateral, por ejemplo, no conocido.

body {
  margin: 0;
  margin-top: 100px; /* simulating a header */
}

main {
  margin: 0 auto;
  max-width: calc(200vh - 200px);
}

section {
  padding-bottom: 50%;
  position: relative;
}

div {
  position:absolute;
  background-color: red;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}
<main>
  <section>
    <div></div>
  </section>
</main>

Aquí está en un jsfiddle usando scss, lo que hace más obvio de dónde vienen los valores.

 0
Author: Cameron Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59