CSS - 为什么百分比高度不起作用?

286

为什么使用百分比作为height的值无效,而作为width的值有效呢?

例如

<div id="working"></div>
<div id="not-working"></div>
#working{
    width:80%;
    height:140px;
    background:orange;
}
#not-working{
    width:80%;
    height:30%;
    background:green;
}

#working的宽度最终是视口的80%,但#not-working的高度最终为0。


4
虽然我不是专家,但我想这可能与假设您在网页上将进行垂直滚动而非水平滚动有关... - user684934
2
这是CSS height属性与百分比值的简单明了的解释:https://dev59.com/51wZ5IYBdhLWcg3wM97Z#31728799 - Michael Benjamin
6个回答

427

块级元素的高度默认等于该块内容的高度。 因此,考虑到以下示例:

<div id="outer">
    <div id="inner">
        <p>Where is pancakes house?</p>
    </div>
</div>

#inner会增长到足以包含段落的高度,#outer会增长到足以包含#inner的高度。

当你将高度或宽度指定为百分比时,那是相对于元素的父级元素的百分比。在宽度的情况下,除非另有规定,所有块级元素都与其父级一样宽,直到回溯到<html>; 因此,块级元素的宽度独立于其内容,并且说 width: 50% 会产生一个明确定义的像素数量。

然而,块级元素的高度取决于其内容,除非您指定特定的高度。因此,在高度方面,父级和子级之间存在反馈,说 height: 50% 不会产生明确定义的值,除非您通过给父级元素指定特定的高度来打破反馈循环。


55
宽度和高度的区别在于,宽度默认由其父元素的值定义,而高度由其内容的“值”定义。父元素的值与内容的值对比。 - arthur
7
那么是否没有一种方式能够使高度具有响应性呢?比如说,您创建了一行带有 CSS 背景颜色的彩色正方形,并且希望这些正方形能够随着屏幕大小进行调整。jjsFiddle - MilkyTech
2
@ChrisM - 根据您想要使用它的方式,只需将相等的填充设置为所需框的一半宽度:http://jsfiddle.net/en9xyv30/1/ 如果您想在框中放置内容,可能需要绝对定位--只需将顶部、右侧、底部和左侧全部设置为0(或其他非0值,如果您想要一些填充),则内容将随着框的大小调整而调整。 - Joshua Coady
13
你也可以使用vw单位。vw是以视口宽度为百分比的单位。因此,类似height: 10vw; width: 10vw;这样的代码会按屏幕宽度进行缩放,并且保持正方形。请参考http://caniuse.com/#feat=viewport-units了解浏览器兼容性。 - Joshua Coady
5
使用vw单位代替百分比要小心,因为如果您决定将元素放入另一个容器中,这将使您的生活非常困难。 - Tomasz Mularczyk
显示剩余4条评论

175

height属性的百分比值有些复杂,而widthheight属性实际上行为不同。让我带您了解一下规范。

height属性:

让我们看一下CSS Snapshot 2010 规范对 height 的说明

百分比是相对于生成框的包含块的高度计算的。如果未明确指定包含块的高度(即它取决于内容高度),并且此元素没有绝对定位,则该值计算为“auto”。根元素上的百分比高度相对于初始包含块。注意:对于其包含块基于块级元素的绝对定位元素,百分比是相对于该元素的内边距框的高度来计算的。

好的,让我们一步一步来拆解:

百分比是相对于生成框的包含块的高度计算的。

什么是包含块?虽然有点复杂,但对于默认 static 位置的普通元素来说,它是:

最近的块级容器祖先盒子

或者用英语说,就是它的父级盒子。(了解对于 fixedabsolute 位置分别是什么也很值得,但为了让答案简明扼要,我忽略了这些。)

因此,看看这两个例子:

<div   id="a"  style="width: 100px; height: 200px; background-color: orange">
  <div id="aa" style="width: 100px; height: 50%;   background-color: blue"></div>
</div>

<div   id="b"  style="width: 100px;              background-color: orange">
  <div id="bb" style="width: 100px; height: 50%; background-color: blue"></div>
</div>

在这个例子中,#aa 的包含块是 #a#b#bb 同理。到目前为止,一切都很好。 height 属性规范的下一句话是我在答案开头提到的复杂之处:
如果没有明确指定包含块的高度(即它取决于内容高度),并且该元素没有绝对定位,则该值计算为“auto”。
啊哈!包含块的高度是否已经明确指定很重要!
- 在 #aa 的情况下,height:200px 的50%为100px - 但是,在 #bb 的情况下,height:auto 的50%是 auto,因为没有内容可以扩展到 auto,所以为0px
正如规范所说,包含块是否已经绝对定位也很重要,但让我们继续看 width 属性。

那么对于width,它的工作方式是否相同呢?让我们看一下规范

百分比是相对于生成框所在块的宽度计算的。

看看这些熟悉的例子,从之前的例子中调整而来,以变化width而不是height

<div   id="c"  style="width: 200px; height: 100px; background-color: orange">
  <div id="cc" style="width: 50%;   height: 100px; background-color: blue"></div>
</div>

<div   id="d"  style="            height: 100px; background-color: orange">
  <div id="dd" style="width: 50%; height: 100px; background-color: blue"></div>
</div>

  • #cc的情况下,width:200px的50%是100px。
  • width:auto的50%取决于width:auto最终成为多少的50%,与height不同,没有特殊规则来处理这种情况。

现在,这里有一个棘手的问题:auto的含义取决于它是否已为widthheight指定!对于height,它只是表示适合内容所需的高度*,但对于widthauto实际上更加复杂。您可以从代码片段中看到,在这种情况下,它最终成为了视口的宽度。

规范对于宽度的自动值有何说明

宽度取决于其他属性的值。请参见以下各节。

嘿,那不是很有帮助。为了节省您的麻烦,我已经为您找到了与我们用例相关的部分,标题为“计算宽度和边距”,副标题为{{link1:“普通流中的块级非替换元素”}}:

其他属性的使用值之间必须满足以下约束条件:

'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = 包含块的宽度

好的,所以width加上相关的边距、边框和内边距必须总和等于包含块的宽度(而不是像height一样处理后代)。只有一个规范句子:

如果将'width'设置为'auto',则任何其他'auto'值都变为'0',并且'width'遵循由此产生的等式。

啊哈!所以在这种情况下,width:auto的50%是视口的50%。希望现在一切都讲得很清楚!


脚注

* 至少在这种情况下是有意义的。spec 好了,现在一切只是有点讲得通。


7
如果可能的话,我会给这个"+10"。 - Henry
非常好的解释 - 谢谢!我在id='b'的框中添加了一些字母,以便它实际上具有高度。但是,id='bb'的框的高度为0 - 为什么?它不应该是id='b'框内容高度的一半吗? - Adam
@Adam 对于高度,#bb的高度是auto的50%,也就是和auto一样,而且由于#bb里面没有任何内容,所以它的高度相当于0。 #b这个父元素最终具有高度并不改变它的高度仍然是auto这个事实。 - Flimm
如果“width”设置为“auto”,则任何其他“auto”值都变为“0”,并且“width”遵循由此产生的等式。我对这句话也感到困惑,您需要澄清吗? - carinlynchin
1
@Flimm 你能解释一下为什么在 flex 子项中设置子元素的 % 高度即使没有明确规定父元素的高度也能生效吗?我的意思是,当您有一个 flex 容器、flex 子项和 flex 子项内部的 div 时,当您在该内部 div 上设置百分比高度时,它会继承自 flex 子项的高度(无论 flex 子项的高度是否被“设置”为 auto)。 - max
显示剩余5条评论

19

我认为你只需要给它一个父容器,即使该容器的高度以百分比定义也可以。 这种方法似乎完全可行:JSFiddle

html, body { 
    margin: 0; 
    padding: 0; 
    width: 100%; 
    height: 100%;
}
.wrapper { 
    width: 100%; 
    height: 100%; 
}
.container { 
    width: 100%; 
    height: 50%; 
}

如果您有一个页眉,或者当您调整窗口大小时,%可能会被计算错误,您也可以使用此方法来减去像素。height: calc(100% - 100px); 对于较旧的浏览器,请使用以下代码: height: -o-calc(100% - 100px); /* opera / height: -webkit-calc(100% - 100px); / google, safari / height: -moz-calc(100% - 100px); / firefox */ - Paintoshi

8
另一种选择是为 div 添加样式。
<div style="position: absolute; height:somePercentage%; overflow:auto(or other overflow value)">
 //to be scrolled 
</div>

这意味着元素的定位相对于最近的已定位祖先元素。

谢谢,这对我很有用 :) - Kishore Kumar
位置:绝对;适合我。 - Jeson Martajaya

8

您需要为其提供一个高度的容器。宽度使用视口作为默认宽度


3
正确,但是请查看 @mu 的答案以了解原因。 - nchpmn

3

如果没有内容,高度就没有价值可以计算百分比。然而,如果没有指定父元素,宽度将从DOM中获取百分比。(使用您的示例) 将第二个div放在第一个div内部,会呈现出以下结果...

<div id="working">
  <div id="not-working"></div>
</div>

第二个 div 的高度应该是第一个 div 高度的 30%。

这促使我去弄清楚它。我忘记了当你构建你的React元素时,你必须将整个返回值封装在一个单一的div中。所以我有我的#app div,然后是一个没有id的div,然后是我试图调整大小的3个div...我只是在中间的div上放了一个id,并在那里进行了绝对定位的样式设置,bingo!非常感谢大家! :) - Jon Sansoucie

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