Escalar la imagen para que se ajuste a un cuadro delimitador

117

¿Existe una solución de solo CSS para escalar una imagen en un cuadro delimitador (manteniendo la relación de aspecto)? Esto funciona si la imagen es más grande que el contenedor:

img {
  max-width: 100%;
  max-height: 100%;
}

Ejemplo:

Pero quiero escalar la imagen hasta que una dimensión sea el 100% del contenedor.

Thomas Guillory
fuente
¿Te refieres a altura: 100% y ancho: 100%? ¿Tiene una dimensión deseada que desea alcanzar? de lo contrario, también podría estirar la imagen y obligarla a alcanzar esas dimensiones.
mikevoermans
@mikevoermans Mira mis dos primeros ejemplos: quiero estirar la imagen hasta que una de las dimensiones sea del 100% y la otra sea <= 100%
Thomas Guillory
@jacktheripper Conservando la relación de aspecto, por supuesto ...
Thomas Guillory
@gryzzly ¡Los ejemplos hablan por sí mismos! Si habían mirado los ejemplos, era obvio.
Thomas Guillory
@Artimuz Estoy completamente en desacuerdo. Tres de las respuestas a sus preguntas (incluida la mía) sugieren que NO era obvio.
Khan

Respuestas:

94

Nota: aunque esta es la respuesta aceptada, la respuesta a continuación es más precisa y actualmente es compatible con todos los navegadores si tiene la opción de usar una imagen de fondo.

No, no existe una única forma de CSS para hacer esto en ambas direcciones. Podrías agregar

.fillwidth {
    min-width: 100%;
    height: auto;
}

Para que un elemento tenga siempre un ancho del 100% y escale automáticamente la altura a la relación de aspecto, o a la inversa:

.fillheight {
    min-height: 100%; 
    width: auto;
}

para escalar siempre a la altura máxima y al ancho relativo. Para hacer ambas cosas, deberá determinar si la relación de aspecto es mayor o menor que su contenedor, y CSS no puede hacer esto.

La razón es que CSS no sabe cómo se ve la página. Establece reglas de antemano, pero solo después de eso, los elementos se renderizan y usted sabe exactamente con qué tamaños y proporciones está tratando. La única forma de detectarlo es con JavaScript.


Aunque no está buscando una solución JS, agregaré una de todos modos si alguien la necesita. La forma más fácil de manejar esto con JavaScript es agregar una clase basada en la diferencia de proporción. Si la relación ancho-alto del cuadro es mayor que la de la imagen, agregue la clase "fillwidth", de lo contrario agregue la clase "fillheight".

Stephan Muller
fuente
7
En realidad, hay una solución: configurar el tamaño de fondo de CSS3 para contener. Mira mi respuesta.
Thomas Guillory
Tienes toda la razón. A pesar de que ha pasado un año y medio, edité mi publicación.
Stephan Muller
4
Postularía que esta es la respuesta correcta para la pregunta formulada, que es el CSS de la etiqueta img. Esto es relevante porque semánticamente la etiqueta img es contenido, la imagen como fondo de un div no lo es. Si bien algunas circunstancias hacen que esto no sea práctico (si no conoce la relación de imagen frente a contenedor), para otras es lo correcto. Gracias.
Duncanwilcox
173

¡Gracias a CSS3 hay una solución!

La solución es poner la imagen como background-imagea continuación, establecer el background-sizea contain.

HTML

<div class='bounding-box'>
</div>

CSS

.bounding-box {
  background-image: url(...);
  background-repeat: no-repeat;
  background-size: contain;
}

Pruébelo aquí: http://www.w3schools.com/cssref/playit.asp?filename=playcss_background-size&preval=contain

Total compatibilidad con los últimos navegadores: http://caniuse.com/background-img-opts

Para alinear el div en el centro, puede usar esta variación:

.bounding-box {
  background-image: url(...);
  background-size: contain;
  position: absolute;
  background-position: center;
  background-repeat: no-repeat;
  height: 100%;
  width: 100%;
}
Thomas Guillory
fuente
1
Buena, aunque mi respuesta no es incorrecta (estabas preguntando sobre el img específicamente), esta es una gran solución y debería haber pensado en eso. El único problema es que IE 8 todavía se usa tan ampliamente que no querría confiar en esto todavía, pero una buena captura de todos modos.
Stephan Muller
6
Ajústelo a "cubrir" si no desea ningún formato de pantalla ancha: tamaño de fondo: contener;
arxpoetica
3
Debe tenerse en cuenta que se puede inyectar URL de imágenes con HTML: <div class=image style="background-image: url('/images/foo.jpg');"></div>. Todos los demás estilos deben aplicarse con CSS.
Andrey Mikhaylov - lolmaus
14
Diría que este es un enfoque terrible. Al cambiarlo a una imagen de fondo, está eliminando el significado semántico de la imagen en el HTML.
animuson
14
@animuson: Todavía me ayudó, ya que estoy usando HTML / CSS para informes impresos, y no me importa un bledo la semántica :)
Christian Wattengård
37

Aquí hay una solución pirateada que descubrí:

#image {
    max-width: 10%;
    max-height: 10%;
    transform: scale(10);
}

Esto agrandará la imagen diez veces, pero la restringirá al 10% de su tamaño final, limitándola así al contenedor.

A diferencia de la background-imagesolución, esto también funcionará con <video>elementos.

Ejemplo interactivo:

Vladimir Panteleev
fuente
1
Amo esta solucion No solo responde realmente la pregunta (lo sé, qué pensamiento), ¡funciona maravillosamente en todos los navegadores modernos sin tener que recurrir a Javascript!
ndm13
2
Me encantaría ver un violín de eso. En mi prueba de colocar un img en un contenedor de 400x400, el img simplemente se recorta en la esquina
cyberwombat
3
¡Buena respuesta! @Yashua Necesita agregar transform-origin: top leftpara detener el recorte. / Zombie
XwipeoutX
Brillante. Mi única preocupación sería una posible pérdida de calidad de imagen en un navegador mal codificado, pero en teoría debería funcionar bien.
Codemonkey
Interesante, pero no funciona en Chrome. Da como resultado una fila recortada de la imagen.
MattK
23

Hoy, solo diga object-fit: contener. El soporte lo es todo menos IE: http://caniuse.com/#feat=object-fit

Glenn Maynard
fuente
3
IE solo tiene alrededor del 16% de participación de mercado en el momento de escribir esto (12/09/2016 10:56 am) y continúa disminuyendo, por lo que esta es la mejor respuesta para mí: D
Zhang
8
No edite las respuestas de otras personas para corregir cosas que no sean errores tipográficos o enlaces rotos. No diría algo infantil como "Hay un polyfill para navegadores basura" en una respuesta SO, y no aprecio que mi respuesta sea editada para que parezca que dije eso. si quieres usar tus palabras, ponlas en tu propia respuesta.
Glenn Maynard
Yo diría que el problema no es IE, sino Edge. Según caniuse object-fittodavía está en desarrollo para ello.
BairDev
Esta debería ser una de las respuestas más votadas en 2017 y en adelante ... Según el enlace caniuse anterior, el 90% de todos los usuarios a nivel mundial ahora usan un navegador que lo admita
fgblomqvist
Acabo de publicar una respuesta que funciona con y sin object-fit: stackoverflow.com/a/46456673/474031
gabrielmaldi
8

html:

    <div class="container">
      <img class="flowerImg" src="flower.jpg">
    </div>

css:

.container{
  width: 100px;
  height: 100px;
}


.flowerImg{
  width: 100px;
  height: 100px;
  object-fit: cover;
  /*object-fit: contain;
  object-fit: scale-down;
  object-position: -10% 0;
  object-fit: none;
  object-fit: fill;*/
}
Deke
fuente
5

Puede lograr esto con CSS puro y soporte completo del navegador, tanto para imágenes de longitud vertical como horizontal al mismo tiempo.

Aquí hay un fragmento que funciona en Chrome, Firefox y Safari (ambos usándolo object-fit: scale-downy sin usarlo):

figure {
  margin: 0;
}

.container {
  display: table-cell;
  vertical-align: middle;
  width: 80px;
  height: 80px;
  border: 1px solid #aaa;
}

.container_image {
  display: block;
  max-width: 100%;
  max-height: 100%;
  margin-left: auto;
  margin-right: auto;
}

.container2_image2 {
  width: 80px;
  height: 80px;
  object-fit: scale-down;
  border: 1px solid #aaa;
}
Without `object-fit: scale-down`:

<br>
<br>

<figure class="container">
  <img class="container_image" src="https://i.imgur.com/EQgexUd.jpg">
</figure>

<br>

<figure class="container">
  <img class="container_image" src="https://i.imgur.com/ptO8pGi.jpg">
</figure>

<br> Using `object-fit: scale-down`:

<br>
<br>

<figure>
  <img class="container2_image2" src="https://i.imgur.com/EQgexUd.jpg">
</figure>

<br>

<figure>
  <img class="container2_image2" src="https://i.imgur.com/ptO8pGi.jpg">
</figure>

Gabrielmaldi
fuente
2

Otra solución sin imagen de fondo y sin la necesidad de un contenedor (aunque se deben conocer los tamaños máximos del cuadro delimitador):

img{
  max-height: 100px;
  max-width: 100px;
  width: auto;    /* These two are added only for clarity, */
  height: auto;   /* as the default is auto anyway */
}


Si se requiere el uso de un contenedor, entonces el ancho máximo y la altura máxima se pueden establecer en 100%:

img {
    max-height: 100%;
    max-width: 100%;
    width: auto; /* These two are added only for clarity, */
    height: auto; /* as the default is auto anyway */
}

div.container {
    width: 100px;
    height: 100px;
}

Para esto tendrías algo como:

<table>
    <tr>
        <td>Lorem</td>
        <td>Ipsum<br />dolor</td>
        <td>
            <div class="container"><img src="image5.png" /></div>
        </td>
    </tr>
</table>
xerxeArt
fuente
1

Este ejemplo para estirar la imagen proporcionalmente para que se ajuste a toda la ventana. Una improvisación del código correcto anterior es agregar$( window ).resize(function(){});

function stretchImg(){
    $('div').each(function() {
      ($(this).height() > $(this).find('img').height()) 
        ? $(this).find('img').removeClass('fillwidth').addClass('fillheight')
        : '';
      ($(this).width() > $(this).find('img').width()) 
        ? $(this).find('img').removeClass('fillheight').addClass('fillwidth')
        : '';
    });
}
stretchImg();

$( window ).resize(function() {
    strechImg();
});

Hay dos condiciones if. El primero sigue comprobando si la altura de la imagen es menor que el div y aplica la .fillheightclase, mientras que el siguiente comprueba el ancho y aplica la .fillwidthclase. En ambos casos, la otra clase se elimina usando.removeClass()

Aquí está el CSS

.fillwidth { 
   width: 100%;
   max-width: none;
   height: auto; 
}
.fillheight { 
   height: 100vh;
   max-width: none;
   width: auto; 
}

Puede reemplazar 100vhpor 100%si desea estirar la imagen en un div. Este ejemplo para estirar la imagen proporcionalmente para que se ajuste a toda la ventana.

Sr. JCRP
fuente
OP solicitó específicamente un enfoque solo de CSS.
Colt McCormack
0

¿Está buscando escalar hacia arriba pero no hacia abajo?

div {
    border: solid 1px green;
    width: 60px;
    height: 70px;
}

div img {
    width: 100%;
    height: 100%;
    min-height: 500px;
    min-width: 500px;
    outline: solid 1px red;
}

Sin embargo, esto no bloquea la relación de aspecto.

ericosg
fuente
5
Trate de ser un poco más claro con sus expectativas antes de rechazar la respuesta de alguien. Especialmente cuando han respondido a su pregunta antes de que la haya aclarado con ediciones.
Khan
2
Además, trate de ser más educado. Nadie te ayudará si hablas de esa manera.
Misha Reyzlin
@Artimuz Mis disculpas si no lo guié, pero no me pareció claro que deseara mantener la relación de aspecto, por eso lo comenté específicamente. Además, notará que pegué un fragmento de su código de los ejemplos. Creo que mantener la altura: automático; lo hará por usted si especifica un ancho.
ericosg
0

He usado una tabla para centrar la imagen dentro de la caja. Mantiene la relación de aspecto y escala la imagen de una manera que está totalmente dentro de la caja. Si la imagen es más pequeña que el cuadro, se muestra como está en el centro. El siguiente código utiliza un cuadro de 40 píxeles de ancho y 40 píxeles de alto. (No estoy muy seguro de qué tan bien funciona porque lo eliminé de otro código más complejo y lo simplifiqué un poco)

CSS:

.SmallThumbnailContainer
{
    display: inline-block; position: relative;
    float: left;    
    width: 40px;
    height: 40px;
    border: 1px solid #ccc;
    margin: 0px; padding: 0px;
}
.SmallThumbnailContainer { width: 40px; margin: 0px 10px 0px 0px; } 
.SmallThumbnailContainer tr { height: 40px; text-align: center; }
.SmallThumbnailContainer tr td { vertical-align: middle; position: relative; width: 40px;  }
.SmallThumbnailContainer tr td img { overflow: hidden; max-height: 40px; max-width: 40px; vertical-align: middle; margin: -1px -1px 1px -1px; }

HTML:

<table class="SmallThumbnailContainer" cellpadding="0" cellspacing="0">
    <tr><td>
        <img src="thumbnail.jpg" alt="alternative text"/>
    </td></tr>
    </table>
Antti
fuente
0

La forma más limpia y sencilla de hacer esto:

Primero algo de CSS:

div.image-wrapper {
    height: 230px; /* Suggestive number; pick your own height as desired */
    position: relative;
    overflow: hidden; /* This will do the magic */
    width: 300px; /* Pick an appropriate width as desired, unless you already use a grid, in that case use 100% */
}
img {
    width: 100%;
    position: absolute;
    left: 0;
    top: 0;
    height: auto;
}

El HTML:

<div class="image-wrapper">
  <img src="yourSource.jpg">
</div>

¡Esto debería funcionar!

Robert Eetheart
fuente
0

Esto me ayudó:

.img-class {
  width: <img width>;
  height: <img height>;
  content: url('/path/to/img.png');
}

Luego, en el elemento (puede usar javascript o consultas de medios para agregar capacidad de respuesta):

<div class='img-class' style='transform: scale(X);'></div>

¡Espero que esto ayude!

bman93
fuente
-3
.boundingbox {
    width: 400px;
    height: 500px;
    border: 2px solid #F63;
}
img{
    width:400px;
    max-height: 500px;
    height:auto;
}

Estoy editando mi respuesta para explicar más mi solución, ya que tengo un voto en contra.

Con los estilos configurados como se muestra arriba en css, ahora el siguiente div html mostrará que la imagen siempre se ajusta al ancho y ajustará la relación de aspecto alto al ancho. Por lo tanto, la imagen se escalará para ajustarse a un cuadro delimitador como se pide en la pregunta.

<div class="boundingbox"><img src="image.jpg"/></div>
Zeeawan
fuente
Esta respuesta solo funciona cuando la caja es más alta que ancha.
XwipeoutX