为什么 CSS 中的边距/填充百分比总是根据宽度计算?

如果你观察 CSS 盒模型规范,你会发现以下几点:

[边距]百分比是根据生成框的包含块的 宽度计算的。如果包含块的宽度取决于这个元素,那么最终的布局在 CSS 2.1中是未定义的。(强调我的)

的确如此。但是 为什么呢?到底是什么迫使人们把它设计成这样?很容易想到你想要的场景,例如某个东西总是从页面顶部下降25% ,但是很难想出任何理由为什么你想要垂直填充相对于父页面的水平大小。

下面是我所指的这种现象的一个例子:

<div style="border: 1px solid red; margin: 0; padding: 0; width: 200px; height: 800px;">
This div is 200x800.
<div style="border: 1px solid blue; margin: 10% 0 0 10%;">
This div has top-margin of 10% and left-margin of 10% with respect to its parent.
</div>
</div>

Http://jsfiddle.net/8jdyd/

77276 次浏览

把我的评论转换成答案,因为这符合逻辑。然而,请注意,这是毫无根据的猜测。为什么规范以这种方式编写的实际原因在技术上仍然是未知的。

元素的高度由 如果一个元素有填充顶部: 10% (相对于父 高度) ,这将影响父类的高度 子级的高度取决于父级的高度,而 父母的身高取决于子女的身高 要么有不准确的高度,或无限循环。当然,这只 影响到偏移父级 = = 父级的情况,但仍然是 难以解决的奇怪案件。

更新: 最后几句话可能不完全准确。Leaf 元素的高度(没有子元素的子元素)会影响其上所有元素的高度,因此这会影响许多不同的情况。

如果“ n%”边距(和填充)是边距-顶部/边距-右边/边距-底部/边距-左边的 一样,那么所有四个边距必须相对于同一个基数。如果顶部/底部使用的底部不同于左/右’,那么“ n%”边距(和填充)在所有四个边上的意思就不一样了。

(还要注意的是,相对于 宽度的上/下边距允许一种奇怪的 CSS 技巧,它允许你指定一个长宽比不变的盒子... ... 即使盒子被重新缩放了。)

在玩过这个 JSFiddle(Chrome 46.0.2490.86)并参考了 这篇文章(中文)之后,我为@ChuckKollar 的回答投了赞成票。


反对 无限计算猜想的一个主要原因是: 使用 width面临同样的 无限计算问题。

看看这个 JSFiddleparent显示器是 inline-block,它可以定义边距/填充。child有边际值 20%。如果我们遵循 无限计算猜想:

  1. child的宽度取决于 parent
  2. parent的宽度取决于 child

但结果是,Chrome 在某处停止了计算,结果是:

enter image description here

如果您尝试在 JSFiddle 上水平地展开“ result”面板,您会发现它们的宽度不会改变。请注意,child中的内容被包装成 两条线(而不是一行) ,为什么?我想 Chrome 只是在某个地方硬编码了。如果你编辑 child的内容,使它更多(JSFiddle) ,你会发现,只要有额外的空间横向,Chrome 保持内容两行。

我们可以看到: 有一些方法可以防止无限计算


我同意这样的推测: 这种设计只是为了保持基于相同度量的四个边距/填充值。

这篇文章 (用中文写)还提出了另一个原因: 这是因为阅读/排版的方向。我们从上往下阅读,宽度固定,高度无限(实际上)。

我知道 OP 要求 为什么的 CSS 规范定义顶部/底部边距百分比为宽度的百分比(而不是假设的高度) ,但我认为它也可能是有用的张贴一个潜在的解决方案。

现在大多数现代浏览器都支持 vw 和 vh,它们允许您根据视口宽度和视口高度指定边距号。

如果没有滚动条,100vw/100vh 等于100% 宽度/100% 高度(分别) ; 如果有一个滚动条,视口号就不会考虑这一点(而% 数字会考虑这一点)。值得庆幸的是,几乎所有的浏览器都使用17px (看这里)大小的滚动条,因此您可以使用 css calc 函数来解释这一点。如果您不知道滚动条是否会出现,那么这个解决方案将不起作用。

例如: 假设没有水平滚动条(高度的50%) ,则可以将顶部边距定义为“ edge-top: 50vh;”。如果使用水平滚动条,则可以将其定义为“间距-top: calc (0.5 * (100vh-17px))”(请记住,calc 中的减号和加号操作符在两边都需要空格!).

我知道这个问题有点老,但我想为 CSS3重新回答一下。虽然 CSS2.1规范说明了百分比填充和边距是相对于包含块的宽度定义的,但这不是 一直都是的情况。这取决于写作模式。这句话直接来自 CSS3规格:

作为一个推论,边距和填充属性的百分比,总是根据 CSS2.1中包含块的宽度计算的,是根据 CSS3中包含块的内联大小计算的。

我用我的 使用 CSS 的纵横比教程报道这个。

具体来说,在 水平和垂直写入模式中的填充百分比上有一个章节。默认情况下,元素具有水平写入模式,其中文本从左向右水平流动(在“内联”方向)。但是,使用 writing-mode CSS 属性,实际上可以将模式设置为垂直(文本从右向左或从左向右流动)。下面是一些横向和纵向写作模式的图表:

A horizontal writing mode, with text flowing vertically from top to bottom. An arrow points from left to right at the top of the document and is labeled as the inline direction. Another arrow points from top to bottom and is labeled as the block direction.

A vertical writing mode, with text flowing horizontally. The horizontal axis is labeled as the block direction, whereas the vertical axis is now labeled as the inline direction. Text is rendered sideways.

这些是从 MDN 关于编写模式的文档上拍的。

在垂直写入模式中,百分比填充将相对于包含块的高度,而不是宽度。

这就是证据:

.document {
writing-mode: vertical-rl;
width: 100%;
height: 100vh;
}


.parent {
width: 100%;
height: 200px;
background-color: black;
color: white;
}


.child {
padding: 10%;
background-color: white;
color: black;
border: solid 1px;
}
<div class="document">
<div class="parent">
<div class="child">
Child
</div>
</div>
</div>

子块获得20px 的填充,这是其包含块高度(200px)的10% 。

至于为什么在这个问题中,这个问题在这里的其他帖子中已经被很好地涵盖了。