如何使div元素自动调整大小并保持纵横比?

5

我想在屏幕中心放置一个 div 元素。这个元素应该有特定的 widthheight,当它适应了可用的窗口空间时,但是当可用的窗口空间不足时,它应该缩小以适应,并且保持其原始纵横比。

我看了很多关于减小 width 的示例,但没有适用于窗口大小变化时 widthheight 都变化的示例。

这是我的当前 CSS:

* {
    border: 0;
    padding: 0;
    margin: 0;
}
.stage_wrapper {
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background: gray;
}
.stage {
    width: 960px;
    height: 540px;
    max-width: 90%;
    max-height: 90%;
    display: flex;
    justify-content: center;
    align-items: center;
    background: chocolate;
    object-fit: contain; /* I know this is for images, it's an example of what I'm looking for */
}

而且,我的当前HTML代码:

<div class="stage_wrapper">
    <div class="stage">
        <p>Some text</p>
    </div>
</div>

这里展示一个居中的 div,它有固定的 宽度 960px 和 高度 540px 。它不应该超过这个大小。

然后,如果我改变窗口大小,使其比这个更小的 宽度高度div 元素会成功地缩小 - 但它没有保持原始的宽高比,这就是我想要的。我希望它响应宽度和高度的变化。

这可能吗?

4个回答

6

aspect-ratio ref属性现在得到了很好的支持,因此您可以使用以下内容:

body {
  height: 100vh;
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background: gray;
}


.stage {
  --r: 960 / 540;

  aspect-ratio: var(--r);
  width:min(90%, min(960px, 90vh*(var(--r))));
  
  display: flex;
  justify-content: center;
  align-items: center;
  
  
  background: 
    /* this gradient is a proof that the ratio is maintained since the angle is fixed */
    linear-gradient(30deg,red 50%,transparent 50%),
    chocolate;
}
<div class="stage">
  <p>Some text</p>
</div>


旧答案

这里有一个使用视口单位和clamp()的想法。它是一种if else用于测试屏幕宽度是否大于高度(考虑比例),并基于结果进行计算。

在下面的代码中,我们有两个变量cvch,只有一个变量将等于1

  • 如果是cv,则宽度较大,因此我们将高度设置为cv,宽度将基于该高度,因此逻辑上为cv/ratio

  • 如果是ch,则高度较大,因此我们将宽度设置为cv,高度将基于该宽度,因此逻辑上为ch/ratio

clamp()中,我使用1vh/1vw乘以90,这相当于您的90%,以获得90vh/90vw

body {
  height: 100vh;
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background: gray;
}


.stage {
  --r: calc(960 / 540);
  
  --cv: clamp(0px,(100vw - 100vh*var(--r))*10000,1vh);
  --ch: clamp(0px,(100vh*var(--r) - 100vw)*10000,1vw);

  height: calc((var(--cv) + var(--ch)/var(--r)) * 90 );
  width:  calc((var(--ch) + var(--cv)*var(--r)) * 90 );
  
  max-width: 960px;
  max-height: 540px; /* OR calc(960px/var(--r)) */
  
  display: flex;
  justify-content: center;
  align-items: center;
  
  
  background: 
    /* this gradient is a proof that the ratio is maintained since the angle is fixed */
    linear-gradient(30deg,red 50%,transparent 50%),
    chocolate;
}
<div class="stage">
  <p>Some text</p>
</div>

理论上,夹具可以简化为:

--cv: clamp(0px,(1vw - 1vh*var(--r)),1vh);
--ch: clamp(0px,(1vh*var(--r) - 1vw),1vw);

为了避免任何四舍五入问题,也不会出现像 0.x 这样的值,我考虑使用一个大数来确保如果为正数,则始终被夹在 1 之间。

更新

看起来 Firefox 存在一个 bug,因此这里提供了相同代码的另一个版本:

body {
  height: 100vh;
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background: gray;
}


.stage {
  --r: calc(960 / 540);
  
  --cv: clamp(0px,(100vw - 100vh*var(--r))*100,90vh);
  --ch: clamp(0px,(100vh*var(--r) - 100vw)*100,90vw);

  height: calc((var(--cv) + var(--ch)/var(--r)) );
  width:  calc((var(--ch) + var(--cv)*var(--r)) );
  
  max-width: 960px;
  max-height: 540px; /* OR calc(960px/var(--r)) */
  
  display: flex;
  justify-content: center;
  align-items: center;
  
  
  background: 
    /* this gradient is a proof that the ratio is maintained since the angle is fixed */
    linear-gradient(30deg,red 50%,transparent 50%),
    chocolate;
}
<div class="stage">
  <p>Some text</p>
</div>


这太棒了,非常感谢!这种CSS对我来说确实很新。你知道我可以期望什么样的向后兼容性吗? - Francisco Zarabozo
@FranciscoZarabozo 我认为只有IE会对我的代码有问题,这并不奇怪,但你在其他浏览器上应该没有问题。clamp和CSS变量现在得到了很好的支持。 - Temani Afif
@TemaniAfif 这真的很聪明!但是我有点难以理解代码。你能详细说明一下 --cv--ch 是什么吗?即使定义变量的全名也会有所帮助。谢谢! - LandonSchropp
@LandonSchropp 我已经详细说明了这两个变量的含义 :) .. 名称并不重要,我可以称它们为 ab。你只需要理解我所描述的逻辑即可。 - Temani Afif
@TemaniAfif你在帖子中没有提到--cv--ch变量代表什么。为什么选择这些名称?它们是什么意思?我试图理解你的逻辑,但很难因为你没有解释为什么选择这些变量。如果你的变量有明确的命名,那会更容易一些。https://medium.com/coding-skills/clean-code-101-meaningful-names-and-functions-bf450456d90c - LandonSchropp

2
任何使用vwvh的解决方案都假定您的容器是视口。但是,如果您需要一个适合于任何容器的letterboxing元素怎么办?
换句话说,您希望对于不是<img><video>的元素,具有object-fit: contain的行为。
您需要一个在垂直和水平方向上都居中的容器:
#container {
  display: flex;
  align-items: center;
  justify-content: center;
}

一个带有固定aspect-ratio的包含对象,它要么将其widthheight拉伸到100%

#object {
  aspect-ratio: 16/9;
  overflow: hidden;
  [dimension]: 100%;
}

当容器很高时,[dimension]width,否则为height

如果事先不知道它是否会很高,需要使用一点JavaScript来检查高度并决定要拉伸哪个维度。

function update() {
  const isTall = container.clientWidth / container.clientHeight < aspectRatio;
  object.style.width = isTall ? '100%' : 'auto';
  object.style.height = isTall ? 'auto' : '100%';
}

new ResizeObserver(update).observe(container);

我认为在不使用JavaScript的情况下,无法通过纯CSS实现此维度切换。

这里是一个演示


1

您可以像这样设置高度和宽度:

  height: 80vw;
  width: 80vw;

接下来,您可以设置最大高度和宽度,如下所示:

  max-height: 100vh;
  max-width: 100vh;

如果你有其他的东西挡住了,比如头部信息:

  max-height: calc(100vh - 32px);
  max-width: calc(100vh - 32px);

32px是指它占据了多少像素(或其他度量单位)


-1

可以使用这个 CSS:

.stage_wrapper {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: gray;

}

.stage {
width: 50vw;
height: 40vw;
max-width: 90%;
max-height: 90%;
display: flex;
justify-content: center;
align-items: center;
background: chocolate;
object-fit: contain; /* I know this is for images, it's an example of what I'm looking for */

}

如果您想要调整大小,可以修改代码,但这将使您的 div 具有固定的宽高比。


仅减小窗口高度时似乎无法正常工作。 - Francisco Zarabozo

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