通过CSS设置元素宽度基于高度的方法

36

我有一组元素,要求它们的最小宽度等于它们的高度,但高度没有明确设置。目前我可以通过使用jQuery设置CSS min-width属性来实现:

$(document).ready
(
    function()
    {
        $('.myClass').each
         (
             function() {$(this).css('min-width', $(this).css('height'));}
         );
    }
);  

这种行为是否可以直接在CSS中指定?

这是一个jsfiddle演示,展示了我想要实现的效果:http://jsfiddle.net/p8PeW/


1
这个问题是关于根据高度设置宽度。如果你需要根据宽度设置高度,请查看Maintain the aspect ratio of a div with CSS - John Mellor
1
@verdesmarald,你能否改变接受的答案呢? - Kerwin Sneijders
1
新的正确简洁答案是aspect-ratio 宽度数字 / 高度数字;。它可以双向工作。有关演示,请参见https://dev59.com/A2025IYBdhLWcg3wNTEV#68073761。 - LuckyLuke Skywalker
10个回答

89

实际上,这可以在没有JS的情况下实现!

关键是利用<img>标签,它是一个替换元素,因此如果你只设置高度,宽度将自动设置以保留图像的固有纵横比。

因此,您可以执行以下操作:

<style>
  .container {
    position: relative;
    display: inline-block; /* shrink wrap */
    height: 50vh; /* arbitrary input height; adjust this */
  }
  .container > img {
    height: 100%; /* make the img's width 100% of the height of .container */
  }
  .contents {
    /* match size of .container, without influencing it */
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
  }
</style>

<div class="container">
  <!-- transparent image with 1:1 intrinsic aspect ratio -->
  <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
  <div class="contents">
    Put contents here.
  </div>
</div>

如果您想让.contents具有4:3的宽高比,那么您应该将img的高度设置为133%,这样img和因此.contents的宽度将是.container高度的133%。

1:4宽高比的在线演示:https://jsbin.com/juduheq/edit(带有额外的代码注释)。

另一个在线演示,其中容器的高度由同级元素中的文本数量确定:https://jsbin.com/koyuxuh/edit

如果您想知道,img数据URI是用于一个1x1像素透明gif图像。如果图像不具有1:1的宽高比,则必须相应地调整所设置的高度值。您还可以使用<canvas><svg>元素代替<img>(感谢Simo)。

如果您想根据宽度设置元素高度,可以在Maintain the aspect ratio of a div with CSS中找到一个更简单的技巧。


3
这是一个很棒的解决方案……这应该就是答案!感谢 @John。 - haxxxton
2
有人能通过例如 .container:first-child::before { ... } 让它工作吗?只使用 CSS 的解决方案可能非常有帮助! - Matmarbon
3
这种方法可以通过使用<canvas>更加方便,因为它默认是透明的,您可以任意设置宽度/高度来创建所需纵横比的图像,而无需在其上进行绘制。请注意,您可能需要在画布或图像上设置padding:0margin:0,否则它可能会占用更多的空间。 - Simo Kinnunen
1
如果容器没有绝对值而是百分比,这似乎不起作用?将 pastebin 修改为将 20% 设置为容器的高度也无效。 - Sébastien Tromp
1
似乎你们都是因为这个答案很受欢迎而盲目点赞,而没有完全评估问题。 OP明确表示他不知道正在尝试使宽度等于高度的容器的高度,这根本不符合这个答案。 John在他的JS Bin示例中使用了固定高度为400像素。删除它,示例就会失效。这就是为什么这不是被接受的答案的原因。 - Gust van de Wal
显示剩余8条评论

19

现在新的aspect-ratio属性可以轻松实现这一点,并且在以下两种情况下均可工作:

  1. 基于宽度的高度
  2. 基于高度的宽度

我们只需设置比例和宽度或高度之一即可:

.box {
  height:80vh;
  background:red;
  aspect-ratio:9/6;
}

.box1 {
  width:50vw;
  background:green;
  aspect-ratio:9/6;
}
<div class="box">

</div>

<div class="box1">

</div>


遗憾的是,目前还无法在IOS(14...)上运行,但希望能在v15(?)上实现。 - A Haworth

2

没有图像,只有使用100%可变宽高比的纯HTML + CSS。诀窍是使用内联SVG,其提供所需的宽高比。

.width-adjusting-to-height {
  display: inline-block;
  height: 200px; /* change to whatever you like */
  background: tomato;
  position: relative;
}

.width-adjusting-to-height > svg {
  height: 100%;
}

.width-adjusting-to-height .content {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
<div class="width-adjusting-to-height">
  <!-- the viewbox will provide the desired aspect ratio -->
  <svg viewBox="0 0 50 100"></svg>
  <div class="content">content goes here</div>
</div>


你不需要 xmlns 链接,对吗? - Le Mot Juiced
当高度设置为百分比时,我无法使其正常工作,这也是 OP 所问的。高度不能显式设置,否则它不是问题的解决方案。 - Le Mot Juiced
这个解决方案也适用于相对高度。一般来说,当使用相对单位时,请确保相应的父元素已正确设置其高度。 - Thomas
请看这个相对高度的示例 https://codepen.io/wilmaknattern/pen/LYbqxjW - Thomas
它确实可以在Edge、Chrome和Firefox中缩放。在Safari中,它最初可以缩放,但当视口改变时不会重新缩放,这似乎更像是Safari中的问题而不是解决方案中的问题。 - Thomas
显示剩余2条评论

0

对于Safari用户来说,有个坏消息:从2021年3月13日起,此页面上的解决方案将无法使用,至少在Mac OS Big Sur中是如此。

由于某种原因,Safari在这方面出现了一些问题。

有一个权宜之计,虽然不是所有情况下都可行,但在某些情况下,它甚至比其他方法更容易实现:

  • 使用 vh 单位来设置宽度:

    .container {
        height: 40vh;
        width: 20vh;
    }
    

非常简单,而且宽度始终与高度保持比例。

  • 为了更灵活,有些情况下甚至可以使用百分比:

    .container {
       height: 40%;
       width: 20vh;
    }
    

这将使容器与其父容器匹配40%,并始终保持宽度与高度成比例。但是,仅当父元素的高度本身始终与整个视口的大小保持一致的比例时才有效。

因此,这不是一个通用的解决方案,但在许多情况下可能是最简单的方法。


0

还有另一个非常简单的CSS解决方案,但仅适用于OP在他的jsfiddle中提出的确切情况:

label {
  background-color: Black;
  color: White;
  padding: 1px;
  font-family: sans-serif;
  text-align: center;
  vertical-align: middle;
  display: inline-block;
  min-width: 1em; /* set width to the glyphs height */
}
<label>A</label><br/>
<label>B</label><br/>
<label>C</label><br/>
<label>D</label><br/>
<label>E</label><br/>
<label>F</label><br/>
<label>R6a</label>


0

我有同样的需求,我使用了@John Melor的解决方案,并取得了良好的成功...直到它在Firefox上不起作用。我尝试通过在这里测试不同的jsbin代码示例来复制我的特定问题,但没有运气。可能是基于我的实际DOM的高度特定的浏览器错误。如果有人有那个问题的jsbin,请分享!

我尝试了许多组合,所有组合都失败了:容器不会扩展到图像宽度。 Firefox声明图像具有其高度的宽度,但无论我尝试什么,父级都是1px宽。

对于那些发现自己处于这种情况的人,我使用了一个局部于图像元素的js bugfix。如果容器的高度未像最初的OP问题中那样指定,那对您也可能有用。

在JSX/ES6中:

const TRANSPARENT_PIXEL = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
const setWidthToHeight = e => { e.target.style.width = e.target.height }
const force1x1Ratio = <img src={TRANSPARENT_PIXEL} onLoad={setWidthToHeight} />

使用普通的 HTML

<img 
    src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" 
    onLoad="javascript:function(e) { e.target.style.width = e.target.height + 'px' }" />

-1

如果你想制作正方形,你需要考虑两种情况(W > HW < H):

$('label').each(function() {
    if ($(this).height() > $(this).width()) {
        $(this).css('min-width', $(this).height());
    } else {
        $(this).css('min-height', $(this).width());
    }
});

1
不,我很高兴元素比高宽,只是不要比宽高。 - verdesmarald

-1

来自W3C Box Model 关于padding的说明:

即使对于'padding-top'和'padding-bottom',百分比是相对于生成的盒子所在块的宽度计算的。如果包含块的宽度取决于此元素,则在CSS 2.1中结果布局未定义。

因此,您可以仅使用CSS进行设置。请参见this example,该示例来自this blog post,介绍了同样有趣的另一个主题。创建比例框的技巧是使用类似于

element::before {
  content: '';
  display: block;
  padding-bottom: 100%;
}

5
你的回答基于宽度设置了高度,这与提问者所要求的相反(并且更加容易)。已经有很好的解决方案在https://dev59.com/u3I_5IYBdhLWcg3wK_zE。 - John Mellor

-1
使用 flexboxpadding。使用 @media 查询来确定视窗的最小纵横比,然后做出相应调整。
具有 16:9 纵横比的简化解决方案。

html,body {
  height: 100%;
}

.parent {
  height: 100%;
  width: 100%;
  border-style: solid;
  border-width: 2px;
  border-color: black;
  /* to center */
  display: flex;
  align-items: center;
  justify-content: center;
}

.child {
  width: 100%;
  /* 16:9 aspect ratio = 9 / 16 = 0.5625 = padding-bottom*/
  padding-bottom: 56.25%;
  background: blue;
}

@media (min-aspect-ratio: 16/9) {
  .parent>img {
    height: 100%;
    /* make the img's width 100% of the height of .container */
  }
  .child {
    height: 100%;
    /*16:9 aspect ratio = 9 / 16 = 177.77 = width*/
    width: 177.77vh;
    padding: 0;
    margin: 0px;
    background: red;
  }
}
<div class="parent">
  <div class="child">
    content that is not images...
  </div>
</div>

這裡有一個fiddle


-10

我不认为这可以在没有 JS 的情况下完成,但也许有人能证明我错了?

CSS 不允许使用动态变量,所以如果高度直到页面加载后才设置,我不确定如何实现。


9
请见下方Josh的回答。这是可行的。 - F Lekschas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接