Div 适合父级并保持纵横比

Div that fits into parent and maintains an aspect ratio

我有一个保持纵横比的 div 元素:它根据宽度计算高度(使用填充技巧)。我想做的是将这个 div 放入另一个,通过在垂直和水平方向上安装最大可用的 space,不裁剪。我认为最接近我想要的是 object-fit: contain - 只有 img

我希望 div 在保持宽高比的同时覆盖可能的最大高度和宽度。没有垂直或水平裁剪。

仅 CSS 有可能吗?如果是,怎么做?

更新: 一个很好的 article 目前的情况。

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

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>

好吧,看来只靠CSS是解决不了的。如果有人感兴趣,我整理了一个 React component 来完成这项工作(测试和更好的自述文件,当我有时间的时候)。

它将其子级包装成 div 并使用 JavaScript 计算 div 的宽度和高度,以便在保持 space 的同时容纳可用的 space给定纵横比。它基本上会拉伸包装纸,直到其中一侧达到最大值。

重大更新 已找到 CSS only solution

到目前为止我设法实现的唯一解决方法是将子元素包装到 svg 的 foraignObject 标记中:

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 命名空间的元素可能会导致更多问题(?)。

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

aspect-ratiooverflow:hidden 在 Chromium 88、Firefox 87Safari 技术预览 118 是你的朋友。

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

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

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

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