我有一个网站要放在一起,它具有大约 16:9
横向的固定纵横比,例如视频。
我想让它居中并扩展以填充可用宽度和可用高度,但永远不要在任何一侧变大。
例如:
一个又高又薄的页面会使内容拉伸整个宽度,同时保持成比例的高度。一个短而宽的页面将使内容延伸到整个高度,并具有成比例的宽度。
我一直在研究两种方法:
使用具有正确纵横比的图像来扩展容器 div,但我无法让它在主要浏览器中的行为方式相同。设置比例底部填充,但这仅适用于宽度并忽略高度。它只是随着宽度变大并显示垂直滚动条。
我知道你可以很容易地用 JS 做到这一点,但我想要一个纯 CSS 解决方案。
有任何想法吗?
position: relative (default) height: 0 padding-<top/bottom>: H/W*100%
使用新的 CSS viewport units vw
和 vh
(视口宽度/视口高度)
垂直和水平调整大小,您会看到元素将始终填充最大视口大小,而不会破坏比例并且没有滚动条!
(纯)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
只需在 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;
}
将 CSS media query @media
与 CSS viewport units vw
和 vh
一起使用以适应视口的纵横比。这也有更新其他属性的好处,例如 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-width
和max-height
approach 非常相似,只是更灵活。
我最初的问题是如何同时拥有一个固定方面的元素,但又如何将其准确地放入指定的容器中,这使得它有点繁琐。如果您只是想让单个元素保持其纵横比,那就容易多了。
我遇到的最好的方法是给一个元素零高度,然后使用百分比 padding-bottom 给它高度。百分比填充总是与元素的宽度成正比,而不是它的高度,即使它的顶部或底部填充也是如此。
因此,您可以利用它为元素指定一个百分比宽度以位于容器内,然后使用填充来指定纵横比,或者换句话说,它的宽度和高度之间的关系。
.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 单位,因此您可能无法接受我的问题的答案,您可能必须使用更低保真的东西。
我了解到,您曾询问过您想要一个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);
window.onresize
在浏览器改变大小时触发。
现在指定了一个新的 CSS 属性来解决这个问题:object-fit
。
https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
该功能目前已得到广泛支持 (http://caniuse.com/#feat=object-fit)。
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,这使得值的来源更加明显。
基于 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">×</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 的大小。
经过大量测试,这对我来说现在完美无缺。
这里是基于@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
vh
、vw
、vmin
、vmax
)的实现有问题。但是,有一个 workaround,它使用媒体查询来定位 iOS 设备。overflow: hidden;
添加到 body 来修复很简单 .. 所以我的 body css decl现在看起来像这样:body { width: 100%; height: 100%; overflow: hidden;
}