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

我有一个网站放在一起,有一个固定的长宽比大约 16:9景观,像一个视频。

我希望它的中心和扩展,以填补可用的宽度和可用的高度,但从来没有增长较大的任何一方。

例如:

  1. 一个高的和薄的页面将有内容拉伸的全宽,同时保持一个比例的高度。
  2. 一个短而宽的页面,其内容会延伸到整个高度,并且有一个比例的宽度。

我一直在研究两种方法:

  1. 使用一个具有正确高宽比的图像来展开一个容器 div,但是我无法让它在主流浏览器中以同样的方式运行。
  2. 设置一个比例的底部填充,但是这只对宽度有效,而忽略了高度。它只是随着宽度的增加而变得越来越大,并且显示垂直滚动条。

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

有什么想法吗?

138232 次浏览

我知道你问你想要一个 CSS特定的解决方案。为了保持高宽比,您需要将高度除以所需的高宽比。16:9 = 1.777777777778.

要获得容器的正确高度,需要将当前宽度除以1.77777777778。因为你不能检查的 width的容器只有 CSS或除以百分比是 CSS,这是不可能的没有 JavaScript(据我所知)。

我已经写了一个工作脚本,将保持所需的高宽比。

超文本标示语言

<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 视图单元 vwvh(视口宽度/视口高度)

小提琴

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

(纯) 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 */
}

* {
margin: 0;
padding: 0;
}
div {
width: 100vw;
height: 56.25vw;
/* 100/56.25 = 1.778 */
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 */
}
<div></div>

If you want to use a maximum of say 90% width and height of the viewport: FIDDLE

* {
margin: 0;
padding: 0;
}
div {
width: 90vw;
/* 90% of viewport vidth */
height: 50.625vw;
/* ratio = 9/16 * 90 = 50.625 */
background: pink;
max-height: 90vh;
max-width: 160vh;
/* 16/9 * 90 = 160 */
margin: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
<div></div>

Also, browser support is pretty good too: IE9+, FF, Chrome, Safari- caniuse

只是重新制定 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;
}

对于这个问题,我最初的问题是如何同时具有一个固定方面的元素,但是要在一个指定的容器中精确地适应这个元素,这使得它有点复杂。如果您只是想要一个单独的元素来保持它的高宽比,那么这会容易得多。

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

W3C 填充属性

利用这一点,你可以给一个元素一个百分比的宽度来放在容器中,然后填充来指定长宽比,或者换句话说,它的宽度和高度之间的关系。

.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% 。如果它的宽度是160px,那么底部填充,因此高度将是90px-一个16:9的方面。

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

另外,vw 和 vh 单元在一些较老的浏览器上不受支持,所以对于我的问题,可以接受的答案可能对您来说是不可能的,您可能需要使用一些更低保真的东西。

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

Https://developer.mozilla.org/en-us/docs/web/css/object-fit

这个特性现在得到了广泛的支持(http://caniuse.com/#feat=object-fit)。

使用 CSS 媒体查询 @media连同 CSS 视图单元 vwvh来适应视窗的高宽比。这还有更新其他属性(如 font-size)的好处。

这个小提琴 演示了 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 接近非常相似,只是更加灵活。

Danield 的回答 很好,但是它只能在 div 填充整个 viewport 时使用,或者通过使用一点 calc,可以在已知 viewport 中其他内容的宽度和高度的情况下使用。

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

body {
margin: 0;
margin-top: 100px; /* simulating a header */
}


main {
margin: 0 auto;
max-width: calc(200vh - 200px);
}


section {
padding-bottom: 50%;
position: relative;
}


div {
position:absolute;
background-color: red;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
<main>
<section>
<div></div>
</section>
</main>

这里是使用 scss 的 jsfiddle,这使得值的来源更加明显。

基于 丹尼尔的回答,我写了这个 SASS 混合与插值(#{})的 youtube 视频的 iframe,是在一个 Bootstrap 模式对话框:

@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)中,标准模式占用了大量空间,所以我决定:
    1. 隐藏 .modal-footer;
    2. 调整 .modal-dialog的定位;
    3. 减小 .modal-header的尺寸。

经过大量的测试,我现在可以完美地使用它了。

这里有一个基于@Danield 解决方案的解决方案,它甚至可以在 div 中工作。

在这个例子中,我使用的是 Angular,但是它可以快速转换到普通的 JS 或其他框架。

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

那个 iframe 必须符合它的父元素的尺寸。

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

下面是一些截图:

enter image description here

enter image description here

enter image description here