更改高度时保持图像纵横比
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;
【问题讨论】:
据我所知,最好的解决方案是使用<div>
和 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 中,允许固有纵横比通知主尺寸计算。作为一种解决方法,您可以用<div>
或<span>
等包装每个<img>
。
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 > divmin-width:0
。
flexbox 规范引入了一个新的auto
值作为min-width
和min-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-start
或align-self: center
等,
http://jsfiddle.net/e394Lqnt/3/
或
-
将 align 属性专门设置为子项本身:例如,
align-self: center
或 align-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 不会保持纵横比。
【讨论】:
以上是关于更改高度时保持图像纵横比的主要内容,如果未能解决你的问题,请参考以下文章