1

I'm wondering why wrapping img flex items in divs will cause them to scale correctly but img items alone do not.

If you check out this JSFiddle, you'll see that wrapping an image in a div does work as suggested by other posts on StackOverflow, but it doesn't seem to work otherwise. And align-self doesn't change anything as suggested here. I tried to align-items so that it would override the default stretch but that doesn't work. I also tried clearing the min-height and min-width values since those are by default set to auto. This answer justifies using the div wrapper except it doesn't explain why it works for div flexbox items and not for img items directly.

Here's some HTML:

 .stack {
      display:flex;
      max-width:600px;
      align-items:center;  /* this does not cause image tags to resize */
    }
    .stack img {
       min-height:0;
       min-width:0;
       height:auto;
       align-self:center;
    }
    .test img {
      width:100%;
    }
<div class="stack">
  <div class="test">
    <img src="https://placehold.it/200x200/E8117F/FFFFFF"/> 
    <!--Wrapping in a div works-->
  </div>

  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
</div>

Why is seemingly the only solution to wrap the image with a div? I don't understand why the only way to scale the image correctly is through a div wrapper.

Community
  • 1
  • 1
rb612
  • 5,280
  • 3
  • 30
  • 68
  • 3
    the image is no more the flex item, now it's the div. So any flex property won't affect it. It will behave an inline element inside the div – Temani Afif Jan 07 '19 at 09:31
  • @TemaniAfif except the `div` itself surrounds the image directly - it's not stretched to the height. See [here](https://jsfiddle.net/vsex4qu9/). Moreover, if you set the image to be `display:block;` you still get expected results. – rb612 Jan 07 '19 at 09:35
  • this has nothing to do with flexbox, it's because image generate whitespace under it due to it being an inline element (https://stackoverflow.com/questions/5804256/image-inside-div-has-extra-space-below-the-image) – Temani Afif Jan 07 '19 at 09:38
  • @TemaniAfif, ah yes I understand. I meant that I don't see why it would matter if the flex item is a div or image. If it works when image is displayed as block inside a div, why do we need the div? – rb612 Jan 07 '19 at 09:42
  • because a div is not the same as an image. It's trivial that you will see different behavior. Same think if you change the image with `input`,`svg`, `canvas`, etc All are different so you will logically see different behavior. an image inside a div that is a flex item is totally different from an image inside a flex container and is a flex item – Temani Afif Jan 07 '19 at 09:47
  • @TemaniAfif that's true, however I thought there might be some general rule about flex items and their size/aspect ratio. I would think that at least using `align-items` and `min-width` would allow us to not have to use a `div` wrapper, no? – rb612 Jan 07 '19 at 10:09
  • I can't tell what your fiddle is trying to prove... the properties you are applying to the flex items and to the images are not consistent. I think you will find that
    elements and elements behave exactly the same as direct children of a `display: flex` element.
    – McHat Jan 07 '19 at 21:00
  • @McHat I’m trying to prove that the only way (besides doing an object-fit) to get the image to maintain its aspect ratio as a flexbox item is through wrapping it in a div. Moreover, oddly enough the div itself is not stretched to the image height, which can be demonstrated by adding a border around the div enclosing the first image. So I’m trying to show that from what I see, that for some reason, I can only get the image to not stretch if I use a wrapping div. – rb612 Jan 07 '19 at 21:49
  • In your example you are not applying the same properties to the div and the images. Of course they will not behave the same way. Put the properties you are applying to the flex-item images onto the flex-item div and it will stretch just as they do. – McHat Jan 07 '19 at 22:14
  • Also, you have not specified what your end goal is for this exercise, which makes it difficult for anyone to post a solution. – McHat Jan 07 '19 at 22:16
  • @McHat sorry about that, you're right that I should've been more clear on my end goal. My end goal is to have [this](https://jsfiddle.net/zbac1dxe/3/) but without having each of them wrapped in a `div`. And I'm just trying to explain that it doesn't seem possible without having that wrapping `div`. – rb612 Jan 08 '19 at 05:54

3 Answers3

2

with CSS flexbox, you need to address the child element directly from a wrapping parent.

In your example, in order to prevent a repeating <div><img><div> structure, you just remove <div class="test"></div>.

in case you need to apply a class (like in your example) to the image you can.

.stack {
  display: flex;
  max-width: 600px;
  align-items: center;
  border:1px solid gold;
}

.stack img {
  min-height: 0;
  min-width: 0;
  height: auto;
  width:200px;
  align-self: center;
}

.test img {
  width: 100%;
}

.test:nth-of-type(1) {
  border: 2px solid #000;
}
<body>
  <div class="stack">
    <img class="test" src="http://picsum.photos/200/200" />
    <img class="test" src="http://picsum.photos/200/200" />
    <img class="test" src="http://picsum.photos/200/200" />
    <img class="test" src="http://picsum.photos/200/200" />
    <img class="test" src="http://picsum.photos/200/200" />
    <img class="test" src="http://picsum.photos/200/200" />
  </div>
</body>

Resize your browser to see it work...

Vickel
  • 7,879
  • 6
  • 35
  • 56
  • Thank you for your response! However I want them to all scale down to be the correct aspect ratio. Right now they are stretched vertically. – rb612 Jan 08 '19 at 05:52
  • @rb612 I don't understand, the original sized 200px images are scaling correctly down to 100px x 100px to fit into the 600px container div? I've added a border to the container div at the snippet to illustrate... – Vickel Jan 08 '19 at 13:07
  • Hi @Vickel, I'm getting on Chrome that it looks like [this](https://imgur.com/a/qPtzaSh). It's being stretched vertically. Are you seeing something different? – rb612 Jan 09 '19 at 02:27
  • I've update the snippet and added `width:200px;` to the img styling, then it works also in chrome – Vickel Jan 09 '19 at 14:16
1

Does this do what you need?

Markup:

<body>
  <div class="stack">
      <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
      <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
      <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
      <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
      <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
      <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
    </div>
</body>

CSS:

.stack {
  display:flex;
}
.stack img {
   align-self:center;
   width: 100px;
}

https://jsfiddle.net/zbac1dxe/6/

McHat
  • 830
  • 5
  • 15
  • Thanks @McHat! This is so close. Because of your answer, I realized that it was a lot simpler than I was making it. All I needed to do was add `min-width:0` to it allow it to shrink to the container size, making it more responsive (see [here](https://jsfiddle.net/zbac1dxe/7/)). Just curious, why does adding that `width` rule cause it not to stretch vertically? Being very new to flexbox, I just want to understand why adding certain rules cause it to behave differently. – rb612 Jan 09 '19 at 02:24
  • 1
    The images were not stretching vertically... they were getting squeezed horizontally. `width: auto` is the default for the `width` property. It was causing your images to adjust to the width of the flex container. Your container(600px wide parent) was not as wide as the images(at 200px each, 1200px total.) `width: auto` caused them to squeeze up to fit in there. By setting the `width` property to any value at all, we are overriding the default `auto` setting which prevents it from trying to squish up your images. – McHat Jan 09 '19 at 03:07
  • 1
    CSS is a trip... take solace in this [animation](http://2.bp.blogspot.com/-41v6n3Vaf5s/UeRN_XJ0keI/AAAAAAAAN2Y/YxIHhddGiaw/s1600/css.gif). – McHat Jan 09 '19 at 03:14
1

The images are being stretched because the default value of align-self is 'stretch'. To maintain aspect ratio, set align-self to 'center'. I have updated your code snippet to demonstrate this.

Please keep in mind that you have 5 images at 200px width and your container width is defined as 600px, so displaying the images correctly at 200x200 causes the container to display a horizontal scrollbar.

Please see this StackOverflow question: Why does flexbox stretch my image?

 .stack {
      display:flex;
      max-width:600px;
    }
    .stack img {
        align-self: center;
    }
<div class="stack">
  <div class="test">
    <img src="https://placehold.it/200x200/E8117F/FFFFFF"/> 
    <!--Wrapping in a div works-->
  </div>

  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
  <img src="https://placehold.it/200x200/E8117F/FFFFFF"/>
</div>
  • Hi Kenny, thank you very much for this! Unfortunately, it's not quite what I was looking for since I wanted it to shrink down to container size (see [here](https://jsfiddle.net/zbac1dxe/7/)). – rb612 Jan 09 '19 at 02:25