132

Is there a css-only solution to scale an image into a bounding box (keeping aspect-ratio)? This works if the image is bigger than the container:

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

Example:

But I want to scale up the image until a dimension is 100% of the container.

sawa
  • 165,429
  • 45
  • 277
  • 381
Thomas Guillory
  • 5,719
  • 3
  • 24
  • 47
  • Do you mean like height: 100% and width: 100% ? do you have a desired dimension you want to reach? otherwise you could also stretch the image and force it to reach those dimensions too. – mikevoermans Apr 03 '12 at 13:42
  • @mikevoermans Look at my two first examples: I want to strech the image until one of the dimensions is 100% and the other is <=100% – Thomas Guillory Apr 03 '12 at 13:55
  • @jacktheripper Conserving aspect-ratio of course... – Thomas Guillory Apr 03 '12 at 13:59
  • @gryzzly The examples speaks for themselves! If they had looked to the examples, that was obvious. – Thomas Guillory Apr 03 '12 at 14:12
  • @Artimuz I completely disagree. Three of the answers to your questions (including mine) suggest that it was NOT obvious. – Khan Apr 03 '12 at 14:23

15 Answers15

185

Thanks to CSS3 there is a solution !

The solution is to put the image as background-image and then set the background-size to contain.

HTML

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

CSS

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

Test it here: http://www.w3schools.com/cssref/playit.asp?filename=playcss_background-size&preval=contain

Full compatibility with latest browsers: http://caniuse.com/background-img-opts

To align the div in the center, you can use this variation:

.bounding-box {
  background-image: url(...);
  background-size: contain;
  position: absolute;
  background-position: center;
  background-repeat: no-repeat;
  height: 100%;
  width: 100%;
}
Charles Brunet
  • 21,797
  • 24
  • 83
  • 124
Thomas Guillory
  • 5,719
  • 3
  • 24
  • 47
  • 1
    Nice one, although my answer isn't incorrect (you were asking about the img specifically) this is a great solution and I should've thought of that. The only problem is that IE 8 is still so widely used that I wouldn't want to rely on this yet, but nice catch nonetheless. – Stephan Muller Apr 05 '12 at 10:49
  • Yes you're right, your answer is not incorrect: I will mark it as accepted and integrate this specific solution in the question for those who google that. – Thomas Guillory Apr 05 '12 at 11:23
  • 6
    Set it to "cover" if you don't want any letterboxing: background-size: contain; – arxpoetica Dec 06 '12 at 16:55
  • 3
    It should be noted that you can inject image URLs with HTML: `
    `. All other styles should be applied with CSS.
    – Andrey Mikhaylov - lolmaus Aug 28 '13 at 19:09
  • 17
    I would say this is a terrible approach. By changing it to a background-image, you're removing the semantic meaning of the image in the HTML. – animuson Sep 06 '13 at 00:16
  • 1
    also it seems you lose the ability to put a border on the image if you do this. – Danny Dulai Oct 20 '13 at 15:02
  • 18
    @animuson: It still helped me as I'm using HTML/CSS for printed reports, and couldn't give a quack about semantics :) – Christian Wattengård Jan 07 '14 at 11:46
  • What if I would like to change the image src using javascript? Would that still work if we use `image: url`? – Forza Feb 19 '14 at 15:41
  • 1
    Would it be better if you put the image tag inside the container (and hide it somehow). And use this trick as well. – Salman A Nov 01 '14 at 14:34
  • There is an IE8 polyfill here https://github.com/louisremi/background-size-polyfill – cyberwombat Apr 09 '15 at 22:21
  • A practical example of how the semantics matters is that, if anyone wanted to print your web page then at least Chrome by default seems to ignore background images like these from printing.. which, you know, semantically makes sense.. better to use that `object-fit` approach in the world today. Hardly any browsers out there not supporting it. – Timo Oct 04 '20 at 13:25
107

Note: Even though this is the accepted answer, the answer below is more accurate and is currently supported in all browsers if you have the option of using a background image.

Edit 2: In the modern age, using object-fit might be an even better solution: https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit

No, there is no CSS only way to do this in both directions. You could add

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

To the an element to always have it 100% width and automatically scale the height to the aspect ratio, or the inverse:

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

to always scale to max height and relative width. To do both, you will need to determine if the aspect ratio is higher or lower than it's container, and CSS can't do this.

The reason is that CSS does not know what the page looks like. It sets rules beforehand, but only after that it is that the elements get rendered and you know exactly what sizes and ratios you're dealing with. The only way to detect that is with JavaScript.


Although you're not looking for a JS solution I'll add one anyway if someone might need it. The easiest way to handle this with JavaScript is to add a class based on the difference in ratio. If the width-to-height ratio of the box is greater than that of the image, add the class "fillwidth", else add the class "fillheight".

$('div').each(function() {
  var fillClass = ($(this).height() > $(this).width()) 
    ? 'fillheight'
    : 'fillwidth';
  $(this).find('img').addClass(fillClass);
});
.fillwidth { 
  width: 100%; 
  height: auto; 
}
.fillheight { 
  height: 100%; 
  width: auto; 
}

div {
  border: 1px solid black;
  overflow: hidden;
}

.tower {
  width: 100px;
  height: 200px;
}

.trailer {
  width: 200px;
  height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tower">
  <img src="http://placekitten.com/150/150" />
</div>
<div class="trailer">
  <img src="http://placekitten.com/150/150" />
</div>
Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
  • 8
    Actually there is a solution: setting CSS3 background-size to contain. See my answer. – Thomas Guillory Apr 04 '12 at 17:57
  • You're totally right. Even though it's one and a half year later now, I edited my post. – Stephan Muller Sep 17 '13 at 14:01
  • 4
    I'd posit that this is the correct answer for the question asked, which is what's the CSS for the img tag. This is relevant because semantically the img tag is content, the image as background to a div isn't. While some circumstances make this impractical (if you don't know image vs. container ratio), for others it's just right. Thanks. – duncanwilcox Jan 02 '14 at 11:43
  • 1
    To everyone who found this on Google like me: You can use object-fit to do that with pure CSS. https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit – lxhom Aug 08 '21 at 16:49
  • 1
    Thanks @lxhom, added that info too :) – Stephan Muller Aug 12 '21 at 15:03
40

Here's a hackish solution I discovered:

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

This will enlarge the image tenfold, but restrict it to 10% of its final size - thus bounding it to the container.

Unlike the background-image solution, this will also work with <video> elements.

Interactive example:

 function step(timestamp) {
     var container = document.getElementById('container');
     timestamp /= 1000;
     container.style.left   = (200 + 100 * Math.sin(timestamp * 1.0)) + 'px';
     container.style.top    = (200 + 100 * Math.sin(timestamp * 1.1)) + 'px';
     container.style.width  = (500 + 500 * Math.sin(timestamp * 1.2)) + 'px';
     container.style.height = (500 + 500 * Math.sin(timestamp * 1.3)) + 'px';
     window.requestAnimationFrame(step);
 }

 window.requestAnimationFrame(step);
 #container {
     outline: 1px solid black;
     position: relative;
     background-color: red;
 }
 #image {
     display: block;
     max-width: 10%;
     max-height: 10%;
     transform-origin: 0 0;
     transform: scale(10);
 }
<div id="container">
    <img id="image" src="https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png">
</div>
Vladimir Panteleev
  • 24,651
  • 6
  • 70
  • 114
29

Today, just say object-fit: contain. Support is everything but IE: http://caniuse.com/#feat=object-fit

Glenn Maynard
  • 55,829
  • 10
  • 121
  • 131
  • 4
    IE only has about 16% market share now at the time of writing this (09/12/2016 10:56am) and continues to dwindle, so this is best answer for me :D – Zhang Dec 09 '16 at 02:56
  • 14
    Don't edit other people's answers to fix things other than typos or broken links. I wouldn't say something childish like "There is a polyfill for crap browsers" in an SO answer, and I don't appreciate my answer being edited to make it look like I said that. if you want to use your words, put them in your own answer. – Glenn Maynard Dec 18 '16 at 22:01
  • I'd say, that not IE is the problem, but Edge. According to caniuse `object-fit` is still under development for it. – BairDev Jun 09 '17 at 07:47
  • This should be one of the top-voted answers 2017 and onwards... According to the caniuse link above, 90% of all users globally now use a browser that supports this – fgblomqvist Jul 27 '17 at 13:40
  • I just posted an answer which works with and without `object-fit`: https://stackoverflow.com/a/46456673/474031 – gabrielmaldi Sep 27 '17 at 20:28
  • How do you get the dimensions of the image after scaling? – Max Waterman Feb 19 '21 at 08:35
10

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
  • 4,451
  • 4
  • 44
  • 65
5

You can accomplish this with pure CSS and complete browser support, both for vertically-long and horizontally-long images at the same time.

Here's a snippet which works in Chrome, Firefox, and Safari (both using object-fit: scale-down, and without using it):

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
  • 2,157
  • 2
  • 23
  • 39
3

Another solution without background image and without the need for a container (though the max sizes of the bounding box must be known):

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


If a container's use is required, then the max-width and max-height can be set to 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;
}

For this you would have something like:

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

This example to stretch the image proportionally to fit the entire window. An improvisation to the above correct code is to add $( 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();
});

There are two if conditions. The first one keeps checking if the image height is less than the div and applies .fillheight class while the next checks for width and applies .fillwidth class. In both cases the other class is removed using .removeClass()

Here is the CSS

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

You can replace 100vh by 100% if you want to stretch the image with in a div. This example to stretch the image proportionally to fit the entire window.

Mr. JCRP
  • 11
  • 1
0

I have used table to center image inside the box. It keeps aspect ratio and scales image in a way that is totally inside the box. If the image is smaller than the box then it is shown as it is in the center. Below code uses 40px width and 40px height box. (Not quite sure how well it works because I removed it from another more complex code and simplified it little bit)

.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;
}
<table class="SmallThumbnailContainer" cellpadding="0" cellspacing="0">
  <tr>
    <td>
      <img src="https://www.gravatar.com/avatar/bf7d39f4ed9c289feca7de38a0093250?s=32&d=identicon&r=PG" width="32" height="32" alt="OP's SO avatar image used as a sample jpg because it is hosted on SO, thus always available" />
    </td>
  </tr>
</table>

Note: the native thumbnail size in this snippet is 32px x 32px, which is smaller than its 40px x 40px container. If the container is instead sized smaller than the thumbnail in any dimension, say 40px x 20px, the image flows outside the container in the dimensions that are smaller than the corresponding image dimension. The container is marked by a gray 1px border.

SherylHohman
  • 16,580
  • 17
  • 88
  • 94
Antti
  • 1,029
  • 12
  • 15
0

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

The HTML:

<div class="image-wrapper">
  <img src="yourSource.jpg">
</div>
miken32
  • 42,008
  • 16
  • 111
  • 154
0
.img-class {
  width: <img width>;
  height: <img height>;
  content: url('/path/to/img.png');
}

Then on the element (you can use javascript or media queries to add responsiveness):

<div class='img-class' style='transform: scale(X);'></div>
miken32
  • 42,008
  • 16
  • 111
  • 154
bman93
  • 1
  • 1
0

Use Object Fit on both div and img to scale image

<div class="box"><img src="image.jpg"></div>

.box {height: auto;
object-fit: cover;} 

img { height: 100%; object-fit: cover; }
Nisha Ankit
  • 151
  • 9
0

This worked for my needs, doesn't flatten out the image while setting height limitation, it overflows instead.

.top-container{
       width:50%;
    }
.img-container {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 40vh;
        width: 100%;
        overflow: hidden;
    }
    
    .img-container img {
        max-width: 10%;
        max-height: auto;
        transform: scale(10);
    }
<div class='top-container'>
 <div class='img-container'>
  <img src='image.jpg'>
 </div>
</div>
Dimanjan
  • 563
  • 6
  • 13
0

Are you looking to scale upwards but not downwards?

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

This however, does not lock aspect-ratio.

ericosg
  • 4,926
  • 4
  • 37
  • 59
  • 5
    Try to be a little more clear with your expectations before down-voting someone's answer. Especially when they've answered your question before you've cleared up your question with edits. – Khan Apr 03 '12 at 13:54
  • 2
    Also, try to be more polite. No one is going to help you if you talk that way. – Misha Reyzlin Apr 03 '12 at 14:07
  • @Artimuz My apologies if I miss-guided you, but it seemed unclear to me that you wished to keep aspect-ratio, which is why I commented on that specifically. Also, you'll notice that I pasted a snippet of your code from the examples. I believe keeping height: auto; will do that for you if you specify a width. – ericosg Apr 03 '12 at 14:09
-3
.boundingbox {
    width: 400px;
    height: 500px;
    border: 2px solid #F63;
}
img{
    width:400px;
    max-height: 500px;
    height:auto;
}

With the styles set as shown above in css, now the following html div will show the image always fit width wise and will adjust hight aspect ratio to width. Thus image will scale to fit a bounding box as asked in the question.

<div class="boundingbox"><img src="image.jpg"/></div>
miken32
  • 42,008
  • 16
  • 111
  • 154
zeeawan
  • 6,667
  • 2
  • 50
  • 56