blueFast
blueFast

Reputation: 44361

Scale an image to maximally fit available space and center it

I am building a single page application. In one of the views I want to show an image which must take as much available space as possible:

For example, let's say that the image is 100px x 100px, and that we have a container of 500px x 300px. The image would then be stretched to 300px x 300px, and be horizontally centered so that 100px are left as padding on both sides.

Is this possible?

Here is my non-finished code of what I am trying to accomplish.

.container1 {
  width: 500px;
  height: 300px;
  border: 2px;
  border-color: red;
  border-style: solid;
}
.container2 {
  width: 300px;
  height: 500px;
  border: 2px;
  border-color: blue;
  border-style: solid
}
.fill-vertical {
  border: 2px;
  border-style: solid;
  border-color: green;
  display: block;
  max-width: 100%;
}
.fill-horizontal {
  width: 100%;
  border: 2px;
  border-style: solid;
  border-color: green;
}
 <h1>Container 1, 500px x 300px, not filled</h1>
<div class="container1">
  <img src="https://dummyimage.com/100x100/000/fff">
</div>
<h1>Container 1, filled vertically (should be horizontally centered)</h1>

<div class="container1">
  <img class="fill-vertical" src="https://dummyimage.com/100x100/000/fff">
</div>

<h1>Container 300px x 500px, not filled</h1>

<div class="container2">
  <img class="fillIt" src="https://dummyimage.com/100x100/000/fff">
</div>

<h1>Container 300px x 500px, filled horizontally, should be vertically centered</h1>

<div class="container2">
  <img class="fill-horizontal" src="https://dummyimage.com/100x100/000/fff">
</div>

In that code I am forced to use a different class for the image depending on whether I want to stretch vertically or horizontally, but actually I want CSS to do this automatically: just one stretch class must be defined.

In short what I want CSS to do is: stretch width and/or height to fit available space, keeping aspect ratio

Upvotes: 15

Views: 37585

Answers (3)

Hidden Hobbes
Hidden Hobbes

Reputation: 14173

#This can be achieved in CSS with a few changes#

The required changes are:

  • Create a new .centerImage css rule. overflow: hidden; ensures that the image does not spill out of the container. position: relative; is required as the child img will need to be positioned absolutely relative to the container.
  • Create a new .centerImage img css rule. max-height: 100%; and max-width: 100% ensures the aspect ratio is kept intact. Setting bottom, left, right and top to 0 and margin: auto; centers the image.
  • Add the centerImage class to the containing divs.
  • Change .fill-vertical to height: 100%; which will make the img fill the vertical space.
  • Change .fill-horizontal to width: 100%; which will make the img fill the horizontal space.

.container1 {
    border: 2px;
    border-color: red;
    border-style: solid;
    height: 300px;
    width: 500px;
}
.container2 {
    border: 2px;
    border-color: blue;
    border-style: solid;
    height: 500px;
    width: 300px;
}
.fill-vertical {
    height: 100%;
}
.fill-horizontal {
    width: 100%;
}
.centerImage {
    display: block;
    overflow: hidden;
    position: relative;
    text-align: center;
}
.centerImage img {
    bottom: 0;
    left: 0;
    margin: auto;
    max-height: 100%;
    max-width: 100%;
    position: absolute;
    right: 0;
    top: 0;
}
<h1>Container 1, 500px x 300px, not filled</h1>
<div class="container1 centerImage">
    <img src="https://picsum.photos/500/500">
</div>
<h1>Container 1, filled vertically (should be horizontally centered)</h1>
<div class="container1 centerImage">
    <img class="fill-vertical" src="https://picsum.photos/500/500">
</div>
<h1>Container 300px x 500px, not filled</h1>
<div class="container2 centerImage">
    <img src="https://picsum.photos/500/500">
</div>
<h1>Container 300px x 500px, filled horizontally, should be vertically centered</h1>
<div class="container2 centerImage">
    <img class="fill-horizontal" src="https://picsum.photos/500/500">
</div>

http://jsbin.com/bupuwohica/2/

#Further to the above changes, it is possible to achieve this with the CSS property object-fit#

To do this you need to:

  • Add object-fit: contain; to the image
  • Set height and width to 100%

The only caveat to this is browser support as while Firefox, Chrome, Safari and Opera have supported this for some time IE and Edge do not and will require either a polyfill or fallback.

.container {
  border: 2px solid red;
  height: 200px;
  overflow: hidden;
  resize: both;
  width: 300px;
}
img {
  object-fit: contain;
  height: 100%;
  width: 100%;
}
<p>The below div is resizable, drag the bottom right corner to see how the image scales</p>
<div class="container">
  <img alt="" src="https://picsum.photos/500/500" />
</div>

https://jsfiddle.net/efyey801/

Upvotes: 21

recursive
recursive

Reputation: 86064

Here's one way to do it, relying on background-size. This does use img tags, as required, but the visible graphic is loaded as background to take advantage of available css rules.

.container {
  background-color: #edc;
  position: relative;
  margin: 2em;
}

.container img {
  display: block;
  width: 100%;
  height: 100%;

  background-image: url(http://www.clipartbest.com/cliparts/yck/eXb/yckeXboMi.png);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

#c1 {
  width: 400px;
  height: 100px;
}


#c2 {
  width: 400px;
  height: 600px;
}
<div id="c1" class="container">
  <img src="">
</div>

<div id="c2" class="container">
  <img src="">
</div>

Here's some more information on background-size: https://developer.mozilla.org/en-US/docs/Web/CSS/background-size

Upvotes: 2

user1789573
user1789573

Reputation: 535

Yes it's entirely possible. You just need to make sure you have "Bounds" or limits on your possible max size for X or horizontal and Y or vertical limits. Once you know the max dimensions then you can make those constants to compare to. The easiest method i know of is to compare X and Y as Vectors so you can see their change. To get it centered is also easy at this point:

(((horizontalScreenLimit - widthOfImage)/2), ((verticalScreenLimit - heightOfImage)/2)')

Upvotes: 0

Related Questions