5

I want to make images centered horizontally and vertically inside their containers. And if their width or height is greater than their containers' width or height, then make them automatically shrink while keeping their proportions.

The following CSS code is what I use on the container to try to achieve the goal:

display: -ms-flexbox;
display: -webkit-flex;
display:         flex;
    -ms-flex-direction: column;
-webkit-flex-direction: column;
        flex-direction: column;
          -ms-flex-pack: center;
-webkit-justify-content: center;
        justify-content: center;

And here are three examples on jsFiddle:

  • The first example is an image whose width is greater than its height. It works fine.
  • The second example is an image whose height is greater than its width. But in this example, its width stretches to container's width, and that isn't what I want.
  • The third example has the same problem as the second example.

Besides, I know the goal can also be achieved by using CSS position and transform. But such a method often creates 1 pixel gap between the resized image and the container's border. That is, the resized image fails to touch the container's border, at where it should do. Therefore I have to resort to CSS flexbox.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Ian Y.
  • 2,293
  • 6
  • 39
  • 55
  • 1
    [Is this example what you want?](http://jsfiddle.net/ycppkdh7/) No flexbox needed... It's a good technique. – misterManSam Jun 02 '15 at 04:40
  • @misterManSam, wow, that's amazing! Yes, it achieves exactly the same result I want. Thank you very much! You may re-post it as an answer so that I could choose it as the best answer. Besides, the `display: block;` on the img can actually be omitted as setting `position: absolute;` on it already makes it block-level. – Ian Y. Jun 02 '15 at 06:01
  • This question has already been asked a few times, so should be closed as a duplicate - [Here is one example](http://stackoverflow.com/questions/10296015/how-to-center-image-in-a-div-horizontally-and-vertically) :) – misterManSam Jun 02 '15 at 06:14
  • Okay. I guess what the title asks does not currently have an answer. – Ian Y. Jun 02 '15 at 06:30

1 Answers1

7

The problem is that the initial value of align-items is stretch and the initial value of align-self is auto, so the images are stretched.

So you need one of the following:

.flex-container {
    align-items: center;
}
.flex-item {
    align-self: center;
}

* {
  margin: 0;
  padding: 0;
}
div {
  display: flex; /* Magic begins */
  flex-direction: column;
  justify-content: center; /* Center in main axis */
  align-items: center; /* Center in cross axis */
  margin: 20px auto;
  width: 300px;
  height: 300px;
  border: 2px solid #000;
}
img {
  max-width: 100%;
  max-height: 100%;
}
<div>
  <img src="http://lorempixel.com/400/200/" alt="" />
</div>
<div>
  <img src="http://lorempixel.com/200/400/" alt="" />
</div>
<div>
  <img src="http://lorempixel.com/50/50/" alt="" />
</div>

But note that the middle image is still a bit stretched. That's because if the images are taller than the container, they will shrink vertically but not horizontally (it would be the opposite with a row layout).

To prevent that, use object-fit (not supported by IE and Edge):

img {
  object-fit: contain;
}

* {
  margin: 0;
  padding: 0;
}
div {
  display: flex; /* Magic begins */
  flex-direction: column;
  justify-content: center; /* Center in main axis */
  align-items: center; /* Center in cross axis */
  margin: 20px auto;
  width: 300px;
  height: 300px;
  border: 2px solid #000;
}
img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
<div>
  <img src="http://lorempixel.com/400/200/" alt="" />
</div>
<div>
  <img src="http://lorempixel.com/200/400/" alt="" />
</div>
<div>
  <img src="http://lorempixel.com/50/50/" alt="" />
</div>
Talisa
  • 3
  • 2
Oriol
  • 274,082
  • 63
  • 437
  • 513