为什么flex项目的宽度和高度会影响flex项目的呈现方式?

43
在flexbox中具有max-height样式的图像似乎会根据其是否设置了heightwidth属性而呈现不同的效果。具有属性设置为图像真实宽度/高度的图像将保持其纵横比,但是没有属性的图像会遵循max-height并显示为压缩状态。

.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>

这是在Chrome 58中的显示效果(在Firefox 54中显示效果类似)。

Different rendering of img in flexbox. Without width and height attributes, and with

为什么它们呈现不同?规定这种行为的规则是什么?
我(显然是错误的)理解是,高度和宽度属性覆盖了加载图像时找到的固有高度和宽度,如果高度和宽度属性等于图像的尺寸,则在图像加载后应该没有渲染差异。
上下文是创建具有响应式图像的页面,其中每个图像
- 可以具有独特的原始尺寸 - 在加载时不会导致重新流动,即在初始呈现时保留正确的空间(因此使用高度和宽度属性) - 可以同时适合屏幕(因此我在CSS中弄乱了`vh`)

这只青蛙的图片来自于https://en.wikipedia.org/wiki/File:Red_eyed_tree_frog_edit2.jpg


你已经将 max-height 分配给了父级 div,现在需要在 flex-parent img:first-of-type 的 img 标签上分配该高度。我使用了 first-of-type 来仅影响第一个 img。第二个图像具有 heightwidth,因此它看起来具有正确的纵横比,但是第一个图像的渲染宽度不符合纵横比。 - LKG
您可以在此处查看示例 https://jsfiddle.net/Lokeshg27/tp53tv82/23/ - LKG
4个回答

46
一个flex容器的初始设置是 align-items: stretch
这意味着flex项目将在容器的交叉轴上扩展。
在问题中,像行方向的容器一样,交叉轴是垂直的。
这意味着项目(在本例中为图像)将覆盖容器的整个高度。
但是,当flex项目具有定义的交叉尺寸时,它会覆盖默认的stretch来自规范: 8.3. 交叉轴对齐: align-itemsalign-self 属性 弹性项可以在当前行的交叉轴中对齐,类似于 justify-content 但是在垂直方向上。 stretch 如果弹性项的交叉尺寸属性计算为 auto,且没有交叉轴边距为 auto,则该弹性项被拉伸。
这是关键语言:
如果弹性项的交叉尺寸属性计算为 auto 规范如何定义“交叉尺寸属性”:

弹性盒子模型中,一个项目的宽度或高度(取决于交叉轴)被称为该项目的交叉尺寸。交叉尺寸属性是指在交叉轴上的widthheight之一。

https://www.w3.org/TR/css-flexbox-1/#cross-size-property


所以你的代码似乎按照规范定义的方式运行。
这是你拥有的内容:

.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>

第一张图片在CSS或HTML中没有定义宽度(主要大小)或高度(交叉大小),因此其交叉大小计算为auto

因此,这个语句:

如果伸缩项的交叉大小属性计算为auto

是正确的,并且align-items: stretch生效。

该图像跨越容器的高度,即10px。

然而,第二张图片具有明确的尺寸。交叉大小在HTML中被定义(height="240")。

现在这个语句:

如果伸缩项的交叉大小属性计算为auto

是错误的,align-items: stretch被覆盖了。HTML的height属性优先。

关于第二张图片有两点需要注意:

  1. 由于CSS的初始设置为overflow: visible,因此图像忽略了容器的max-height限制。
  2. HTML的widthheight属性映射到它们各自的CSS属性。因此,height="240"覆盖了默认的height: auto。有关规范参考,请参见下文。*

在 flex 容器中渲染图像时,还需考虑另外两个问题。

  1. flex 项目的默认最小大小。此设置可防止 flex 项目缩小至其内容的大小以下。阅读此文章以获取完整细节:

  2. 主要浏览器之间的行为差异。Firefox、Chrome、Safari、Edge 和 IE11 并不总是以相同方式将图像呈现为 flex 项目。阅读此文章以获取更多详细信息:


考虑到以上所有因素,这是我建议的解决方案:

.flex-parent {
  display: flex;
  max-height: 50vh; /* adjusted for demo */
}

.flex-parent {
  min-width: 0;
}

img {
  width: 100%;
  height: auto;
}
<div class="flex-parent">
  <div>
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
  </div>
  <div>
    <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>
</div>


HTML中的widthheight属性对应其各自的CSS属性。因此,当指定时,它们会覆盖CSS的默认值。根据HTML5规范:

10.4.3 嵌入内容和图像的属性

appletembediframeobjectvideo 元素上的 widthheight 属性,以及处于 Image Button 状态并且代表图像或用户预期最终将代表图像的 type 属性的 input 元素,分别映射到元素上的尺寸属性 widthheight

10.2 CSS 用户代理样式表和呈现提示

当下文中提到一个元素上的属性映射到尺寸属性(或属性)时,它意味着如果元素有设置属性,并且使用解析尺寸值的规则解析该属性的值不会生成错误,则用户代理应将解析的尺寸作为呈现提示的值用于属性,如果尺寸是整数,则给定值为像素长度,如果尺寸是百分比,则给定值为百分比。


3
尝试阅读w3c flexbox规范时,我发现了这里。它说:

对于每个尺寸,如果弹性容器内容框的该尺寸为明确大小,则使用该尺寸;如果该尺寸被限制在最小或最大内容约束下,则该尺寸的可用空间为该约束。

否则,从该尺寸中减去弹性容器的边距、边框和填充,并使用该值,这可能会导致无限值。

希望这可以帮助你。


2

在这里,您写了max-height:10vh,除了最新的iOS 6之外,任何浏览器都不支持vh。这适用于所有与视口相关的长度单位�� 请使用其他值代替Vh,这样就可以正常工作。 请阅读此博客https://css-tricks.com/the-lengths-of-css/

.flex-parent {
  display: flex;
  max-height:  max-content;
}
<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>


4
你指出的那篇文章是2013年的,按互联网时间计算,已经过去了约十年。https://caniuse.com/#search=vw 这个链接展示了与视口相关的测量单位有多大的改进。在某些情况下,我个人非常喜欢使用vh/vw。 - Andrew Adam

0
问题在于您设置的最大高度。CSS属性最大高度默认情况下不会被继承。您的CSS声明创建了一个占视口高度10%的div。没有设置尺寸的图像会根据其父级尺寸缩小。您设置了隐式尺寸的图像将始终保持这些尺寸。取决于div的大小,它可能会溢出。如果在第一张图像上放置max-height属性,则应该保持纵横比调整大小。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接