Mettre l'image à l'échelle pour l'adapter à un cadre de sélection

117

Existe-t-il une solution css uniquement pour mettre à l'échelle une image dans un cadre de sélection (en conservant les proportions)? Cela fonctionne si l'image est plus grande que le conteneur:

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

Exemple:

Mais je veux agrandir l'image jusqu'à ce qu'une dimension soit 100% du conteneur.

Thomas Guillory
la source
Voulez-vous dire comme hauteur: 100% et largeur: 100%? avez-vous une dimension souhaitée que vous souhaitez atteindre? Sinon, vous pouvez également étirer l'image et la forcer à atteindre ces dimensions.
mikevoermans
@mikevoermans Regardez mes deux premiers exemples: je veux étirer l'image jusqu'à ce que l'une des dimensions soit à 100% et l'autre à <= 100%
Thomas Guillory
@jacktheripper Conserver le rapport hauteur / largeur bien sûr ...
Thomas Guillory
@gryzzly Les exemples parlent d'eux-mêmes! S'ils avaient regardé les exemples, c'était évident.
Thomas Guillory
@Artimuz Je ne suis pas du tout d'accord. Trois des réponses à vos questions (y compris la mienne) suggèrent que ce n'était PAS évident.
Khan

Réponses:

94

Remarque: Même s'il s'agit de la réponse acceptée, la réponse ci - dessous est plus précise et est actuellement prise en charge dans tous les navigateurs si vous avez la possibilité d'utiliser une image d'arrière-plan.

Non, il n'y a pas de moyen CSS uniquement pour le faire dans les deux sens. Vous pourriez ajouter

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

Pour que l'élément an ait toujours une largeur de 100% et ajuste automatiquement la hauteur au rapport hauteur / largeur, ou à l'inverse:

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

pour toujours mettre à l'échelle la hauteur maximale et la largeur relative. Pour faire les deux, vous devrez déterminer si le rapport hauteur / largeur est supérieur ou inférieur à celui de son conteneur, et CSS ne peut pas le faire.

La raison en est que CSS ne sait pas à quoi ressemble la page. Il définit les règles à l'avance, mais ce n'est qu'après que les éléments sont rendus et que vous savez exactement à quelles tailles et à quels rapports vous avez affaire. Le seul moyen de détecter cela est d'utiliser JavaScript.


Bien que vous ne cherchiez pas de solution JS, j'en ajouterai quand même une si quelqu'un en a besoin. Le moyen le plus simple de gérer cela avec JavaScript est d'ajouter une classe basée sur la différence de ratio. Si le rapport largeur / hauteur de la boîte est supérieur à celui de l'image, ajoutez la classe "fillwidth", sinon ajoutez la classe "fillheight".

Stéphan Muller
la source
7
En fait, il existe une solution: définir la taille de fond CSS3 à contenir. Voyez ma réponse.
Thomas Guillory
Vous avez tout à fait raison. Même si c'est un an et demi plus tard maintenant, j'ai édité mon article.
Stephan Muller
4
Je dirais que c'est la bonne réponse à la question posée, qui est le CSS pour la balise img. Ceci est pertinent car sémantiquement la balise img est content, l'image comme arrière-plan d'un div ne l'est pas. Alors que certaines circonstances rendent cela irréalisable (si vous ne connaissez pas le rapport image / conteneur), pour d'autres, c'est juste. Merci.
duncanwilcox
173

Grâce à CSS3, il existe une solution!

La solution consiste à mettre l'image en tant que background-image, puis à définir le background-sizesur contain.

HTML

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

CSS

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

Testez-le ici: http://www.w3schools.com/cssref/playit.asp?filename=playcss_background-size&preval=contain

Compatibilité totale avec les derniers navigateurs: http://caniuse.com/background-img-opts

Pour aligner le div au centre, vous pouvez utiliser cette variante:

.bounding-box {
  background-image: url(...);
  background-size: contain;
  position: absolute;
  background-position: center;
  background-repeat: no-repeat;
  height: 100%;
  width: 100%;
}
Thomas Guillory
la source
1
Belle, bien que ma réponse ne soit pas incorrecte (vous posiez des questions sur l'img en particulier), c'est une excellente solution et j'aurais dû y penser. Le seul problème est que IE 8 est encore si largement utilisé que je ne voudrais pas encore me fier à cela, mais belle prise quand même.
Stephan Muller
6
Réglez-le sur "cover" si vous ne voulez pas de letterbox: background-size: contain;
arxpoetica
3
Il convient de noter que vous pouvez injecter URL d'image avec HTML: <div class=image style="background-image: url('/images/foo.jpg');"></div>. Tous les autres styles doivent être appliqués avec CSS.
Andrey Mikhaylov - lolmaus
14
Je dirais que c'est une approche terrible. En le changeant en image d'arrière-plan, vous supprimez la signification sémantique de l'image dans le HTML.
animuson
14
@animuson: Cela m'a toujours aidé car j'utilise HTML / CSS pour les rapports imprimés, et je ne pouvais pas faire un charlatan sur la sémantique :)
Christian Wattengård
37

Voici une solution hackish que j'ai découverte:

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

Cela agrandira l'image dix fois, mais la limitera à 10% de sa taille finale, la liant ainsi au conteneur.

Contrairement à la background-imagesolution, cela fonctionnera également avec<video> éléments.

Exemple interactif:

Vladimir Panteleev
la source
1
J'adore cette solution. Non seulement il répond réellement à la question (je sais, quelle pensée), mais il fonctionne à merveille dans tous les navigateurs modernes sans avoir à recourir à Javascript!
ndm13
2
J'adorerais voir un violon de cela. Dans mon test de placement d'une image dans un conteneur de 400x400, l'image est juste rognée dans le coin
cyberwombat
3
Bonne réponse! @Yashua Vous devez ajouter transform-origin: top leftpour arrêter le recadrage. / Zombie
XwipeoutX
Brillant. Ma seule préoccupation serait une possible perte de qualité d'image dans un navigateur mal codé, mais en théorie cela devrait fonctionner correctement!
Codemonkey
Intéressant, mais ne fonctionne pas sur Chrome. Résultats dans une ligne recadrée de l'image.
MattK
23

Aujourd'hui, dites simplement object-fit: contenir. Le support est tout sauf IE: http://caniuse.com/#feat=object-fit

Glenn Maynard
la source
3
IE ne détient actuellement qu'environ 16% de part de marché au moment de la rédaction de cet article (09/12/2016 10h56) et continue de diminuer, c'est donc la meilleure réponse pour moi: D
Zhang
8
Ne modifiez pas les réponses d'autres personnes pour corriger des choses autres que des fautes de frappe ou des liens rompus. Je ne dirais pas quelque chose d'enfant comme "Il y a un polyfill pour les navigateurs de merde" dans une réponse SO, et je n'apprécie pas que ma réponse soit éditée pour donner l'impression que j'ai dit cela. si vous voulez utiliser vos mots, mettez-les dans votre propre réponse.
Glenn Maynard
Je dirais que le problème n'est pas IE, mais Edge. Selon caniuse object-fitest encore en cours de développement pour cela.
BairDev
Cela devrait être l'une des réponses les plus votées en 2017 et au-delà ... Selon le lien caniuse ci-dessus, 90% de tous les utilisateurs dans le monde utilisent maintenant un navigateur qui prend en charge cela
fgblomqvist
Je viens de publier une réponse qui fonctionne avec et sans 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
la source
5

Vous pouvez accomplir cela avec du CSS pur et une prise en charge complète du navigateur, à la fois pour des images verticales et horizontales en même temps.

Voici un extrait de code qui fonctionne dans Chrome, Firefox et Safari (à la fois en utilisant object-fit: scale-downet sans l'utiliser):

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
la source
2

Une autre solution sans image de fond et sans besoin de conteneur (bien que les tailles maximales du cadre de sélection doivent être connues):

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 l'utilisation d'un conteneur est requise, alors la largeur maximale et la hauteur maximale peuvent être définies sur 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;
}

Pour cela, vous auriez quelque chose comme:

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

Cet exemple permet d'étirer l'image proportionnellement pour l'adapter à toute la fenêtre. Une improvisation au code correct ci-dessus consiste à ajouter$( 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();
});

Il y a deux conditions si. Le premier vérifie si la hauteur de l'image est inférieure au div et applique la .fillheightclasse tandis que le suivant vérifie la largeur et applique la .fillwidthclasse. Dans les deux cas, l'autre classe est supprimée en utilisant.removeClass()

Voici le CSS

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

Vous pouvez remplacer 100vhpar 100%si vous souhaitez étirer l'image par dans un div. Cet exemple permet d'étirer l'image proportionnellement pour l'adapter à toute la fenêtre.

M. JCRP
la source
OP a spécifiquement demandé une approche css uniquement.
Colt McCormack
0

Cherchez-vous à évoluer vers le haut mais pas vers le bas?

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

Cependant, cela ne verrouille pas le rapport hauteur / largeur.

ericosg
la source
5
Essayez d'être un peu plus clair avec vos attentes avant de voter contre la réponse de quelqu'un. Surtout quand ils ont répondu à votre question avant que vous n'ayez clarifié votre question avec des modifications.
Khan
2
Essayez également d'être plus poli. Personne ne vous aidera si vous parlez de cette façon.
Misha Reyzlin
@Artimuz Mes excuses si je vous ai mal guidé, mais il ne m'a semblé pas clair que vous souhaitiez conserver les proportions, c'est pourquoi j'ai commenté cela spécifiquement. De plus, vous remarquerez que j'ai collé un extrait de votre code à partir des exemples. Je crois garder la hauteur: auto; le fera pour vous si vous spécifiez une largeur.
ericosg
0

J'ai utilisé une table pour centrer l'image à l'intérieur de la boîte. Il conserve le rapport hauteur / largeur et redimensionne l'image d'une manière totalement à l'intérieur de la boîte. Si l'image est plus petite que la boîte, elle est affichée telle qu'elle est au centre. Le code ci-dessous utilise une largeur de 40 px et une zone de hauteur de 40 px. (Je ne sais pas si cela fonctionne bien car je l'ai supprimé d'un autre code plus complexe et l'ai simplifié un peu)

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
la source
0

Le moyen le plus propre et le plus simple de le faire:

Tout d'abord un peu 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;
}

Le HTML:

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

Cela devrait faire l'affaire!

Robert Eetheart
la source
0

Cela m'a aidé:

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

Ensuite sur l'élément (vous pouvez utiliser javascript ou media queries pour ajouter de la réactivité):

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

J'espère que cela t'aides!

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

J'édite ma réponse pour expliquer davantage ma soluton car j'ai un vote négatif.

Avec les styles définis comme indiqué ci-dessus en css, maintenant le div html suivant montrera que l'image s'ajustera toujours dans le sens de la largeur et ajustera le rapport hauteur / largeur élevé. Ainsi, l'image sera mise à l' échelle pour s'adapter à une boîte englobante comme demandé dans la question.

<div class="boundingbox"><img src="image.jpg"/></div>
Zeeawan
la source
Cette réponse ne fonctionne que lorsque la boîte est plus haute que large.
XwipeoutX