当改变高度时保持图像纵横比

126

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

JS Fiddle: http://jsfiddle.net/xLc2Le0k/2/

请注意,图像会拉伸或缩小以填充容器的宽度。 这很好,但我们是否也可以使其拉伸或缩小高度以保持图像比例?

HTML

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

CSS

.slider {
    display: flex;
}
.slider img {
    margin: 0 5px;
}

1
据我所知,最好的解决方案是使用带有CSS属性background-image: url(...); background-size: contain; background-repeat: no-repeat<div> - Blazemonger
1
这里有一些有趣的线索,但如果图像的比例不相同怎么办?添加一个“额外”的 div 是我们最不需要担心的事情。为什么不使用像 https://jsfiddle.net/sheriffderek/999Lg9qv/ 这样的测试用例呢? - sheriffderek
9个回答

88
为了保持 flex 父元素内的图像不会在任何轴向上拉伸,我发现了几种解决方案。
你可以尝试在图像上使用 object-fit 属性,例如:
```html ```
请注意,这不适用于 IE11 及更早版本。
object-fit: contain;

http://jsfiddle.net/ykw3sfjd/

或者您可以添加一些特定于flex的规则,在某些情况下可能效果更好。

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

4
如果IE和Edge直到Edge 14版本还不支持object-fit,那么它可能不是一个好的解决方案。 - daniels
我自己一直在使用那个备用方案,效果非常好。 - Matty Balaam
1
@daniels Edge现在正在开发object-fit功能:https://developer.microsoft.com/zh-cn/microsoft-edge/platform/status/objectfitandobjectposition/ - AMDG
1
当我只在Chrome中遇到问题时,object-fit: contain;对我很有帮助,而Firefox则没有问题。 - Benjamin Peter
object-fit: containalign-self: center; flex: 0 0 auto; 比使用 width: 100%; 来设置图片宽度更好,因为图片的宽高仍然保持比例。 - Moff452

70

对于img标签,如果你定义了一边的大小,则另一边会根据宽高比例进行调整,而且默认情况下图像会扩展到其原始大小。

基于这个事实,如果你将每个img标签包装在div标签中,并将其宽度设置为父div的100%,则高度将按照所需的宽高比进行调整。

http://jsfiddle.net/0o5tpbxg/

* {
    margin: 0;
    padding: 0;
}
.slider {
    display: flex;
}
.slider .slide img {
    width: 100%;
}

2
我知道有两个答案建议使用div,但我标记这个答案是正确的,因为它解释了为什么图像高度与我预期的不同。实际上,这是正常和正确的行为,不太可能被“修复”,因为这不是一个错误。 - coderMe
20
但是这个回答没有涉及到flexbox,因为图像在flexbox容器中的表现不同。设置一个边不会按比例调整另一个边。将它们包裹在非flexbox容器中可以帮助解决问题,但这样会增加不必要的标记并失去语义性。 - Robert Koritnik
3
看起来你不需要添加包装 div 就能让这个工作:http://jsfiddle.net/xLc2Le0k/120/ - Rick Strahl
4
但是,这个呢?http://jsfiddle.net/xLc2Le0k/15/ 我认为这个解决方案只是因为所有图片的比例都相同而起作用,所以可能只是一时的偶然。顺便说一下:将图像放在div中定位时不会失去任何“语义”,尤其是当处理响应式图片时。 - sheriffderek
@RickStrahl,你的解决方案实际上比答案中的更好。 - Mikhail Batcer
1
真的是最干净的解决方案,而且它还可以使用图片! - shaneonabike

68

不需要添加包含div。

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

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

6
啊...感谢您实际按照支持的方式进行操作。在读到那个答案之前,我一直在阅读其他答案,并且无法相信我们所拥有的都是些不正规的技巧。 - Félix Adriyel Gagnon-Grenier

36
大多数具有固有尺寸(即自然大小)的图像(例如jpeg图像)都有固有尺寸。如果指定的尺寸定义了宽度和高度中的一个,则缺失的值将使用固有比率确定... - 请参见MDN
但是,如果正在使用当前的Flexible Box Layout Module Level 1将图像设置为直接弹性盒子项,则其效果与预期不同,据我所知。
以下讨论和错误报告可能与此相关:
- Flexbugs #14 - Chrome/Flexbox Intrinsic Sizing not implemented correctly. - Firefox Bug 972595 - Flex containers should use "flex-basis" instead of "width" for computing intrinsic widths of flex items - Chromium Issue 249112 - In Flexbox, allow intrinsic aspect ratios to inform the main-size calculation.
作为解决方法,您可以将每个<img>包装在一个<div><span>中。 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 值作为 CSS 2.1 中定义的 min-widthmin-height 属性的初始值。


或者,您可以使用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的新浏览器上.slider>div {min-width: 0} - Oriol
3
flexbox规范引入了一个新的auto值作为 min-widthmin-height 的默认值(以前是0)。Chrome还没有实现它,因此您的第一个片段有效。但是新的浏览器需要它,以便允许弹性项目缩小到比图像的默认宽度更小的尺寸。 - Oriol
3
这个回答应该被采纳,因为它讨论了flexbox模型中的图像问题,这正是这种情况的根本问题 - Robert Koritnik
表格在布局不会在各种断点处发生变化时非常好用,但这种情况在当今很少见。 - sheriffderek
1
当图像不是相同的比例时怎么办?https://jsfiddle.net/sheriffderek/5u7y21we/ - sheriffderek

6
我最近在玩弄flexbox,通过试验和以下推理,我找到了解决方案。但是,在现实中,我不确定这是否确切地发生了。
如果真实宽度受到flex系统的影响。因此,在元素的宽度达到父元素的最大宽度后,CSS中设置的额外宽度将被忽略。然后将宽度设置为100%是安全的。
由于img标记的高度是从图像本身派生的,因此将高度设置为0%可能会产生某些效果。(这就是我不清楚的地方...但是我认为这应该能够修复它)
演示:DEMO
.slider {
    display: flex;
}
.slider img {
    height: 0%;
    width: 100%;
    margin: 0 5px;
}

目前仅在Chrome中可用


有趣,但似乎是个bug。根据规范,“*百分比是相对于生成的框的包含块的高度计算的。如果未明确指定包含块的高度(即它取决于内容高度),并且此元素未绝对定位,则该值计算为auto*”。这就是Firefox上发生的情况。 - Oriol
请解释一下在 Firefox 和 Chrome 中的区别:http://jsfiddle.net/xLc2Le0k/8/。 - Muhammad Umer
宽度在Firefox中似乎所起的作用与Chrome中高度所起的作用相同。 - Muhammad Umer
很有趣,但我担心仅限于X浏览器的解决方案并不是真正的解决方案。您在此处的评论fiddle:http://jsfiddle.net/xLc2Le0k/8/绝对是**迷人的**,尤其是在FF中。这似乎表明,如果图像真正为100%,则FF会使图像高度“成比例”地与图像高度相同。换句话说,img不知道容器的显示方式:flex。这就解释了为什么在FF中,如果将img的宽度设置为100%,则图像比将宽度设置为自动时更高。 - coderMe
这个有点接近……但只在Chrome中有效:http://jsfiddle.net/sheriffderek/xLc2Le0k/270/ - sheriffderek

4
这种行为是可以预料的。默认情况下,flex容器会将所有子元素都拉伸。图片也不例外(即父元素会有align-items: stretch属性)。
为了保持宽高比,我们有两个解决方案:
1. 将默认的align-items: stretch属性替换为align-items: flex-startalign-self: center等。 http://jsfiddle.net/e394Lqnt/3/ 2. 将对齐属性专门设置给子元素本身:例如align-self: centeralign-self: flex-start等。 http://jsfiddle.net/e394Lqnt/2/

0

声明给定元素的 display: flex; 属性。
align-items: center;


-1

我之前也遇到了同样的问题。使用flex对齐来居中你的元素。你需要使用align-items: center而不是align-content: center。这将保持宽高比,而align-content则不能保持宽高比。


-1

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

.container{display:flex; height:100%;} img{width:100%;height:auto;}

然后在你的HTML中,你的容器将包裹标签图像

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

这适用于IE和其他浏览器


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