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

如果您查看CSS框模型规范 ,您将观察以下内容:

[margin]百分比是根据生成的box的包含块的宽度计算的。 请注意,“margin-top”和“margin-bottom”也是如此。 如果包含块的宽度取决于这个元素,那么在CSS 2.1中得到的布局是不确定的。 (重点是我的)

这确实如此。 但为什么 ? 究竟是什么迫使任何人这样devise呢? 很容易想到你想要的场景,例如某个东西永远比页面顶部降低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/

将我的评论转移到答案,因为这是合理的。 但请注意,这是毫无根据的猜想。 为什么规范是这样写的,实际的推理在技术上还是未知的。

元素高度由儿童的高度定义。 如果一个元素有padding-top:10%(相对于父级高度),这将影响父级的高度。 由于孩子的身高取决于父母的身高,父母的身高取决于孩子的身高,所以我们要么有不准确的身高,要么是无限循环。 当然,这只影响抵消父母===父母的情况,但仍然如此。 这是一个很难解决的奇怪情况。

更新:最后几个句子可能不完全准确。 叶元素(没有孩子的孩子)的高度对其上的所有元素的高度有影响,所以这影响许多不同的情况。

对于margin-top / margin-right / margin-bottom / margin-left,“n%”的边距(和填充)是相同的 ,所有四个必须是相对于相同的基数。 如果顶部/底部使用与左/右不同的底部,那么“n%”边距(和填充)在四面都不意味着相同的东西。

(还要注意,相对于宽度来说,使用顶部/底部边距可以实现奇怪的CSS黑客攻击,使您可以指定长宽比不变的盒子,即使盒子已重新resize)。

我玩了这个JSFiddle (在Chrome 46.0.2490.86上)并参考了这篇文章 (用中文写的)之后,从@ChuckKollars投了个答案。


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

看看这个JSFiddle , parent显示是inline-block ,它有资格定义margin / padding。 child保证金为20% 。 如果我们遵循无限的计算猜想:

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

但结果是,Chrome停止了计算,导致:

在这里输入图像描述

如果您尝试在JSFiddle上水平展开“结果”面板,则会发现它们的宽度不会更改。 请注意, child的内容被分成两行 (不是说一行),为什么? 我想铬只是硬编码的地方。 如果您编辑child内容( JSFiddle ),您会发现只要有额外的空间水平,Chrome保持内容两行。

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


我同意这样的猜想:这种devise只是为了保持四个边际/填充价值基于相同的措施。

这篇文章 (中文)也提出另一个原因是:这是因为阅读/排版的方向。 我们从上到下阅读,宽度固定,高度无限(虚拟)。

我意识到OP在问为什么 CSS规范将顶部/底部边距百分比定义为宽度的百分比(而不是假定的高度),但是我认为发布潜在的解决scheme可能也是有用的。

大多数现代浏览器现在支持vw和vh,这使您可以根据视口宽度和视口高度来指定保证金数量。

如果没有滚动条,100vw / 100vh等于100%宽度/ 100%高度(分别) 如果有一个滚动条,视口数字不会占这个(而%数字)。 谢天谢地,几乎所有的浏览器都使用17px的滚动条大小( 见这里 ),所以你可以使用css calc函数来解决这个问题。 如果你不知道滚动条是否会出现,那么这个解决scheme将不起作用。

例如:假设没有水平滚动条,高度为50%的上​​边距可以定义为“margin-top:50vh”。 使用水平滚动条,可以将其定义为“margin-top:calc(0.5 *(100vh – 17px)); (请记住calc中的minus和plus操作符在两边都需要空格!)。