135

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

[margin] 百分比是根据生成框的包含块的宽度计算的。请注意,“margin-top”和“margin-bottom”也是如此。如果包含块的宽度取决于此元素,则结果布局在 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/

4

5 回答 5

60

将我的评论转移到答案,因为它合乎逻辑。但请注意,这是毫无根据的猜想。以这种方式编写规范的实际原因在技术上仍然未知。

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

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

于 2012-06-12T21:03:31.700 回答
30

要使“n%”边距(和填充)margin-top/margin-right/margin-bottom/margin-left 相同,所有四个必须相对于同一个基数。如果 top/bottom 使用的 base 与 left/right' 不同,那么“n%”边距(和填充)在所有四个边上的含义都不相同。

(另请注意,相对于宽度的上/下边距会启用一个奇怪的 CSS hack,它允许您指定一个具有不变纵横比的框……即使该框被重新缩放。)

于 2013-08-18T02:40:50.953 回答
4

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


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

看看这个JSFiddleparent显示的是inline-block,它有资格在其上定义边距/填充。具有child边际价值20%。如果我们遵循无限计算猜想:

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

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

在此处输入图像描述

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

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


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

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

于 2015-11-26T03:19:58.910 回答
3

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

大多数现代浏览器现在都支持 vw 和 vh ,这使您可以根据视口宽度和视口高度指定边距数。

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

例如:假设没有水平滚动条,50% 高度的上边距可以定义为“margin-top: 50vh;”。使用水平滚动条,这可以定义为“margin-top: calc(0.5 * (100vh - 17px));” (请记住,calc 中的减号和加号运算符需要两边都有空格!)。

于 2016-01-05T17:16:56.817 回答
1

我知道这个问题有点老了,但我想为 CSS3 刷新它。虽然 CSS2.1 规范确实说百分比填充和边距是相对于包含块的宽度定义的,但情况并非总是如此。这取决于写作模式。这直接来自CSS3 规范

作为推论,margin 和 padding 属性的百分比,在 CSS2.1 中总是根据包含块的宽度计算,在 CSS3 中是根据包含块的内联大小计算的。

我在我的 CSS 纵横比教程中对此进行了介绍。

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

一种水平书写模式,文本从上到下垂直流动。 一个箭头从左到右指向文档顶部,并标记为内联方向。 另一个箭头从上到下,标记为块方向。

一种垂直书写模式,文字水平流动。 水平轴被标记为块方向,而垂直轴现在被标记为内联方向。 文本横向呈现。

这些取自MDN 文档 on writing patterns

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

这是证据:

.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>

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

至于问题中的原因,这里的其他帖子对此进行了很好的介绍。

于 2020-09-24T12:19:58.043 回答