适应父元素并保持宽高比的Div

24

我有一个保持长宽比的

元素:它根据其宽度计算其高度(使用填充技巧)。我想做的是将此
放入另一个
中,以适应可用的最大空间,垂直和水平,不剪裁。我认为最接近我想要的东西是object-fit: contain - 仅适用于img

我希望

覆盖可能的最大高度和宽度,同时保持长宽比。没有垂直或水平裁剪。

只使用CSS是否可能? 如果可以,如何实现?

更新: 一篇很好的文章,介绍了目前的情况。

代码(可以是任何其他解决方案,不必基于此片段构建):

html,
body {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
}

.container {
  position: relative;
  width: 100%;
}

.container:before {
  content: "";
  display: block;
  width: 50%;
  padding-top: 50%;
}

.embed {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: red;
}
<div class="container">
  <div class="embed">
    this should accommodate all the available space and maintain aspect ratio, no crop when width is too wide
  </div>
</div>

enter image description here


你尝试过使用 width:100%; 吗? - Candy Crunch
请添加您的代码! - Adam
@Adam - 代码已添加 - haxpanel
你想让这个 div 覆盖整个屏幕的 100% 吗? - Adam
3
我想要拉伸直到一侧达到极限。 - haxpanel
显示剩余6条评论
5个回答

10

在Chromium 88上使用overflow:hidden,并且在Firefox 87和Safari Technology Preview 118中已经过时(不再适用),这时候aspect-ratio是你的好朋友。

2023年1月更新:

现在你还需要一个@container (aspect-ratio > X)容器查询。Firefox v110.0b2、Safari和Chromium都支持。

我已经更新了下面的代码,同时提供jsitor上的演示

html,
body {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
}

.container {
  container-type: size;
  container-name: resize-box;
  display: grid;
  resize: both;
  overflow: hidden;
  border: black 2px solid;
  min-width: 50px;
  min-height: 50px;
  width: 150px;
}

.embed {
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: contain;
  overflow: hidden;
  border: 2px red solid;
  box-sizing: border-box;
  display: flex;
  margin: auto;
}

@container resize-box (aspect-ratio > 1/1) {
  .embed {
    width: auto;
    height: 100%;
  }
}

.embed > div {
  margin: auto;
}
<div class="container">
  <div class="embed">
    <div>1:1</div>
  </div>
</div>


这是一个很棒的解决方案。我很惊讶它到现在为止还没有被选中或得到其他任何赞同。 - Brandon McConnell
这在 Microsoft Edge 108.0.1462.54 上不再起作用 :/ - Vapid
1
@Vapid确实如此 - 在Chrome中也是这样!不错的发现 - 需要调查一下... - Semmel
2
@Vapid,我更新了解决方案。应该可以在Chromium(包括Edge)和Safari上正常工作。你能试一下吗? - Semmel

4

好的,看起来这个问题不能仅通过CSS解决。如果有兴趣,我已经制作了一个React组件来完成这项工作(测试和更好的README很快就会出现,等我有时间)。

它将其子元素包装在一个div中,并使用JavaScript计算该div的宽度和高度,以适应可用空间,同时保持给定的纵横比。它基本上会拉伸包装器,直到其中一侧达到其最大值。

重要更新已经发现了一个仅使用CSS的解决方案


1
欢迎提供解决方案的链接,但请确保您的答案即使没有链接也是有用的:在链接周围添加上下文,以便其他用户了解它的内容和原因,然后引用您链接的页面中最相关的部分,以防目标页面不可用。仅仅提供链接的答案可能会被删除。 - dippas
5
“BREAKING UPDATE”是基于视口的宽度/高度而非父元素的宽度/高度。 - David Callanan

4

到目前为止,我所能够实现的唯一解决方法是将子元素包装在svg的foreignObject标签中:

const container = document.getElementById('container');
document.getElementById('btn').addEventListener('click', () => {
  container.style.height = container.style.height === '100px' ? '200px' : '100px';
});
body {
  margin: 1rem;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

button {
  margin-bottom: 1rem;
}


#container {
  background-color: #ffceaf;
  width: 400px;
}

svg {
  background-color: #b8d6ff;
  height: auto;
  width: auto;
  max-width: 100%;
  max-height: 100%;
  overflow: hidden;
}

#content {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  border: solid;
}
<button id="btn">Change parent height</button>

<div id="container" style="height: 100px;">
  <svg width="15000" height="5000">
    <foreignObject width="100%" height="100%">
      <div id="content">
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
        content content content content content content content
      </div>
    </foreignObject>
  </svg>
</div>

这种解决方案有以下缺点:

  • 浏览器兼容性(IE/Edge不能正确地支持 foraignObject)
  • 这不是最佳实践。包含来自不同 XML 命名空间的元素可能会引起进一步的问题。

我觉得在这里使用 JavaScript 可能是更好的选择。


3
这是我的纯CSS解决方案:

Codepen链接 或者在此处运行演示 ⬇

.resizable-container {
  resize: both;
  overflow: scroll;
  border: 1px solid black;
  padding: 3px;
  height: 140px;
  width: 330px;
}

.container {
  height: 100%;
  box-sizing: border-box;
}

.aspect-thing {
  aspect-ratio: 16/9;
  border: 2px red solid;
  box-sizing: border-box;
  
  max-width: 100%;
  max-height: 100%;
  margin: auto;
}
<div class="resizable-container"> 
  <div class="container">
    <div class="aspect-thing">
    </div>
  </div>
</div> 
<p>Resize me ^</p>

enter image description here


优秀的解决方案。但是我还想将子div垂直居中对齐。我找不到解决办法,所以我改为通过JavaScript手动计算div的宽度和高度,并使用flex来实现居中对齐。 - undefined

1

我不确定这是否是最好的解决方案,但它是纯CSS的。 它使用嵌套的flexbox。 外层flex-direction: row内层flex-direction: column。内部也很重要需要设置纵横比为 1/1 ,请注意 innerheight 已经设置和 inner:beforewidth 已经设置。

<div class="outer">
  <div class="inner"></div>
</div>

.outer {
  width: 80%;
  height: 80%;
  margin: auto;
  background-color: red;
  padding: 50px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.inner {
  height: 100%;
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

.inner:before {
  content: '';
  width: 100%;
  aspect-ratio: 1 / 1;
  background-color: blue;
}

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