使用CSS维护div的长宽比

我想创建一个div,它可以随着窗口宽度的变化而改变其宽度/高度。

是否有任何CSS3规则允许高度根据宽度同时保持其长宽比更改?

我知道我可以通过JavaScript做到这一点,但我更喜欢只使用CSS。

根据窗口宽度保持div的长宽比

767152 次浏览

我已经找到了一种使用CSS来做到这一点的方法,但是你必须小心,因为它可能会根据你自己网站的流程而改变。我这样做是为了在我网站的流体宽度部分嵌入具有恒定长宽比的视频。

假设你有一个像这样的嵌入式视频:

<object><param ... /><param ... />...<embed src="..." ...</embed></object>

然后,您可以将所有这些放在带有“视频”类的div中。此视频类可能是您网站中的流体元素,因此它本身没有直接的高度限制,但是当您调整浏览器大小时,它将根据网站的流程改变宽度。这可能是您在保持视频一定长比宽的同时尝试嵌入视频的元素。

为了做到这一点,我在“视频”类div中的嵌入对象之前放置了一个图像。

!!!重要的是图像具有您希望保持的正确长宽比。此外,确保图像的大小至少与您期望视频(或任何您正在维护的A. R.的)根据您的布局获得的最小大小一样大。这将避免百分比调整大小时图像分辨率中的任何潜在问题。例如,如果您想保持3:2的长宽比,不要只使用3px x 2px的图像。它可能在某些情况下有效,但我还没有测试过,避免它可能是个好主意。

您可能已经为网站的流体元素定义了这样的最小宽度。如果没有,这样做是一个好主意,以避免在浏览器窗口太小时切断元素或重叠。最好在某个时候有一个滚动条。网页的最小宽度应该在~600px左右(包括任何固定宽度的列),因为屏幕分辨率不会变小,除非您处理的是手机友好的网站。!!!

我使用一个完全透明的png,但我真的不认为它最终会影响你是否做对了。像这样:

<div class="video"><img class="maintainaspectratio" src="maintainaspectratio.png" /><object><param ... /><param ... />...<embed src="..." ...</embed></object></div>

现在您应该能够添加类似于以下内容的CSS:

div.video { ...; position: relative; }div.video img.maintainaspectratio { width: 100%; }div.video object { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; }div.video embed {width: 100%; height: 100%; }

确保您还删除了对象中的任何显式高度或宽度声明以及通常随复制/粘贴嵌入代码一起提供的嵌入标记。

它的工作方式取决于视频类元素的位置属性和你想要保持一定长宽比的项目。它利用图像在元素中调整大小时保持适当长宽比的方式。它告诉视频类元素中的任何其他元素通过强制其宽度/高度为图像调整的视频类元素的100%来充分利用动态图像提供的空间。

很酷吧?

您可能需要稍微玩弄一下才能让它与您自己的设计配合使用,但这实际上对我来说效果非常好。一般概念就在那里。

只需创建一个包装器<div>,其中包含padding-bottom的百分比值,如下所示:

.demoWrapper {padding: 10px;background: white;box-sizing: border-box;resize: horizontal;border: 1px dashed;overflow: auto;max-width: 100%;height: calc(100vh - 16px);}
div {width: 100%;padding-bottom: 75%;background: gold; /** <-- For the demo **/}
<div class="demoWrapper"><div></div></div>

这将导致<div>的高度等于其容器宽度的75%(4:3长宽比)。

这依赖于以下事实:对于填充:

百分比是相对于生成的框的包含块的宽度计算的[…](来源:w3.org,强调我的)

其他纵横比和100%宽度的填充底值:

aspect ratio  | padding-bottom value--------------|----------------------16:9      |       56.25%4:3       |       75%3:2       |       66.66%8:5       |       62.5%

在div中放置内容:

为了保持div的长宽比并防止其内容拉伸它,您需要添加一个绝对定位的子级并将其拉伸到包装器的边缘:

div.stretchy-wrapper {position: relative;}
div.stretchy-wrapper > div {position: absolute;top: 0; bottom: 0; left: 0; right: 0;}

这里有一个演示和另一个更深入demo

为了补充Web_Designer的回答,<div>的高度(完全由底部填充组成)是含元素宽度的75%。这里有一个很好的总结:http://mattsnider.com/css-using-percent-for-margin-and-padding/。我不知道为什么会这样,但就是这样。

如果您希望您的div的宽度不是100%,则需要另一个包装div来设置宽度:

div.ar-outer{width: 60%; /* container; whatever width you want */margin: 0 auto; /* centered if you like */}div.ar {width:100%; /* 100% of width of container */padding-bottom: 75%; /* 75% of width of container */position:relative;}div.ar-inner {position: absolute;top: 0; bottom: 0; left: 0; right: 0;}

我最近使用了类似于Elliot的图像技巧,允许我使用CSS媒体查询来根据设备分辨率提供不同的徽标文件,但仍然按比例缩放,就像<img>自然做的那样(我将徽标设置为具有正确长宽比的透明. png的背景图像)。但是Web_Designer的解决方案将为我节省超文本传输协议请求。

埃利奥特启发了我这个解决方案-谢谢:

aspectratio.png是一个完全透明的PNG文件,其大小与您的首选纵横比相同,在我的情况下为30x10像素。

超文本标记语言

<div class="eyecatcher"><img src="/img/aspectratio.png"/></div>

CSS3

.eyecatcher img {width: 100%;background-repeat: no-repeat;background-size: 100% 100%;background-image: url(../img/autoresized-picture.jpg);}

请注意:background-size是一个css3功能,可能不适用于您的目标浏览器。您可以检查互操作性(在caniuse.com上)。

基于你的解决方案,我做了一些技巧:

当您使用它时,您的超文本标记语言将仅

<div data-keep-ratio="75%"><div>Main content</div></div>

以这种方式使用它:CSS:

*[data-keep-ratio] {display: block;width: 100%;position: relative;}*[data-keep-ratio] > * {position: absolute;left: 0;right: 0;top: 0;bottom: 0;}

和js(jQuery)

$('*[data-keep-ratio]').each(function(){var ratio = $(this).data('keep-ratio');$(this).css('padding-bottom', ratio);});

有了这个,你只需将attrdata-keep-ratio设置为高度/宽度,就是这样。

像div这样的元素上有几种指定固定长宽比的方法,这里有2个:

1.aspect-ratio CSS属性

div {background: teal;width: 50%;aspect-ratio: 1 / 1;}
<div>aspect-ratio: 1 / 1;</div>

This is the most simple and flexible solution. It directly specifies a fixed width to height (or height to width) aspect ratio for an element. This means you can also specify an aspect ratio according to the elements height.
It doesn't rely on the parent width (like the padding technique) or the viewport size (like the following vw unit technique) it relies on the element's own width or height More info on MDN. That is what make it so powerfull compared to other workarounds.

This is a modern property (2021). All modern browsers support it, see caniuse for precise browser support.

Here are a few examples with different aspect ratios :

.ar-1-1  {aspect-ratio: 1 / 1;}.ar-3-2  {aspect-ratio: 3 / 2;}.ar-4-3  {aspect-ratio: 4 / 3;}.ar-16-9 {aspect-ratio: 16 / 9;}.ar-2-3  {aspect-ratio: 2 / 3;}.ar-3-4  {aspect-ratio: 3 / 4;}.ar-9-16 {aspect-ratio: 9 / 16;}

/** For the demo : **/body {display:flex;flex-wrap:wrap;align-items:flex-start;}div {background: teal;width: 23%;margin:1%;padding:20px 0;box-sizing: border-box;color:#fff;text-align:center;}
<div class="ar-1-1">aspect-ratio: 1 / 1;</div><div class="ar-3-2">aspect-ratio: 3 / 2;</div><div class="ar-4-3">aspect-ratio: 4 / 3;</div><div class="ar-16-9">aspect-ratio: 16 / 9;</div><div class="ar-2-3">aspect-ratio: 2 / 3;</div><div class="ar-3-4">aspect-ratio: 3 / 4;</div><div class="ar-9-16">aspect-ratio: 9 / 16;</div>

2.使用vw单位:

您可以使用vw单位作为元素的宽度和高度。这允许保留元素的长宽比,基于视口宽度

vw:视口宽度的1/100。[MDN]

或者,您也可以使用vh作为视口高度,甚至vmin/vmax使用较小/较大的视口尺寸(讨论这里)。

例子:1:1长宽比

div {width: 20vw;height: 20vw;background: gold;}
<div></div>

For other aspect ratios, you can use the following table to calculate the value for height according to the width of the element :

aspect ratio  |  multiply width by-----------------------------------1:1      |         11:3      |         34:3      |        0.7516:9      |       0.5625

示例:方形div的4x4网格

body {display: flex;flex-wrap: wrap;justify-content: space-between;}div {width: 23vw;height: 23vw;margin: 0.5vw auto;background: gold;}
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>

Here is a Fiddle with this demo and here is a solution to make a responsive grid of squares with verticaly and horizontaly centered content.


Browser support for vh/vw units is IE9+ see canIuse for more info

在w3schools.com中所述,并在接受的答案中有所重申,将值填充为百分比(强调我的):

含元素宽度的百分比指定填充

因此,保持16:9长宽比的响应式DIV的正确示例如下:

css

.parent {position: relative;width: 100%;}.child {position: relative;padding-bottom: calc(100% * 9 / 16);}.child > div {position: absolute;top: 0;bottom: 0;left: 0;right: 0;}

超文本标记语言

<div class="parent"><div class="child"><div>Aspect is kept when resizing</div></div></div>

JSFiddle上的演示

只是一个想法或黑客。

div {background-color: blue;width: 10%;transition: background-color 0.5s, width 0.5s;font-size: 0;}
div:hover {width: 20%;background-color: red;}  
img {width: 100%;height: auto;visibility: hidden;}
<div><!-- use an image with target aspect ratio. sample is a square --><img src="http://i.imgur.com/9OPnZNk.png" /></div>

我是这样做的:

[data-aspect-ratio] {display: block;max-width: 100%;position: relative;}
[data-aspect-ratio]:before {content: '';display: block;}
[data-aspect-ratio] > * {display: block;height: 100%;left: 0;position: absolute;top: 0;width: 100%;}[data-aspect-ratio="3:1"]:before {padding-top: 33.33%;}[data-aspect-ratio="2:1"]:before {padding-top: 50%;}[data-aspect-ratio="16:9"]:before {padding-top: 56.25%;}[data-aspect-ratio="3:2"]:before {padding-top: 66.66%;}[data-aspect-ratio="4:3"]:before {padding-top: 75%;}[data-aspect-ratio="1:1"]:before {padding-top: 100%;}[data-aspect-ratio="3:4"]:before {padding-top: 133.33%;}[data-aspect-ratio="2:3"]:before {padding-top: 150%;}[data-aspect-ratio="9:16"]:before {padding-top: 177.77%;}[data-aspect-ratio="1:2"]:before {padding-top: 200%;}[data-aspect-ratio="1:3"]:before {padding-top: 300%;}

例如:

<div data-aspect-ratio="16:9"><iframe ...></iframe></div>

来源

我使用了一个新的解决方案。

.squares{width: 30vwheight: 30vw

长宽比

.aspect-ratiowidth: 10vwheight: 10vh

但是,这是相对于整个视口的。因此,如果您需要一个占视口宽度30%的div,您可以使用30vw代替,并且由于您知道宽度,您可以使用calc和vw单位在高度中重用它们。

假设你有2个div,外面的div是一个容器,里面的可以是任何你需要保持其比例的元素(img或youtube ifram或其他什么)

html看起来像这样:

<div class='container'><div class='element'></div><!-- end of element --><div><!-- end of container -->

假设你需要保持“元素”的比率比率=>4比1或2比1…

css看起来像这样

.container{position: relative;height: 0padding-bottom : 75% /* for 4 to 3 ratio */ 25% /* for 4 to 1 ratio ..*/  
}
.element{width : 100%;height: 100%;position: absolute;top : 0 ;bottom : 0 ;background : red; /* just for illustration */}

填充在%中指定时,它是基于宽度而不是高度计算的。…所以基本上你的宽度并不重要,它的高度总是根据这个来计算的。这将保持比率。

您可以使用svg。使容器/包装器的位置相对,首先将svg放置为静态定位,然后放置绝对定位的内容(顶部:0;左:0;右:0;底部:0;)

比例为16:9的示例:

image.svg:(可以在src中内联)

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 9" width="16" height="9"/>

css:

.container {position: relative;}.content {position: absolute;top:0; left:0; right:0; bottom:0;}

超文本标记语言:

<div class="container"><img style="width: 100%" src="image.svg" /><div class="content"></div></div>

请注意,内联svg似乎不起作用,但您可以对svg进行urlencode并将其嵌入到img src属性中,如下所示:

<img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%209%22%20width%3D%2216%22%20height%3D%229%22%2F%3E" style="width: 100%;" />

虽然大多数答案都非常酷,但它们中的大多数都需要正确调整图像大小……其他解决方案仅适用于宽度,不关心可用的高度,但有时您也希望将内容适合一定的高度。

我试图将它们结合在一起,以带来一个完全可移植和可调整大小的解决方案……诀窍是使用自动缩放图像,但使用内联svg元素而不是使用预渲染图像或任何形式的第二个HTTP请求……

div.holder{background-color:red;display:inline-block;height:100px;width:400px;}svg, img{background-color:blue;display:block;height:auto;width:auto;max-width:100%;max-height:100%;}.content_sizer{position:relative;display:inline-block;height:100%;}.content{position:absolute;top:0;bottom:0;left:0;right:0;background-color:rgba(155,255,0,0.5);}
<div class="holder"><div class="content_sizer"><svg width=10000 height=5000 /><div class="content"></div></div></div>

请注意,我在SVG的宽度和高度属性中使用了大值,因为它需要大于预期的最大大小,因为它只能收缩。该示例使div的比率为10:5

我已经遇到这个问题很多次了,所以我为它做了一个JS解决方案。这基本上是通过你指定的比率根据元素的宽度调整domElement的高度。你可以按照以下方式使用它:

<div ratio="4x3"></div>

请注意,由于它正在设置元素的高度,因此元素应该是display:blockdisplay:inline-block

https://github.com/JeffreyArts/html-ratio-component

如果你想在纵向或横向视图的视口内安装一个正方形(尽可能大,但不要粘在外面),请在方向portrait/landscape上使用vw/vh切换:

@media (orientation:portrait ) {.square {width :100vw;height:100vw;}}@media (orientation:landscape) {.square {width :100vh;height:100vh;}}

由于@web-tiki已经展示了使用vh/vw的方法,我还需要一种在屏幕中心的方法,这里是9点16分肖像的片段代码。

.container {width: 100vw;height: calc(100vw * 16 / 9);transform: translateY(calc((100vw * 16 / 9 - 100vh) / -2));}

translateY将保持这个中心在屏幕上。calc(100vw * 16 / 9)是9/16的预期高度。(100vw * 16 / 9 - 100vh)是溢出高度,因此,向上拉overflow height/2将保持它在屏幕上的中心。

对于风景,并保持16:9,您显示使用

.container {width: 100vw;height: calc(100vw * 9 / 16);transform: translateY(calc((100vw * 9 / 16 - 100vh) / -2));}

9/16的比例易于更改,无需预定100:56.25100:75。如果想先确保高度,则应切换宽度和高度,例如9:16的肖像比例为height:100vh;width: calc(100vh * 9 / 16)

如果你想适应不同的屏幕尺寸你也可能感兴趣

  • 背景大小覆盖/包含
    • 上面的样式类似于包含,取决于宽:高比率。
  • 对象匹配
    • img/视频标签封面/包含
  • @media (orientation: portrait)/@media (orientation: landscape)
    • 媒体查询portrait/landscape以改变比率。

这是对已接受答案的改进:

  • 使用伪元素而不是包装div
  • 长宽比基于框的宽度而不是其父框的宽度
  • 当内容变得更高时,盒子会垂直伸展

.box {margin-top: 1em;margin-bottom: 1em;background-color: #CCC;}
.fixed-ar::before {content: "";float: left;width: 1px;margin-left: -1px;}.fixed-ar::after {content: "";display: table;clear: both;}
.fixed-ar-16-9::before {padding-top: 56.25%;}.fixed-ar-3-2::before {padding-top: 66.66%;}.fixed-ar-4-3::before {padding-top: 75%;}.fixed-ar-1-1::before {padding-top: 100%;}
.width-50 {display: inline-block;width: 50%;}.width-20 {display: inline-block;width: 20%;}
<div class="box fixed-ar fixed-ar-16-9">16:9 full width</div><hr><div class="box fixed-ar fixed-ar-16-9 width-50">16:9</div><hr><div class="box fixed-ar fixed-ar-16-9 width-20">16:9</div><div class="box fixed-ar fixed-ar-3-2 width-20">3:2</div><div class="box fixed-ar fixed-ar-4-3 width-20">4:3</div><div class="box fixed-ar fixed-ar-1-1 width-20">1:1</div><hr><div class="box fixed-ar fixed-ar-16-9 width-20">16:9</div><div class="box fixed-ar fixed-ar-16-9 width-50">16:9</div>

假设你喜欢保持宽度:100px和高度:50px(即2:1)只需做这个数学:

.pb-2to1 {padding-bottom: calc(50 / 100 * 100%); // i.e., 2:1}

我偶然发现了我认为这个问题的一个智能解决方案,使用<svg>display:grid

display:grid元素允许您使用相同的grid-area与它的两个(或更多)子元素占用相同的空间。
这意味着它们都是流内容、重叠和开箱即用的高的那个决定比例

其中一个将是负责设置比率的<svg>。另一个是实际内容。如果实际内容很短并且永远不会填满整个比率(并且您只是希望它在具有此比率的空间中居中),只需将其居中(请参阅下面的第一个可运行片段)。

<div class="ratio"><svg viewBox="0 0 1 1"></svg><div>I'm square</div></div>
.ratio {display: grid;}.ratio > * {grid-area: 1/1;}

<svg>比率设置为您想要的任何值:

  • <svg viewBox="0 0 4 3"></svg>
  • <svg viewBox="0 0 16 9"></svg>

.ratio {display: grid;}.ratio > * {grid-area: 1/1;}
/* below code NOT needed for setting the ratio* I just wanted to mark it visually* and center contents*/.ratio div {border: 1px solid red;display: flex;align-items: center;justify-content: center;}
<div class="ratio"><svg viewBox="0 0 7 1"></svg><div>Fixed ratio 7:1</div></div>


如果您需要一个解决方案,其中内容元素有更多的内容,您希望将其限制在具有所需比例的可滚动区域中,请在父元素上设置position:relative,在内容上设置position:absolute; height:100%; overflow-y: auto;,允许流内容元素(<svg>)设置大小,从而设置比例。

.ratio {display: grid;position: relative;}.ratio > * {grid-area: 1/1;}

.ratio > div {height: 100%;overflow-y: auto;position: absolute;  
/* the rest is not needed */border: 1px solid red;padding: 0 1rem;}
<div class="ratio"><svg viewBox="0 0 7 2"></svg><div><h1>Fixed ratio 7:2</h1><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. A scelerisque purus semper eget. Sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum. A cras semper auctor neque vitae tempus quam pellentesque nec. Morbi enim nunc faucibus a pellentesque sit amet porttitor. Arcu odio ut sem nulla. Sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque. Cras tincidunt lobortis feugiat vivamus at augue eget. Laoreet sit amet cursus sit amet. Amet nulla facilisi morbi tempus iaculis urna id volutpat. Leo in vitae turpis massa sed elementum tempus egestas sed. Egestas integer eget aliquet nibh. Dolor sit amet consectetur adipiscing elit.
<p>Ut aliquam purus sit amet. Eget magna fermentum iaculis eu non diam phasellus vestibulum. Diam in arcu cursus euismod quis viverra nibh. Nullam vehicula ipsum a arcu cursus vitae congue. Vel orci porta non pulvinar neque laoreet suspendisse. At tellus at urna condimentum mattis pellentesque. Tristique senectus et netus et malesuada. Vel pretium lectus quam id leo in. Interdum velit euismod in pellentesque. Velit euismod in pellentesque massa placerat duis. Vitae suscipit tellus mauris a diam maecenas sed enim.
<p>Mauris a diam maecenas sed enim ut sem. In hendrerit gravida rutrum quisque. Amet dictum sit amet justo donec enim diam. Diam vulputate ut pharetra sit amet aliquam id. Urna porttitor rhoncus dolor purus non enim praesent. Purus in massa tempor nec feugiat nisl pretium. Sagittis vitae et leo duis ut. Facilisi nullam vehicula ipsum a arcu cursus vitae congue mauris. Volutpat odio facilisis mauris sit amet massa vitae tortor condimentum. Aliquam purus sit amet luctus venenatis lectus magna. Sit amet purus gravida quis blandit turpis. Enim eu turpis egestas pretium aenean. Consequat mauris nunc congue nisi. Nunc sed id semper risus in hendrerit gravida rutrum. Ante metus dictum at tempor. Blandit massa enim nec dui nunc mattis enim ut.</div></div>


正如@emjay在下面的评论中指出的那样,比率svg可以放在父元素的伪元素之一中,只要它被正确编码:

.three-squares {display: grid;border: 1px solid red;}
.three-squares > *, .three-squares:before {grid-area: 1/1;}
.three-squares:before {content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 1'%3E%3C/svg%3E");line-height: 0;}
<div class="three-squares"><div>I'm 3:1</div></div>

当在伪元素中使用时,<svg>变成替换元素,默认情况下,它位于可变高度的基线上(Chrome中的4px,Firefox中的3.5px)。基线的高度根据line-height而变化,这就是为什么我们需要在伪元素上设置line-height: 0以获得准确的比率。更多细节这里


我个人更喜欢将<svg>放在标记中的版本,因为我可以有一个类(.ratio)来处理各种比率的容器(而不是为我可能需要的每个单独的比率设置一个类)。

我想分享我的解决方案,我有一个img标签填充一定的长宽比。由于缺乏CMS的支持,我无法使用background,我也不喜欢使用这样的样式标签:<img style="background:url(...)" />。此外,宽度是100%,所以它不需要像某些解决方案那样设置为固定大小。它会响应地缩放!

.wrapper {width: 50%;}
.image-container {position: relative;width: 100%;}
.image-container::before {content: "";display: block;}
.image-container img {position: absolute;top: 0;left: 0;width: 100%;height: 100%;object-fit: cover;}
.ratio-4-3::before {padding-top: 75%;}
.ratio-3-1::before {padding-top: calc(100% / 3);}
.ratio-2-1::before {padding-top: 50%;}
<div class="wrapper"> <!-- Just to make things a bit smaller --><p>Example of an 4:3 aspect ratio, filled by an image with an 1:1 ratio.</p><div class="image-container ratio-4-3"> <!-- Lets go for a 4:3 aspect ratio --><img src="https://placekitten.com/1000/1000/" alt="Kittens!" /></div><p>Just place other block elements around it; it will work just fine.</p></div>

您可以通过使用SVG来实现这一点。

这取决于具体情况,但在某些情况下它真的很有用。例如-您可以设置background-image而不设置固定高度,或者使用它来嵌入YouTube<iframe>16:9position:absolute等比例。

对于3:2比率设置viewBox="0 0 3 2"等。

示例:

div{background-color:red}svg{width:100%;display:block;visibility:hidden}
.demo-1{width:35%}.demo-2{width:20%}
<div class="demo-1"><svg viewBox="0 0 3 2"></svg></div>
<hr>
<div class="demo-2"><svg viewBox="0 0 3 2"></svg></div>

一个简单的方法来保持长宽比,使用画布元素。

尝试调整下面的div的大小以查看它的运行情况。

对我来说,这种方法效果最好,所以我与其他人分享,这样他们也可以从中受益。

.cont {border: 5px solid blue;position: relative;width: 300px;padding: 0;margin: 5px;resize: horizontal;overflow: hidden;}
.ratio {width: 100%;margin: 0;display: block;}
.content {background-color: rgba(255, 0, 0, 0.5);position: absolute;top: 0;left: 0;width: 100%;height: 100%;margin: 0;}
<div class="cont"><canvas class="ratio" width="16" height="9"></canvas><div class="content">I am 16:9</div></div>

也适用于动态高度!

.cont {border: 5px solid blue;position: relative;height: 170px;padding: 0;margin: 5px;resize: vertical;overflow: hidden;display: inline-block; /* so the div doesn't automatically expand to max width */}
.ratio {height: 100%;margin: 0;display: block;}
.content {background-color: rgba(255, 0, 0, 0.5);position: absolute;top: 0;left: 0;width: 100%;height: 100%;margin: 0;}
<div class="cont"><canvas class="ratio" width="16" height="9"></canvas><div class="content">I am 16:9</div></div>

2021更新-CSS相对比率属性

好吧,我们最近收到了在CSS中使用aspect-ratio属性的能力。

https://twitter.com/Una/status/1260980901934137345/photo/1

注意:支持还不是最好的…

注意:支持越来越好!

https://caniuse.com/#search=aspect-ratio

编辑:宽高比现在可用!

https://web.dev/aspect-ratio/

如果您对如何使用它感兴趣,请查看下面的超级简单示例

    .yourClass {aspect-ratio: 4/3;}

这是我的解决方案,用于在具有可选固定边距的div上保持纵向或横向16:9长宽比。

它是宽度/高度和最大宽度/最大高度属性与vw单位的组合。

在此示例中,在悬停时添加了50px的顶部和底部边距。

html {height: 100%;}
body {margin: 0;height: 100%;}
.container {display: flex;justify-content: center;align-items: center;height: 100%;}
.fixedRatio {max-width: 100vw;max-height: calc(9 / 16 * 100vw);width: calc(16 / 9 * 100vh);height: 100vh;  
/* DEBUG */display: flex;justify-content: center;align-items: center;background-color: blue;font-size: 2rem;font-family: 'Arial';color: white;transition: width 0.5s ease-in-out, height 0.5s ease-in-out;}
.fixedRatio:hover {width: calc(16 / 9 * (100vh - 100px));height: calc(100vh - 100px);}
<div class='container'><div class='fixedRatio'>16:9</div></div>

JSFiddle上的演示

2020解决方案-使用网格和伪元素的填充

我找到了一些更新鲜的方法来解决这个问题。这个解决方案是anypadding-bottom方法的后代,但没有任何position: absolute子级,只是使用display: grid;和伪元素。

这里我们有.ratio::before和旧的padding-bottom: XX%grid-area: 1 / 1 / 1 / 1;,这迫使伪元素保持网格中的位置。虽然这里我们有width: 0;来防止主元素溢出(我们在这里冷使用z-index,但这个更短)。

我们的主元素.ratio > *:first-child.ratio::before的位置相同,也就是grid-area: 1 / 1 / 1 / 1;,所以它们都共享相同的网格单元格位置。现在我们可以在div中放置任何内容,伪元素是决定宽度/高度比的元素。更多关于网格区域

.ratio {display: grid;grid-template-columns: 1fr;max-width: 200px; /* just for instance, can be 100% and depends on parent */}
.ratio::before {content: '';width: 0;padding-bottom: calc(100% / (16/9)); /* here you can place any ratio */grid-area: 1 / 1 / 1 / 1;}
.ratio>*:first-child {grid-area: 1 / 1 / 1 / 1; /* the same as ::before */background: rgba(0, 0, 0, 0.1); /* just for instance */}
<div class="ratio"><div>16/9</div></div>


尽管您可以使用CSS val并使用style属性将您的比率放置在超文本标记语言中。也适用于display: inline-grid

.ratio {display: inline-grid;grid-template-columns: 1fr;width: 200px; /* just for instance, can be 100% and depends on parent */margin-right: 10px; /* just for instance */}
.ratio::before {content: '';width: 0;padding-bottom: calc(100% / (var(--r))); /* here you can place any ratio */grid-area: 1 / 1 / 1 / 1;}
.ratio>*:first-child {grid-area: 1 / 1 / 1 / 1; /* the same as ::before */background: rgba(0, 0, 0, 0.1); /* just for instance */}
<div class="ratio" style="--r: 4/3;"><div>4/3</div></div>
<div class="ratio" style="--r: 16/9;"><div>16/9</div></div>

我刚刚创建了一个2:1的div,它调整大小以占据整个宽度,但如果它会导致顶部或底部超过,则会缩小宽度。但请注意,这只适用于窗口的大小,而不是父窗口的大小。

#scene {position: relative;top: 50vh;left: 50vw;width: 100vw;height: 50vw;max-height: 100vh;max-width: calc(100vh * 2);transform: translate(-50%, -50%);}

我相信你可以计算出正确的%'s用于4:3而不是2:1

新Chrome88和很快在其他浏览器跟随是新的CSS#0属性。

纵横比CSS属性设置框的首选长宽比,这将用于计算自动大小和其他一些布局函数。

CSS技巧文章

更多信息

div {background: rebeccapurple;height:100px;margin:1em auto;}
.square {aspect-ratio: 1 / 1;}
<div class="square">  
</div>

我想分享这个,因为我花了几天令人沮丧的时间才找到一个适合我的解决方案。我正在使用这些填充技术(上面提到的使用填充和绝对定位的一些变体)来实现网格/柔性布局中类似按钮的元素的1:1长宽比。布局设置为100vh高,以便它始终显示为单个非滚动页面。

填充技术确实工作得很好,但它很容易破坏您的网格布局并导致井喷/讨厌的滚动条。那些说绝对div不能影响布局的人在这种情况下是错误的,因为父级同时增长高度和/或宽度,即使子级不直接,父级也可以弄乱您的布局。

通常这不是一个问题,但在使用网格时需要注意。网格是一个2D布局,它可以考虑两个轴上的大小和布局。我仍在试图理解这一点的确切性质,但到目前为止,如果你在一个受到两个轴上fr单位约束的网格区域内使用这种技术,你几乎肯定会在宽高比项增长或以其他方式改变布局时经历井喷(显示:没有用css切换和交换网格区域也是导致井喷的布局变化问题)。

在我的情况下,我限制了不需要的列的高度。将其更改为“自动”而不是“1fr”,使我所有其他布局保持不变,防止井喷,同时仍然让我保留我漂亮的方形按钮!

我不知道这是否是这里每个人沮丧的根源,但这是一个容易犯的错误,即使使用开发工具也不会让你准确地了解井喷在许多情况下来自哪里,因为它不是一个单独的元素吹出来的情况,而是网格布局扩大了自己,以保持这些fr单位在垂直和水平上的准确性。

2022解决方案-使用aspect-ratio CSS属性

<div class='demo'></div>
.demo {background: black;width: 500px;aspect-ratio: 4/3;}

更新:此解决方案现在支持所有常绿浏览器

我想只是使用rem或em应该解决固定比率的问题,但不会像vwvh那样硬绑定到屏幕上,也不会像%那样痛苦地使用flexbox。好吧,没有一个答案对我有效,在我的情况下,这让我感到困扰:

<div class="container"><div></div></div>
.container {height: 100vh;width: 100vw;}.container div {height: 4em;width: 3em;}

或者使用rem。但无论如何,他们中的任何一个都应该做到。
rem使用默认的font-size值,因为em使用最接近的font-size。

感谢大家的贡献,我将在这里添加我的解决方案,我主要通过重复已接受的答案来生成。我喜欢这种方法的主要原因是没有不必要的DOM,因为我使用:before来做填充的脏工作。

@card-standard-line-height: 21px;@card-standard-title-line-height: 22.5px;@16to9percentage: 56.25%;
.overflow {background-color: inherit;/* stylelint-disable property-no-unknown */box-orient: vertical;-moz-box-orient: vertical;-webkit-box-orient: vertical;/* stylelint-enable */color: inherit;display: box;display: -webkit-box;display: -moz-box;max-width: 100%;overflow: hidden;position: relative;text-overflow: -o-ellipsis-lastline;text-overflow: ellipsis;}
* {box-sizing: border-box;}
body {padding: 2rem;}
.card {color: #fff;height: auto;max-width: 100%;min-width: unset;position: relative;  
h2 {font: 18px / 22.5px bold;}  
p {font: 14px / 21px normal;}
&-16to9 {.badge {color: white;display:flex;background-color: red;justify-content: baseline;padding: 16px 32px 12px 16px;position: absolute;right: 0;top: 16px;z-index: 2;span {font: 14px / 14px bold;}}// look at this https://css-tricks.com/aspect-ratio-boxes/.card {&_description {max-height: @card-standard-line-height * 1;// Number of allowable lines in layout-webkit-line-clamp: 1;}
&_image,&_info {bottom: 0;height: 100%;max-height: 100%;min-height: 100%;left: 0;position: absolute;right: 0;top: 0;z-index: 0;}
&_info {display: flex;flex-direction: column;justify-content: flex-end;padding: 24px;z-index: 2;}
&_title {max-height: @card-standard-title-line-height * 2;// Number of allowable lines in layout-webkit-line-clamp: 2;}}
&:after,&:before {content: "";display: block;}
&:after {background: rgba(0, 0, 0, 0);background: linear-gradient(0deg, rgba(0, 0, 0, 1) 16%, rgba(0, 0, 0, 0) 100%);bottom: 0;height: 100%;left: 0;position: absolute;right: 0;top: 0;z-index: 1;}
&:before {padding-bottom: @16to9percentage;}}}

https://codepen.io/augur/pen/GRNGLZv?editors=0100

CSS对此有一个新属性:aspect-ratio

https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio

@supports (aspect-ratio: 1 / 1) {div {aspect-ratio: 16 / 9;background-color: orange;}}
<div style="width: 200px"></div><hr /><div style="width: 400px"></div><hr /><div style="height: 50px"></div><hr /><div style="height: 10px"></div>

Chrome和Edge从V88开始完全支持它,Firefox从V81开始支持它在旗帜后面(在关于:配置中设置layout.css.aspect-ratio.enabledtrue)。

有关兼容性信息,请检查https://caniuse.com/mdn-css_properties_aspect-ratio

container {height: 100vh;width: 100vw;}.container div {height: 4em;width: 3em;}

实际上,高票数的答案是一个非常好的解决方案,但有一个新的CSS功能,名称是#0

它可以像这样使用:

.someClass {width: 100%;aspect-ratio: 4/3;}

它会自动确定其高度,但请参阅兼容性表:

输入图片描述

如果浏览器支持对您的项目很重要,请不要使用它。使用padding-bottom技术。

新的宽高比标签会很棒,但它弄乱了我的div的定位。填充包装器div的传统解决方案有效,但仅根据父级或视口的宽度调整大小,这使其当高度是限制因素时就有问题了

我发现min()函数非常有用,并像这样调整了传统方法:

body{background-image: linear-gradient(to top right, #FFE6B5, #B3CEBF);padding: 0;margin: 0 auto;overflow-y: hidden; /* this is to avoid scrolling when the height of the viewport is less than what the aspect ratio requires */}
.wrapper {position: relative;width: 100vw;max-height: 100vh;}.sixteen-by-nine.aspect-ratio {padding-bottom: 56.25% /* 9:16 ratio */}.content {position: absolute;top: 0; bottom: 0; left: 0; right: 0;background-color: green}
.centered {position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);height: 100%;width: min(177.8vh, 100%); /* this always keeps a 16:9 ratio within the viewport */font-size: min(3vh,1.7vw); /* if you are also interested in scaling the font size */background-color: blue}
<body><div class="wrapper"><div class="sixteen-by-nine aspect-ratio"></div><div class="content" ><div class="centered"><!-- stuff goes here --></div></div></div></body>

我们是这样解决的:

.square {width: 100%;max-height: 100%;aspect-ratio: 1;background: red;position: relative;margin: auto;top: 50%;transform: translateY(-50%);}

https://jsfiddle.net/r1jL3oqa/1/

在Angular上,我添加了处理长宽比的指令。

import { AfterViewInit, Directive, ElementRef, Input, Renderer2 } from"@angular/core";import { debounceTime, fromEvent, Subject, takeUntil } from "rxjs"; 
// Auto sets the height of element based on width. Also supports window resize@Directive({selector: '[aspectRatio]'})export class AspectRatioDirective implements AfterViewInit {@Input() aspectRatio?: number; // example 9/16
private readonly onDestroy$ = new Subject<void>();
constructor(private element: ElementRef, private renderer: Renderer2) {}
public ngAfterViewInit(): void {this.setDimensions();this.initResizeListeners();}
public ngOnDestroy(): void {this.onDestroy$.next();this.onDestroy$.complete();}
private setDimensions(): void {if (!this.aspectRatio) { return; }const width = this.element.nativeElement.clientWidth;this.renderer.setStyle(this.element.nativeElement, 'height', `${width * this.aspectRatio}px`);}
private initResizeListeners(): void {fromEvent(window, 'resize').pipe(debounceTime(100), takeUntil(this.onDestroy$)).subscribe(() => this.setDimensions());}}