Flexbox 图像按高度缩放并保持纵横比

24
我有一个DIV,使用CSS flexbox将其缩放到可用高度。在这个DIV中有一张图像,我希望它与DIV一起按比例缩放,较小的维度应居中。我可以使图像遵循DIV的宽度,但不能遵循高度,因此纵向图像会超出DIV的范围。这里是一个jsFiddle演示问题: https://jsfiddle.net/aer69rcr/

html, body {
  height: 100%;
  margin: 0;
}
.container {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.box {
  flex: 1 1 auto;
  display: flex;
  justify-content: center;
  align-items: center;
}
.box img {
  width: auto;
  height: auto;
  max-width: 90%;
  max-height: 90%;
}
<div class="container">
  <div class="box"></div>
  <div class="box" style="background: pink;">
    <img src="//dummyimage.com/300" />
  </div>
  <div class="box"></div>
</div>


你想让图片适应高度吗,即使它本来比较小?(你在示例中使用的是一张相当大的图片,所以我不确定) - Ben Philipp
我想要实现的第一件事是根据需要进行缩放。 - languitar
不好意思,图像应保留其原始纵横比。如果此比例与容器的比例不同,则在调整大小后,图像应沿较小的轴居中。 - languitar
弹性盒子布局是否是为了解决与此相关的图像缩放问题而实现的,还是出于其他原因?(即:更改为块DIV是否是一种选择?) - Ben Philipp
我可能可以改用其他的方法,但是使用flexbox实际上很容易实现我目前所需的功能。 - languitar
显示剩余3条评论
5个回答

15
当您将高度指定为百分比值时,它是相对于父元素的高度的百分比。对于 <img> 标签也是如此。
在这个高度未知的 flexbox 布局中,您可以使用 position 技巧使图像适应 flex 子项的宽度和高度,并使用 transform 技巧进行居中。 jsFiddle

html, body {
  height: 100%;
  margin: 0;
}
.container {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.box {
  flex: 1 1 auto;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}
.box:nth-child(2) {
  background: pink;
}
.box img {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}
<div class="container">
  <div class="box"></div>
  <div class="box">
    <img src="//dummyimage.com/300" />
  </div>
  <div class="box"></div>
</div>

你还可以使用背景图片,这可以使得操作更加简便,关键是使用contain的值。请参见下面的简化演示。

jsFiddle

html, body {
  height: 100%;
  margin: 0;
}
.container {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.box {
  flex: 1 1 auto;
}
.box:nth-child(2) {
  background: pink url(//dummyimage.com/300) no-repeat center center / contain;
}
<div class="container">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</div>


8

如果你可以从flex变为block:

https://jsfiddle.net/svArtist/ug6eoxfs/

正如@janfoeh指出的那样,使用object-fit:contain就可以实现:

body, html {
    height: 100%;
    margin: 0;
    padding: 0;
    overflow:hidden;
    position:relative;
}

.container {
    width: 100%;
    max-width: 100%;
    height: 100%;
    max-height: 100%;
}

.box {
    background: yellow;
    width: 100%;
    padding: 0 5%;
    box-sizing:border-box;
    max-width: 100%;
    height: 100%;
    max-height:100%;
    position:relative;
}

.box img {
    height:100%;
    max-height: 100%;
    width: auto;
    max-width: 100%;
    margin: auto;
    position:absolute;
    top:0%;
    bottom:0%;
    left:0%;
    right:0%;
    display:block;
    object-fit: contain;
}

如果确实需要使用Flex布局,那么作为最后手段,您可以考虑使用background-image,这样整个过程就变得非常简单了:https://jsfiddle.net/svArtist/e1c2tLme/
    background: url(http://placehold.it/300) no-repeat center center;
    background-size: contain;

除此之外,我找不到不涉及脚本编写的方法。

抱歉,但这正是我在fiddle中的代码,它并没有起作用? - languitar
谢谢你提供的解决方案。我会尝试一下并看看是否可以重新排版或切换到背景图片。不过我还不确定是否可以将其视为对于 flexbox 问题的具体回答。 - languitar
是的,这并不理想。 那么JavaScript不是一个选项吗? - Ben Philipp
我通常会在浏览器中阻止JavaScript。因此,对于我的网站使用它是一个不好的习惯 ;) - languitar
5
@languitar 屏蔽 JavaScript?该死,丹尼尔。 - scniro

6

使用Flexbox布局! (JSFiddle)

body, html {
    height: 100%;
    margin: 0;
    padding: 0;
}

.container {
    display: flex;
    flex-flow: column;
    width: 100%;
    height: 100%;
}

.box {
    flex: 1 1 auto;
    background: yellow;
    display: flex;
    justify-content: center;
    align-items: stretch;
}

.box img {
    width: 100%;
    object-fit: contain;
}

关键是使用object-fit: contain;来保持比例,同时使用align-items: stretch;确保图片在左右两侧不被裁剪(这可能是一个bug?)。


这确实限制了图像,但是它留下了额外的高度。请参见https://fiddle.jshell.net/betae931/1,在窄面板宽度上。 - isherwood

1
基于@darrylyeo的答案。
.container {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: stretch;

  width: 100%;
  height: 100%;

  border-radius: 4px;
  background-color: hsl(0, 0%, 96%);
}

.box {
  border-radius: 4px;
  display: flex;
}

.box img {
  width: 100%;
  object-fit: contain;
  border-radius: 4px;
}

-1

删除图像标签,并将其设置为 .box div 的背景,使用 background-size:cover;
jsfiddle 1

或者,如果您想避免裁剪:

删除图像标签,并将其设置为 .box div 的背景,使用 background-size:contain;
jsfiddle 2


两种情况都会导致图像裁剪。 - isherwood
您还没有展示一个与图片高度匹配的 flex 容器。这不符合 OP 的要求。 - isherwood

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