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


122

我有一个可以放在一起的网站,其纵横比大约为 16:9等于风景,例如视频。

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

例如:

  1. 高而薄的页面将使内容伸展整个宽度,同时保持成比例的高度。
  2. 短而宽的页面将使内容延伸到整个高度,并具有成比例的宽度。

我一直在研究两种方法:

  1. 使用具有正确长宽比的图像来扩展容器div,但是我无法在主要浏览器中以相同的方式显示图像。
  2. 设置成比例的底部填充,但这仅相对于宽度有效,而忽略高度。它的宽度不断增大,并显示垂直滚动条。

我知道您可以使用JS轻松完成此操作,但是我想要一个纯CSS解决方案。

有任何想法吗?


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

Answers:


279

使用新的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 */
}

如果要使用最大90%的视口宽度和高度,请执行以下操作:FIDDLE

另外,浏览器支持也相当不错:IE9 +,FF,Chrome,Safari- caniuse


1
这是一个非常好的清洁解决方案。理想情况下,我可以在浏览器支持方面做得更好。我猜在较旧的浏览器上,您只有一个最小的宽度/高度并将其设置为该值-如果它具有滚动条,那么就可以了
Henry Gibson

8
嗯,谢谢您为我节省了2天的工作时间和无数用户的挫败感。如果可以的话,可以超过1000。
Schoening

2
你救了我这么多时间。非常感谢。
Dylan Gattey 2014年

1
不幸的是,最近的iOS版本不支持,或有破损实现视台(vhvwvminvmax)。但是,有一种解决方法,它使用媒体查询来定位iOS设备。
蒂姆(Tim)

1
我爱你。很好的解决方案!
古特堡2014年

20

只需Danield在LESS mixin中重新编写答案即可,以供进一步使用:

// 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;
}

11

CSS媒体查询 @mediaCSS视口单位 一起使用,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-widthand max-height 方法非常相似,只是更加灵活。


7

我最初的问题是如何同时拥有一个固定方面的元素,但又如何将该元素准确地放入指定的容器中,这使它显得有些笨拙。如果您只希望单个元素保持其长宽比,则容易得多。

我遇到的最好的方法是将元素的高度设置为零,然后使用百分比填充底部将其设置为高度。填充百分比始终与元素的宽度成比例,而不与元素的高度成比例,即使元素的顶部或底部填充也是如此。

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宽度设置一个填充底部。这将具有相同的效果,但标记较少,并使整个对象区域可用于放置内容,而无需使用容器。
亨利·吉布森

6

据了解,您要求提供CSS特定的解决方案。要保持长宽比,您需要将高度除以所需的长宽比。16:9 = 1.777777777778。

为了获得正确的容器高度,您需要将当前宽度除以1.777777777778。由于您无法使用来检查width容器的正好CSS或除以is 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。
亨利·吉布森

1
@Henry Gibson该脚本已在Chrome,FF,IE,Opera和Safari中经过测试。所有这些都工作迅速,即使在旧版浏览器中也可靠。每个浏览器都会触发自己的事件。window.onresize浏览器更改大小后立即触发。
MCSharp 2013年

请记住,最终用户调整浏览器大小的幅度不如开发人员那么大
Simon_Weaver


1

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;
}
<main>
  <section>
    <div></div>
  </section>
</main>

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


0

根据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:

<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

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.