An image in a flexbox that has a max-height
style appears to render differently depending on whether it has its height
and width
attributes set.
The one with the attributes, set to the true width/height of the image, renders with its aspect ratio preserved, but the ones without the attributes respects the max-height
and appear squashed.
.flex-parent {
display: flex;
max-height: 10vh;
}
<div class="flex-parent">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
<img width="320" height="240" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
</div>
This is how is appears in Chrome 58 (and it appears similarly in Firefox 54).
Why do they render differently? What are the rules that govern this behaviour?
My (obviously incorrect) understanding is that height and width attributes overwrite the intrinsic height and width that is found when the image loads, and if the height and width attributes equal the dimensions of the image, there should be no difference in rendering once the image has loaded.
The context is making a page with responsive images, where each image
- can have unique original dimensions
- does not cause a reflow when it's loaded, i.e. the correct space is reserved on initial render (hence using height and width attributes)
- can fit all on screen at once (hence me messing with
vh
in the CSS)
The frog image is from https://en.wikipedia.org/wiki/File:Red_eyed_tree_frog_edit2.jpg
Tried reading the w3c flexbox specs and stumbled onto this. It says that
Hope this helps.
The problem is where you set max-height. The css property max-height is not inherited by default. Your css declaration creates a div that is 10% of the viewport height. The image with no dimensions set shrunk based on it's parent dimensions. The image you set the implicit dimensions on is always going to be those dimensions. Depending on the size of the div, it may overflow. If you put the max-height property on the first image, it should resize keeping the aspect ratio the same.
Here you have written max-height:10vh, vh does not support in any browsers except the very latest iOS 6. This goes for all the viewport related length units. use other values instead of Vh this will work fine. Please Read this blog https://css-tricks.com/the-lengths-of-css/.
An initial setting of a flex container is
align-items: stretch
.That means that flex items will expand across the cross axis of the container.
In a row-direction container, like in the question, the cross axis is vertical.
That means the items (images, in this case) will cover the full height of the container.
However, when a flex item has a defined cross size, that overrides the
stretch
default.From the spec:
This is the key language:
And this is how the spec defines "cross size property":
So your code appears to be playing out as defined in the spec.
This is what you have:
The first image has no defined width (main size) or height (cross size), either in the CSS or the HTML. Its cross size, therefore, computes to
auto
.This statement:
... is true, and
align-items: stretch
goes into effect.The image expands across the height of the container, which is 10px.
The second image, however, has explicit sizing. The cross size is defined in the HTML (
height="240"
).Now this statement:
... is false, and
align-items: stretch
is overridden. The HTMLheight
attribute prevails.Two notes about the second image:
max-height
limit on the container because an initial setting in CSS isoverflow: visible
.width
andheight
attributes map to their respective CSS properties. Hence,height="240"
overrides theheight: auto
default. See below for the spec references.*There are two other issues to consider when rendering images in a flex container.
The default minimum size of flex items. This setting prevents flex items from shrinking below the size of their content. Read this post for full details:
Varying behavior among major browsers. Firefox, Chrome, Safari, Edge and IE11 don't always render images as flex items in the same way. Read this post for more details:
Considering all factors above, here's my suggested solution:
*The HTML
width
andheight
attributes map to their respective CSS properties. Hence, when specified, they override the CSS defaults. From the HTML5 spec: