为什么 flex 项的宽度和高度会影响 flex 项的呈现方式? [英] Why does width and height of a flex item affect how a flex item is rendered?

查看:12
本文介绍了为什么 flex 项的宽度和高度会影响 flex 项的呈现方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有 max-height 样式的 flexbox 中的图像呈现不同的效果取决于它是否具有 heightwidth 属性设置.

带有属性的,设置为图像的真实宽度/高度,渲染时保留其纵横比,但没有属性的则遵循max-height 并显示为压扁.

.flex-parent {显示:弹性;最大高度:10vh;}

<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyeed_tree_frog_edit2.jpg"><img width="320" height="240" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyeed_tree_frog_edit2.jpg/320px-Red_eyeed_tree_frog_edit2.jpg">

这就是 Chrome 58 中的显示方式(与 Firefox 54 中的显示方式类似).

为什么它们的渲染方式不同?控制这种行为的规则是什么?

我的(显然是错误的)理解是height和width属性覆盖了图片加载时发现的固有高度和宽度,如果高度和宽度属性等于图片的尺寸,那么渲染应该没有区别图片加载完毕后.

上下文正在制作一个带有响应式图像的页面,其中每个图像

  • 可以有唯一的原始尺寸
  • 加载时不会导致回流,即在初始渲染时保留正确的空间(因此使用高度和宽度属性)
  • 可以一次在屏幕上显示所有内容(因此我在 CSS 中使用了 vh)
<小时>

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

解决方案

flex 容器的初始设置是 align-items: 拉伸.

这意味着弹性项目将在容器的横轴上展开.

在行方向容器中,就像问题中一样,横轴是垂直的.

这意味着项目(在本例中为图像)将覆盖容器的整个高度.

然而,当一个 flex 项目具有定义的交叉尺寸时,它会覆盖 stretch 默认值.

来自规范:

<块引用>

8.3.跨轴对齐:align-itemsalign-self属性

Flex 项目可以在当前行的横轴上对齐flex 容器,类似于 justify-content 但垂直方向.

拉伸

如果 flex 项的 cross size 属性计算为 auto,并且两个横轴边距都不是 auto,弹性项目是拉伸.

这是关键语言:

<块引用>

如果 flex 项的 cross size 属性计算为 auto

这就是规范定义横向尺寸属性"的方式:

<块引用>

flex item 的宽度或高度,以叉号为准尺寸,是商品的横向尺寸.横向尺寸属性widthheight 在横向尺寸中的任意一个.

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

<小时>

所以您的代码似乎按照规范中的定义进行.

这就是你所拥有的:

.flex-parent {显示:弹性;最大高度:10vh;}

<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyeed_tree_frog_edit2.jpg"><img width="320" height="240" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyeed_tree_frog_edit2.jpg/320px-Red_eyeed_tree_frog_edit2.jpg">

第一张图片在 CSS 或 HTML 中都没有定义宽度(主要尺寸)或高度(横向尺寸).因此,它的交叉大小计算为 auto.

本声明:

<块引用>

如果 flex 项的 cross size 属性计算为 auto

... 为真,align-items:stretch 生效.

图像扩展到容器的高度,即 10 像素.

第二张图片,但是,有明确的尺寸.十字尺寸在 HTML (height="240") 中定义.

现在声明:

<块引用>

如果 flex 项的 cross size 属性计算为 auto

... 为假,并且 align-items:stretch 被覆盖.以 HTML height 属性为准.

关于第二张图片的两个注意事项:

  1. 图像忽略了容器的 max-height 限制,因为 CSS 中的初始设置是 溢出:可见.
  2. HTML widthheight 属性映射到它们各自的 CSS 属性.因此,height="240" 覆盖了 height: auto 默认值.请参阅下面的规范参考.*

<小时>

在 flex 容器中渲染图像时还有两个问题需要考虑.

  1. 弹性项目的默认最小尺寸.此设置可防止弹性项目缩小到其内容的大小以下.阅读这篇文章了解完整详情:

  2. 主要浏览器的行为各不相同.Firefox、Chrome、Safari、Edge 和 IE11 并不总是以相同的方式将图像渲染为弹性项目.阅读这篇文章了解更多详情:

<小时>

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

.flex-parent {显示:弹性;最大高度:50vh;/* 为演示调整 */}.flex-父{最小宽度:0;}图片{宽度:100%;高度:自动;}

<div><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyeed_tree_frog_edit2.jpg">

<div><img width="320" height="240" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyeed_tree_frog_edit2.jpg/320px-Red_eyeed_tree_frog_edit2.jpg">

<小时>

*HTML widthheight 属性映射到它们各自的 CSS 属性.因此,当指定时,它们会覆盖 CSS 默认值.来自 HTML5 规范:

<块引用>

10.4.3嵌入内容的属性和图片

appletembediframe 上的 widthheight 属性,objectvideo 元素,以及具有 typeinput 元素图像按钮状态中的属性,或者表示一个图像或用户期望最终代表图像,分别映射到元素上的尺寸属性 widthheight.

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

当下面的文字说元素上的属性映射到维度属性(或属性),表示如果元素有一个属性集,并使用 解析该属性的值规则用于解析维度values 不会产生错误,那么用户代理应该使用解析维度作为 presentational hint 的值属性,如果维度为像素长度,则值为是一个整数,并以百分比形式给出值,如果维度是一个百分比.

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

解决方案

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:

8.3. Cross-axis Alignment: the align-items and align-self properties

Flex items can be aligned in the cross axis of the current line of the flex container, similar to justify-content but in the perpendicular direction.

stretch

If the cross size property of the flex item computes to auto, and neither of the cross-axis margins are auto, the flex item is stretched.

This is the key language:

If the cross size property of the flex item computes to auto

And this is how the spec defines "cross size property":

The width or height of a flex item, whichever is in the cross dimension, is the item’s cross size. The cross size property is whichever of width or height that is in the cross dimension.

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


So your code appears to be playing out as defined in the spec.

This is what you have:

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

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:

If the cross size property of the flex item computes to auto

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

If the cross size property of the flex item computes to auto

... is false, and align-items: stretch is overridden. The HTML height attribute prevails.

Two notes about the second image:

  1. The image ignores the max-height limit on the container because an initial setting in CSS is overflow: visible.
  2. The HTML width and height attributes map to their respective CSS properties. Hence, height="240" overrides the height: auto default. See below for the spec references.*


There are two other issues to consider when rendering images in a flex container.

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

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

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


*The HTML width and height attributes map to their respective CSS properties. Hence, when specified, they override the CSS defaults. From the HTML5 spec:

10.4.3 Attributes for embedded content and images

The width and height attributes on applet, embed, iframe, object or video elements, and input elements with a type attribute in the Image Button state and that either represents an image or that the user expects will eventually represent an image, map to the dimension properties width and height on the element respectively.

10.2 The CSS user agent style sheet and presentational hints

When the text below says that an attribute on an element maps to the dimension property (or properties), it means that if the element has an attribute set, and parsing that attribute's value using the rules for parsing dimension values doesn't generate an error, then the user agent is expected to use the parsed dimension as the value for a presentational hint for properties, with the value given as a pixel length if the dimension was an integer, and with the value given as a percentage if the dimension was a percentage.

这篇关于为什么 flex 项的宽度和高度会影响 flex 项的呈现方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆