更改高度时保持图像纵横比

Posted

技术标签:

【中文标题】更改高度时保持图像纵横比【英文标题】:Maintain image aspect ratio when changing height 【发布时间】:2015-08-27 13:57:56 【问题描述】:

使用 CSS flex box 模型,我如何强制图像保持其纵横比?

JS 小提琴:http://jsfiddle.net/xLc2Le0k/2/

请注意,图像会拉伸或收缩以填充容器的宽度。没关系,但我们也可以让它拉伸或缩小 高度 以保持图像比例吗?

HTML

<div class="slider">
    <img src="http://www.placebacon.net/400/300" >
    <img src="http://www.placebacon.net/400/300" >
    <img src="http://www.placebacon.net/400/300" >
    <img src="http://www.placebacon.net/400/300" >
</div>

CSS

.slider 
    display: flex;

.slider img 
    margin: 0 5px;

【问题讨论】:

据我所知,最好的解决方案是使用 &lt;div&gt; 和 CSS background-image: url(...);background-size:contain; background-repeat:no-repeat 这里有一些有趣的线索,但是当图像的比例不同时怎么办?添加和“额外”的 div 是我们需要担心的最后一件事。为什么不使用这样的测试用例:jsfiddle.net/sheriffderek/999Lg9qv 【参考方案1】:

为了防止图像在 flex 父级中的任一轴上拉伸,我找到了几个解决方案。

您可以尝试在图像上使用 object-fit,例如

object-fit: contain;

http://jsfiddle.net/ykw3sfjd/

或者您可以添加在某些情况下可能效果更好的 flex-specfic 规则。

align-self: center;
flex: 0 0 auto;

【讨论】:

如果不是 missing support in IE and Edge 甚至到 Edge 14,object-fit 可能是一个很好的解决方案 看看这个object-fit fallback for Edge an IE。 我自己一直在使用那个后备,效果很好。 @daniels Edge 现在正在开发对象拟合:developer.microsoft.com/en-us/microsoft-edge/platform/status/… object-fit: contain; 为我解决了问题,当我只在 chrome 中遇到问题时,ff 很好。【参考方案2】:

对于 img 标签,如果您定义一侧,则另一侧会调整大小以保持纵横比,并且默认情况下图像会展开为其原始大小。

使用这个事实,如果你将每个 img 标签包装到 div 标签中并将其宽度设置为父 div 的 100%,那么高度将根据你想要的纵横比。

http://jsfiddle.net/0o5tpbxg/

* 
    margin: 0;
    padding: 0;

.slider 
    display: flex;

.slider .slide img 
    width: 100%;

【讨论】:

我知道有两个答案建议使用 div,但我将这个答案标记为正确,因为它解释了为什么图像高度与我预期的不同。事实上,这是正常且正确的行为,不太可能被“修复”,因为它不是错误。 但是这个答案并没有谈论任何关于 flexbox 的内容,因为图像在 flexbox 容器中的行为确实不同。设置一侧不会按比例调整另一侧的大小。将它们包装在非 flexbox 容器中会有所帮助,但这会增加不必要的标记,失去语义。 看起来你不需要包装 div 来完成这项工作:jsfiddle.net/xLc2Le0k/120 但是,这个呢? jsfiddle.net/xLc2Le0k/15 我认为这个解决方案是侥幸,因为图像都是相同的比例。旁注:将图像放置在 div 中进行定位不会丢失任何“语义”/尤其是在处理响应式图像时。 真的是最干净的解决方案,它适用于图片!【参考方案3】:

无需添加包含 div。

css“align-items”属性的默认值是“stretch”,这会导致您的图像被拉伸到其原始高度。将 css“align-items”属性设置为“flex-start”可以解决您的问题。

.slider 
    display: flex;
    align-items: flex-start;  /* ADD THIS! */

【讨论】:

啊...感谢您以受支持的方式实际做事。我一直在阅读答案,直到那个答案,无法相信我们所拥有的只是肮脏的黑客...... 这应该是答案【参考方案4】:

大多数图像具有固有尺寸,即自然尺寸,例如jpeg 图像。如果指定的大小定义了宽度和高度之一,则使用固有比率确定缺失值... - 请参阅MDN。

但据我所知,如果将图像设置为具有当前Flexible Box Layout Module Level 1 的直接弹性项目,则这不会按预期工作。

查看这些讨论和可能相关的错误报告:

Flexbugs #14 - Chrome/Flexbox Intrinsic Sizing 未正确实现。 Firefox Bug 972595 - Flex 容器应该使用“flex-basis”而不是“width”来计算弹性项目的内在宽度 Chromium Issue 249112 - 在 Flexbox 中,允许固有纵横比通知主尺寸计算。

作为一种解决方法,您可以用&lt;div&gt;&lt;span&gt; 等包装每个&lt;img&gt;

jsFiddle

.slider 
  display: flex;


.slider>div 
  min-width: 0; /* why? see below. */


.slider>div>img 
  max-width: 100%;
  height: auto;
<div class="slider">
  <div><img src="https://picsum.photos/400/300?image=0" /></div>
  <div><img src="https://picsum.photos/400/300?image=1" /></div>
  <div><img src="https://picsum.photos/400/300?image=2" /></div>
  <div><img src="https://picsum.photos/400/300?image=3" /></div>
</div>

4.5 Implied Minimum Size of Flex Items

为flex items 提供更合理的默认最小大小, 本规范引入了一个新的auto 值作为初始值 中定义的 min-width 和 min-height 属性的值 CSS 2.1。


或者,您可以使用 CSS table 布局代替,您将获得与 flexbox 相似的结果,它适用于更多浏览器,甚至适用于 IE8。

jsFiddle

.slider 
  display: table;
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;


.slider>div 
  display: table-cell;
  vertical-align: top;


.slider>div>img 
  max-width: 100%;
  height: auto;
<div class="slider">
  <div><img src="https://picsum.photos/400/300?image=0" /></div>
  <div><img src="https://picsum.photos/400/300?image=1" /></div>
  <div><img src="https://picsum.photos/400/300?image=2" /></div>
  <div><img src="https://picsum.photos/400/300?image=3" /></div>
</div>

【讨论】:

在支持min-width: auto的新浏览器上,第一个sn-p需要.slider &gt; divmin-width:0 flexbox 规范引入了一个新的auto 值作为min-widthmin-height 的默认值(以前是0)。 Chrome 还没有实现它,所以你的第一个 sn-p 工作。但是新的浏览器需要它来允许弹性项目缩小到小于图像的默认宽度。 +1 这应该是被接受的答案,因为它讨论的是 flexbox 模型中的图像,在这种情况下这是 根本问题... 如果您的布局在不同的断点处不发生变化,那么表格非常棒,但现在不太可能。 图片比例不一致怎么办? jsfiddle.net/sheriffderek/5u7y21we【参考方案5】:

我最近一直在玩 flexbox,我通过实验和以下推理来解决这个问题。但是,实际上我不确定这是否正是发生的情况。

如果实际宽度受 flex 系统影响。因此,在元素的宽度达到父级的最大宽度后,它们在 css 中设置的额外宽度将被忽略。然后将宽度设置为 100% 是安全的。

由于 img 标签的高度来自图像本身,因此将高度设置为 0% 可以做一些事情。 (这是我不清楚是什么的地方......但对我来说应该修复它是有道理的)

DEMO

(记得先在这里看过!)

.slider 
    display: flex;

.slider img 
    height: 0%;
    width: 100%;
    margin: 0 5px;

目前仅适用于 chrome

【讨论】:

有趣,但它似乎是一个错误。根据the spec,“百分比是相对于生成框的包含块的高度计算的。如果包含块的高度没有明确指定(即取决于内容高度),则该元素不是绝对定位,值计算为auto"。这就是在 Firefox 上发生的事情。 jsfiddle.net/xLc2Le0k/8解释ff和chrome的区别。为此 width 似乎在 ff 中做了什么 height 在 chrome 中做了什么。 这很有趣,但恐怕只有 X 浏览器的解决方案并不是真正的解决方案。你评论的小提琴,在这里:jsfiddle.net/xLc2Le0k/8 绝对是迷人,不过,在 FF。这似乎表明 FF 正在使图像高度与图像高度“成比例”,如果它真的是 100%。换句话说,img 并不“知道”容器的显示:这解释了为什么在 FF 中,如果将 img 的宽度设置为 100%,则图像比将宽度设置为 auto 时更高。 这有点接近...但仅适用于 Chrome:jsfiddle.net/sheriffderek/xLc2Le0k/270【参考方案6】:

这种行为是意料之中的。默认情况下,flex 容器会拉伸它的所有子容器。图片也不例外。 (即,父母将拥有align-items: stretch 属性)

为了保持纵横比,我们有两种解决方案:

    将默认的align-items: stretch 属性替换为align-items: flex-startalign-self: center 等, http://jsfiddle.net/e394Lqnt/3/

    将 align 属性专门设置为子项本身:例如,align-self: centeralign-self: flex-start 等。 http://jsfiddle.net/e394Lqnt/2/

【讨论】:

【参考方案7】:

声明 display: flex; 被赋予元素的位置。align-items: center;

【讨论】:

【参考方案8】:

其实我发现图片标签的容器需要有一个高度才能保持图片的比例。 例如>

.containerdisplay:flex; height:100%; imgwidth:100%;height:auto;

然后在您的 html 中,您的容器将包装标签图像

<div class="container"><img src="image.jpg"  /></div>

这项工作适用于 IE 和其他浏览器

【讨论】:

【参考方案9】:

我也遇到了同样的问题。使用 flex align 使元素居中。您需要使用align-items: center 而不是align-content: center。这将保持纵横比,而 align-content 不会保持纵横比。

【讨论】:

以上是关于更改高度时保持图像纵横比的主要内容,如果未能解决你的问题,请参考以下文章

如何在更改屏幕宽度的同时保持响应式背景图像高度?

CSS:在保持纵横比的同时保持 100% 的宽度或高度?

仅当宽度和高度都更改时才更改图像大小

PHP裁剪图像以固定宽度和高度而不丢失尺寸比

将一排图像保持在相同的高度

图像视图在 3.5 和 4 英寸屏幕上更改高度