ChatGPT解决这个技术问题 Extra ChatGPT

保持div的纵横比但在CSS中填充屏幕宽度和高度?

我有一个网站要放在一起,它具有大约 16:9 横向的固定纵横比,例如视频。

我想让它居中并扩展以填充可用宽度和可用高度,但永远不要在任何一侧变大。

例如:

一个又高又薄的页面会使内容拉伸整个宽度,同时保持成比例的高度。一个短而宽的页面将使内容延伸到整个高度,并具有成比例的宽度。

我一直在研究两种方法:

使用具有正确纵横比的图像来扩展容器 div,但我无法让它在主要浏览器中的行为方式相同。设置比例底部填充,但这仅适用于宽度并忽略高度。它只是随着宽度变大并显示垂直滚动条。

我知道你可以很容易地用 JS 做到这一点,但我想要一个纯 CSS 解决方案。

有任何想法吗?

sitepoint.com/… 将容器 div 设置为 position: relative (default) height: 0 padding-<top/bottom>: H/W*100%

D
Danield

使用新的 CSS viewport units vwvh(视口宽度/视口高度)

FIDDLE

垂直和水平调整大小,您会看到元素将始终填充最大视口大小,而不会破坏比例并且没有滚动条!

(纯)CSS

div
{
    width: 100vw; 
    height: 56.25vw; /* height:width ratio = 9/16 = .5625  */
    background: pink;
    max-height: 100vh;
    max-width: 177.78vh; /* 16/9 = 1.778 */
    margin: auto;
    position: absolute;
    top:0;bottom:0; /* vertical center */
    left:0;right:0; /* horizontal center */
}

* {边距:0;填充:0; } div { 宽度:100vw;高度:56.25vw; /* 100/56.25 = 1.778 */ 背景:粉红色;最大高度:100vh;最大宽度:177.78vh; /* 16/9 = 1.778 */ 边距:自动;位置:绝对;顶部:0;底部:0; /* 垂直居中 */ left: 0;右:0; /* 水平居中 */ }

如果您想使用最多 90% 的视口宽度和高度:FIDDLE

{边距:0;填充:0; } div { 宽度:90vw; /* 90% 的视口宽度 */ height: 50.625vw; /* 比率 = 9/16 * 90 = 50.625 */ 背景:粉红色;最大高度:90vh;最大宽度:160vh; /* 16/9 * 90 = 160 */ 边距:自动;位置:绝对;顶部:0;底部:0;左:0;右:0; }

此外,浏览器支持也很好:IE9+、FF、Chrome、Safari-caniuse


这是一个非常好的清洁解决方案。不过,理想情况下,我可以在更远的地方使用浏览器支持。我猜在较旧的浏览器上,您只需设置最小宽度/高度并将其设置为 - 如果它有滚动条,就这样吧
不幸的是,最近的 iOS 版本 don't support 或视口单元(vhvwvminvmax)的实现有问题。但是,有一个 workaround,它使用媒体查询来定位 iOS 设备。
我正在尝试实现您那里的 90% 解决方案,但我的图像不是 16:9,它正在垂直压缩我的图像。我的图像有各种尺寸。有解决方案吗?
@J82 如果您的图像具有不同的宽度/高度比,那么您要么需要每个比率的代码(例如通过单独的类),要么您需要裁剪图像以适应特定的比率。如果您查看我发布的小提琴中的评论,您可以轻松修改代码以适应您需要的比例
@NaturalBornCamper - 我偶尔也会出现滚动条的问题,在我的 webgl canvas only 应用程序中(需要保持 16:9 AR),但是通过将 overflow: hidden; 添加到 body 来修复很简单 .. 所以我的 body css decl现在看起来像这样:body { width: 100%; height: 100%; overflow: hidden;}
C
Christophe Marois

只需在 LESS 混合中重新制定 Danield 的答案,以供进一步使用:

// Mixin for ratio dimensions    
.viewportRatio(@x, @y) {
  width: 100vw;
  height: @y * 100vw / @x;
  max-width: @x / @y * 100vh;
  max-height: 100vh;
}

div {

  // Force a ratio of 5:1 for all <div>
  .viewportRatio(5, 1);

  background-color: blue;
  margin: 0;
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
}

C
Community

CSS media query @mediaCSS viewport units vwvh 一起使用以适应视口的纵横比。这也有更新其他属性的好处,例如 font-size

This fiddle 演示了 div 的固定纵横比,以及与其比例完全匹配的文本。

初始大小基于全宽:

div {
  width: 100vw; 
  height: calc(100vw * 9 / 16);

  font-size: 10vw;

  /* align center */
  margin: auto;
  position: absolute;
  top: 0px; right: 0px; bottom: 0px; left: 0px;

  /* visual indicators */
  background:
    url(data:image/gif;base64,R0lGODlhAgAUAIABAB1ziv///yH5BAEAAAEALAAAAAACABQAAAIHhI+pa+EPCwA7) repeat-y center top,
    url(data:image/gif;base64,R0lGODlhFAACAIABAIodZP///yH5BAEAAAEALAAAAAAUAAIAAAIIhI8Zu+nIVgEAOw==) repeat-x left center,
    silver;
}

然后,当视口比所需的宽高比宽时,切换到高度作为基本度量:

/* 100 * 16/9 = 177.778 */
@media (min-width: 177.778vh) {
  div {
    height: 100vh;
    width: calc(100vh * 16 / 9);

    font-size: calc(10vh * 16 / 9);
  }
}

这与@Danield 的max-widthmax-height approach 非常相似,只是更灵活。


H
Henry Gibson

我最初的问题是如何同时拥有一个固定方面的元素,但又如何将其准确地放入指定的容器中,这使得它有点繁琐。如果您只是想让单个元素保持其纵横比,那就容易多了。

我遇到的最好的方法是给一个元素零高度,然后使用百分比 padding-bottom 给它高度。百分比填充总是与元素的宽度成正比,而不是它的高度,即使它的顶部或底部填充也是如此。

W3C Padding Properties

因此,您可以利用它为元素指定一个百分比宽度以位于容器内,然后使用填充来指定纵横比,或者换句话说,它的宽度和高度之间的关系。

.object {
    width: 80%; /* whatever width here, can be fixed no of pixels etc. */
    height: 0px;
    padding-bottom: 56.25%;
}
.object .content {
    position: absolute;
    top: 0px;
    left: 0px;
    height: 100%;
    width: 100%;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    padding: 40px;
}

所以在上面的例子中,对象占据了容器宽度的 80%,然后它的高度是那个值的 56.25%。如果它的宽度是 160 像素,那么底部填充,因此高度将是 90 像素 - 16:9 的纵横比。

这里的小问题可能对您来说不是问题,是您的新对象内部没有自然空间。例如,如果您需要放入一些文本并且该文本需要采用它自己的填充值,则您需要在其中添加一个容器并在其中指定属性。

一些较旧的浏览器也不支持 vw 和 vh 单位,因此您可能无法接受我的问题的答案,您可能必须使用更低保真的东西。


为避免在此处使用额外的标记,您可以使用 ::before 或 ::after 添加元素,并为该元素指定高度 0 和相对于对象宽度的 padding-bottom 和其自身的 0 宽度。这将具有相同的效果,但标记较少,并且将使整个对象区域可用于放入内容而无需容器。
J
Jason J. Nathan

我了解到,您曾询问过您想要一个CSS特定的解决方案。要保持纵横比,您需要将高度除以所需的纵横比。 16:9 = 1.777777777778。

要获得容器的正确高度,您需要将当前宽度除以 1.777777777778。由于您无法仅使用 CSS 检查容器的 width 或除以百分比为 CSS,因此如果没有 JavaScript(据我所知),这是不可能的。

我编写了一个可以保持所需纵横比的工作脚本。

HTML

<div id="aspectRatio"></div>

CSS

body { width: 100%; height: 100%; padding: 0; margin: 0; }
#aspectRatio { background: #ff6a00; }

JavaScript

window.onload = function () {
    //Let's create a function that will scale an element with the desired ratio
    //Specify the element id, desired width, and height
    function keepAspectRatio(id, width, height) {
        var aspectRatioDiv = document.getElementById(id);
        aspectRatioDiv.style.width = window.innerWidth;
        aspectRatioDiv.style.height = (window.innerWidth / (width / height)) + "px";
    }

    //run the function when the window loads
    keepAspectRatio("aspectRatio", 16, 9);

    //run the function every time the window is resized
    window.onresize = function (event) {
        keepAspectRatio("aspectRatio", 16, 9);
    }
}

如果您想使用不同的比例显示其他内容,可以再次使用 function

keepAspectRatio(id, width, height);

感谢您的回答。在脚本中执行此操作相对简单,但我真的想要一个基于 CSS 的解决方案。我想要一个非常快速可靠的响应式解决方案,我发现有时在不同浏览器中调整事件大小有点滞后。在浏览器调整大小发生后,您最终会进行一些转换,因此它不会提供最佳的用户体验。想要在浏览器改变大小时呈现的东西,因此是纯 CSS。
@Henry Gibson 该脚本已经在 Chrome、FF、IE、Opera 和 Safari 中进行了测试。即使在旧版本的浏览器中,所有工作都可以快速运行并且可靠。每个浏览器都会触发它自己的事件。 window.onresize 在浏览器改变大小时触发。
请记住,最终用户不会像开发人员那样调整浏览器的大小
d
damd

现在指定了一个新的 CSS 属性来解决这个问题:object-fit

https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit

该功能目前已得到广泛支持 (http://caniuse.com/#feat=object-fit)。


C
Community

Danield's answer 很好,但只能在 div 填满整个视口时使用,或者在知道视口中其他内容的宽度和高度的情况下使用一点 calc

但是,通过将 margin-bottom 技巧与上述答案中的方法相结合,可以将问题简化为只需要知道其他内容的高度。如果您有一个固定高度的标题,这很有用,但例如,侧边栏的宽度是未知的。

身体{边距:0;边距顶部:100px; /* 模拟标题 */ } main { margin: 0 auto;最大宽度:计算(200vh - 200px); } 部分 { 填充底部:50%;位置:相对; } div { 位置:绝对;背景颜色:红色;顶部:0;左:0;底部:0;右:0; }

Here it is in a jsfiddle using scss,这使得值的来源更加明显。


C
CPHPython

基于 Daniel's answer,我为 Bootstrap 模态对话框内的 youtube 视频 iframe 编写了这个带有插值 (#{}) 的 SASS mixin:

@mixin responsive-modal-wiframe($height: 9, $width: 16.5,
                                $max-w-allowed: 90, $max-h-allowed: 60) {
  $sides-adjustment: 1.7;

  iframe {
    width: #{$width / $height * ($max-h-allowed - $sides-adjustment)}vh;
    height: #{$height / $width * $max-w-allowed}vw;
    max-width: #{$max-w-allowed - $sides-adjustment}vw;
    max-height: #{$max-h-allowed}vh;
  }

  @media only screen and (max-height: 480px) {
    margin-top: 5px;
    .modal-header {
      padding: 5px;
      .modal-title {font-size: 16px}
    }
    .modal-footer {display: none}
  }
}

用法:

.modal-dialog {
  width: 95vw; // the modal should occupy most of the screen's available space
  text-align: center; // this will center the titles and the iframe

  @include responsive-modal-wiframe();
}

HTML:

<div class="modal">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Video</h4>
      </div>
      <div class="modal-body">
        <iframe src="https://www.youtube-nocookie.com/embed/<?= $video_id ?>?rel=0" frameborder="0"
          allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
          allowfullscreen></iframe>
      </div>
      <div class="modal-footer">
        <button class="btn btn-danger waves-effect waves-light"
          data-dismiss="modal" type="button">Close</button>
      </div>
    </div>
  </div>
</div>

当宽度或高度与视频不成比例时,这将始终显示没有 youtube 添加到 iframe 的黑色部分的视频。笔记:

$sides-adjustment 是一个轻微的调整,以补偿这些黑色部分出现在侧面的一小部分;

在非常低高度的设备(< 480px)中,标准模式占用了大量空间,所以我决定:隐藏 .modal-footer;调整 .modal-dialog 的位置;减小 .modal-header 的大小。

隐藏.modal-footer;

调整 .modal-dialog 的位置;

减小 .modal-header 的大小。

经过大量测试,这对我来说现在完美无缺。


A
Angel Fraga Parodi

这里是基于@Danield 解决方案的解决方案,即使在 div 中也可以使用。

在该示例中,我使用的是 Angular,但它可以快速迁移到 vanilla JS 或其他框架。

主要思想只是将@Danield 解决方案移动到一个空的 iframe 中,并在 iframe 窗口大小更改后复制尺寸。

该 iframe 必须适合其父元素的尺寸。

https://stackblitz.com/edit/angular-aspect-ratio-by-iframe?file=src%2Findex.html

这里有几张截图:

https://i.stack.imgur.com/pDWZU.png

https://i.stack.imgur.com/7EQes.png

https://i.stack.imgur.com/btSrW.png