我有一个放在一起的站点,它的固定长宽比大约为16:9横向,例如视频。
我想使它居中并扩展以填充可用的宽度和可用的高度,但不要在任何一侧变大。
例如:
高而薄的页面将使内容伸展整个宽度,同时保持成比例的高度。
短而宽的页面将使内容伸展到整个高度,并具有成比例的宽度。
我一直在研究两种方法:
使用具有正确长宽比的图像来展开容器div,但是我无法在主要浏览器中以相同的方式表现该图像。
设置成比例的底部填充,但这仅相对于宽度有效,而忽略高度。它的宽度不断增大,并显示垂直滚动条。
我知道您可以使用JS轻松完成此操作,但是我想要一个纯CSS解决方案。
有任何想法吗?
/将容器div设置为position: relative (default) height: 0 padding-: HW*100%
使用新的CSS视口单位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 */
}
* {
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 */
}
如果要使用最大90%的视口宽度和高度,请执行以下操作: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;
}
另外,浏览器支持也相当不错:IE9 +,FF,Chrome,Safari-caniuse
这是一个非常好的清洁解决方案。理想情况下,我可以在浏览器支持方面做得更好。我猜在较旧的浏览器上,您只有最小宽度/高度并将其设置为该值-如果它具有滚动条,就这样吧
嗯,谢谢您为我节省了2天的工作时间和无数用户的挫败感。如果可以的话,可以超过1000。
你救了我这么多时间。非常感谢。
完美...但是android浏览器..如4.3等呢?
不幸的是,最新的iOS版本不支持视口单元(vh,vw,vmin,vmax),或者实现的视口单元损坏。但是,有一种解决方法,它使用媒体查询来定位iOS设备。
我爱你。很好的解决方案!
我正在尝试实现您那里的90%解决方案,但是我的图像没有达到16:9并垂直压缩我的图像。我的图像有各种尺寸。有解决方案吗?
@ J82如果您的图像具有不同的宽高比,则您将需要每个比例的代码(通过单独的类说),或者需要裁剪图像以适合特定的比例。如果您查看我发布的小提琴中的评论,则可以轻松修改代码以适合所需的比例
元素需要为div或具有display:block
Android 4.3及以下WebView不支持vh
是否有与装箱尺寸有关的类似物品? (IIUC,vh / vw是相对于视口本身,而不是包含元素)
有人给这个人一块奖牌。
您将如何在容器div(而不是视口)内完成此工作? JavaScript的?
不幸的是,这导致水平滚动条:(
@NaturalBornCamper-我的webgl仅画布应用程序(需要保持16:9 AR)中有时也会出现带有滚动条的问题,但是通过在主体上添加overflow: hidden;可以轻松解决问题。所以我的主体css decl现在看起来像这样:body { width: 100%; height: 100%; overflow: hidden;}
使用javascript的等效方式是什么?
这是一个绝妙的解决方案。我可能还要补充一点,不要忘记那里的任何人的" margin:auto"部分。这样可以缩小内容时正确地使内容居中。
只需在LESS mixin中重新构成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
.viewportRatio(5, 1);
background-color: blue;
margin: 0;
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
}
将CSS媒体查询@media与CSS视口单元vw和vh结合使用,以适应视口的宽高比。这具有更新其他属性(例如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-width和max-height方法非常相似,只是更加灵活。
我最初的问题是如何同时拥有一个固定方面的元素,但又如何将该元素准确地放入指定的容器中,这使其显得有些笨拙。如果您只是希望单个元素保持其长宽比,则容易得多。
我遇到的最好的方法是将元素的高度设置为零,然后使用百分比填充底部将其设置为高度。填充百分比始终与元素的宽度成比例,而不与元素的高度成比例,即使元素的顶部或底部填充也是如此。
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%。如果宽度为160像素,则底部填充,因此高度为90像素-16:9宽高比。
这里的一个小问题对您来说可能不是问题,那就是新对象内部没有自然空间。例如,如果您需要添加一些文本,并且该文本需要采用自己的填充值,则需要在其中添加一个容器并在其中指定属性。
此外,某些较旧的浏览器也不支持vw和vh单位,因此您可能无法接受我的问题的答案,并且可能需要使用更多lo-fi。
为了避免在此处使用额外的标记,您可以使用:: before或:: after添加元素,并将该元素的高度设置为0,并相对于对象自身的宽度和宽度0设置一个填充底部。这将具有相同的效果,但标记较少,并使整个对象区域可用于放置内容,而无需使用容器。
据了解,您要求使用CSS特定解决方案。为了保持长宽比,您需要将高度除以所需的长宽比。 16:9 = 1.777777777778。
为了获得正确的容器高度,您需要将当前宽度除以1.777777777778。由于无法仅用CSS来检查容器的width或除以百分比是CSS,因此如果没有JavaScript,这是不可能的(据我所知)。
我写了一个工作脚本,将保持所需的宽高比。
HTML
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。
请记住,最终用户调整浏览器大小的程度几乎不如开发人员那么大
现在指定了一个新的CSS属性来解决此问题:object-fit。
/wiki/css/properties/object-fit
仍然缺少浏览器支持(/#feat=object-fit)-当前在除Microsoft之外的大多数浏览器中都可以使用,但是在一定的时间内,这恰恰是这个问题所需要的。
Danield的答案很好,但是只有在div填充整个视口时才可以使用它,或者如果知道视口中其他内容的宽度和高度,则可以使用calc来使用。
但是,通过将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;
}
这是在使用scss的jsfiddle中,这使得值的来源更加明显。
根据Daniel的回答,我为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:
Video
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
data-dismiss="modal" type="button">Close
当宽度或高度与视频不成比例时,这将始终显示视频,而没有youtube添加到iframe的黑色部分。笔记:
$sides-adjustment进行了微调,以补偿侧面出现的这些黑色部分中的一小部分;
在高度非常低的设备(<480px)中,标准模式占用了大量空间,因此我决定:
隐藏.modal-footer;
调整.modal-dialog的位置;
减小.modal-header的大小。
经过大量测试,现在这对我来说是完美无缺的。