Scale image to fit a bounding box
Solution 1
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>
Solution 2
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%;
}
Solution 3
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>
Solution 4
Today, just say object-fit: contain. Support is everything but IE: http://caniuse.com/#feat=object-fit
Solution 5
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;*/
}
Thomas Guillory
Full stack web-dev I code in Ruby, Rails, Angular.js, Backbone.js... and I try some other things as soon as I have time. Lead Developper & Product Manager at altagem.com
Updated on January 28, 2022Comments
-
Thomas Guillory over 2 years
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:
- Use case 1 (works): http://jsfiddle.net/Jp5AQ/2/
- Use case 2 (works): http://jsfiddle.net/Jp5AQ/3/
But I want to scale up the image until a dimension is 100% of the container.
- Use case 3 (doesn't work): http://jsfiddle.net/Jp5AQ/4/
-
Khan about 12 yearsTry 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.
-
Misha Reyzlin about 12 yearsAlso, try to be more polite. No one is going to help you if you talk that way.
-
ericosg about 12 years@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.
-
Thomas Guillory about 12 yearsActually there is a solution: setting CSS3 background-size to contain. See my answer.
-
Stephan Muller about 12 yearsNice 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.
-
Thomas Guillory about 12 yearsYes 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.
-
arxpoetica over 11 yearsSet it to "cover" if you don't want any letterboxing: background-size: contain;
-
Andrey Mikhaylov - lolmaus over 10 yearsIt should be noted that you can inject image URLs with HTML:
<div class=image style="background-image: url('/images/foo.jpg');"></div>
. All other styles should be applied with CSS. -
animuson over 10 yearsI 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.
-
Stephan Muller over 10 yearsYou're totally right. Even though it's one and a half year later now, I edited my post.
-
Danny Dulai over 10 yearsalso it seems you lose the ability to put a border on the image if you do this.
-
duncanwilcox over 10 yearsI'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.
-
Christian Wattengård over 10 years@animuson: It still helped me as I'm using HTML/CSS for printed reports, and couldn't give a quack about semantics :)
-
Forza about 10 yearsWhat if I would like to change the image src using javascript? Would that still work if we use
image: url
? -
Salman A over 9 yearsWould it be better if you put the image tag inside the container (and hide it somehow). And use this trick as well.
-
ndm13 over 9 yearsI love this solution. Not only does it actually answer the question (I know, what a thought), it works beautifully in all modern browsers without having to resort to Javascript!
-
Colton McCormack over 9 yearsOP specifically asked for a css-only approach.
-
cyberwombat about 9 yearsThere is an IE8 polyfill here github.com/louisremi/background-size-polyfill
-
cyberwombat about 9 yearsI'd love to see a fiddle of that. In my test of placing an img in a 400x400 container the img just gets cropped in the corner
-
XwipeoutX almost 9 yearsThis answer only works when the box is taller than it is wide.
-
XwipeoutX almost 9 yearsNice answer! @Yashua You need to add
transform-origin: top left
to stop the cropping. /Zombie -
Codemonkey about 8 yearsBrilliant. My only concern would be a possible loss of image quality in a poorly-coded browser, but in theory it should work fine!
-
MattK almost 8 yearsInteresting, but doesn't work on Chrome. Results in a cropped row of the image.
-
Andrey Mikhaylov - lolmaus over 7 yearsGreat trick, but how do I center the image within the container?
-
Zhang over 7 yearsIE 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
-
Glenn Maynard over 7 yearsDon'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.
-
BairDev almost 7 yearsI'd say, that not IE is the problem, but Edge. According to caniuse
object-fit
is still under development for it. -
fgblomqvist almost 7 yearsThis 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
-
gabrielmaldi over 6 yearsI just posted an answer which works with and without
object-fit
: stackoverflow.com/a/46456673/474031 -
Andrey Mikhaylov - lolmaus over 5 years@MastaBaba,
margin: auto
only works for horizontal centering. It may work for vertical if container's width is preset, but that's not always the case. -
MastaBaba over 5 yearsRight. I thought you were only referring to horizontal centering.
-
Konstantin over 4 yearsI tried it without scale, just like that: max-width: 90%; max-height: 90% and it also worked. Why would you use scale, anyway?
-
Vladimir Panteleev almost 4 years@cyberwombat Five years too late, but I added a runnable snippet.
-
Vladimir Panteleev almost 4 years@Konstantin Scaling is only needed if you also want to enlarge the image (when it is smaller than the container's either width or height).
-
Timo over 3 yearsA 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. -
Max Waterman about 3 yearsHow do you get the dimensions of the image after scaling?
-
lxhom almost 3 yearsTo everyone who found this on Google like me: You can use object-fit to do that with pure CSS. developer.mozilla.org/en-US/docs/Web/CSS/object-fit
-
Stephan Muller almost 3 yearsThanks @lxhom, added that info too :)
-
Elikill58 over 2 yearsCan you edit your answer to explain why your post is different/better than other ?