Re: [css-flexbox] Intrinsic sizes and flexibility

On 01/12/2015 11:09 AM, Tab Atkins Jr. wrote:
> On Sun, Jan 11, 2015 at 7:50 AM, Lev Solntsev <greli@mail.ru> wrote:
>> Hello!
>>
>> There is interesting case questioned at http://toster.ru/q/170371 (in
>> russian).
>>
>> In short, it was asked to make an image with a caption beneath centered
>> using Flexbox. When the page is too narrow or short the image should
>> be smaller. I've made an example here:
>> http://codepen.io/GreLI/pen/RNKoxo
>>
>> One can see that the image there doesn't keep its proportions. It become
>> smaller proportionally when page is too narrow with ‘max-width: 100%’,
>> but it doesn't in case of height.
>>
>> When ‘max-height: 100%’ is set, image height resolves relative to the
>> whole ‘display: flex’ element (i.e. <figure>) height, including the
>> caption height. The worst part is that one can't limit the height
>> using wrapping element since it wouldn't have definite height.
>> (And in case of setting height it would resolve against the value that
>> was set, not the flexible one.)
>>
>> I guess it happens because there is no place in spec that says that
>> replaced elements should keep it intrinsic proportions after resolving
>> flexible lengths.
>>
>> I believe it's a considerable defect which breaks author expectations.
>
> Flexbox actually honors intrinsic proportions in two different spots
> in its algorithm.  The issue is that there are multiple ways to honor
> intrinsic proportions, when combined with explicitly-specified
> proportions, and you can't handle all of them with any single set of
> rules (because the behaviors are contradictory sometimes).
>
> In this case, your use of max-height accidentally invokes the stronger
> "I really want it to stay this ratio, dammit" algorithm in CSS 2.1,
> defined at <http://dev.w3.org/csswg/css2/visudet.html#min-max-widths>
> (in the table near the bottom of the section).  But, as you note, a
> percentage max-height is calculated relative to the container, so it
> only kicks in when the intrinsic size of the element is less than the
> entire flexbox height, which means the image will squish somewhat
> before the aspect-ratio-maintaining algo kicks in.

This can be fixed by applying max-height: 100% to the flex container
instead of to the flex item.

> Unfortunately, there's no way to opt into the stronger
> aspect-ratio-maintaining behavior without min/max width/height, and
> there's no way to get the behavior you want with min/max width/height.
> This will be handled in the future with an aspect-ratio property that
> can opt elements with intrinsic dimensions into the weaker or stronger
> algorithm explicitly, avoiding the need for these kinds of hacks.
> Unfortunately, that's not going to help you right now.

I think your conclusion is incorrect here. Unless I've made a mistake,
the following code should do what is expected:

<figure>
   <img>
   <caption/>
</figure>

figure {
   display: flex;
   flex-flow: column;
   max-height: 100vh;
}

img {
   align-self: center;
   max-width: 100%;
}

Assuming it's a normal block, the flex container will size itself as
fill-available, taking up all the available space width-wise.
This is definite, and allows max-width to take effect as necessary.

Then the hypothetical main size of the image is calculated.
http://dev.w3.org/csswg/css-flexbox/#algo-main-item
If the max-width is taking effect, we fall into case B,
   and the image is shrink accordingly.
Otherwise, we fall into case E,
   and the image is at its usual size.

Then the caption's hypothetical main size is also calculated.
It fills the flex container widthwise, and is assigned a height
based on the amount of content. This is its min-content height.

The flex container's height is now calculated. Since it is specified
to max out at 100vh (or 100%, whichever is specified), it will be
at minimum the content height and at most that amount.
   http://dev.w3.org/csswg/css-flexbox/#algo-main-container

Next, we flex. Since the initial value of 'flex' is '0 1 auto',
the image's main size is, if necessary to satisfy the flex
container's max-height, shrunk. The caption doesn't shrink
because of the automatic min-content minimum. (!)
   http://dev.w3.org/csswg/css-flexbox/#algo-flex

Then we compute the cross size based on the main size. If the
image has shrunk height-wise, this will cause the width to
shrink accordingly, since that is the usual rules for layout.
   http://dev.w3.org/csswg/css-flexbox/#algo-cross-item

Since we are centering instead of stretching, the image is not
widened again. It therefore remains at its aspect ratio.

Did I miss something?

Note: Firefox currently forgets to handle the aspect ratio in the
final cross size determination step.

~fantasai

Received on Tuesday, 13 January 2015 08:37:31 UTC