为什么CSS中的margin / padding百分比总是根据宽度计算?

时间:2012-06-12 19:58:06

标签: w3c css

如果查看CSS box model spec,您会看到以下内容:

  

[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/

5 个答案:

答案 0 :(得分:57)

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

  

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

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

答案 1 :(得分:26)

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

(另请注意,相对于 width 具有顶部/底部边距会启用一个奇怪的CSS hack,允许您指定具有不变宽高比的框...即使该框重新缩放。 )

答案 2 :(得分:3)

在使用此JSFiddle(在Chrome浏览器46.0.2490.86上)并参考this post(用中文书写)后,我投票支持@ChuckKollars的答案。

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

查看此JSFiddleparent显示为inline-block,有资格在其上定义边距/填充。 child的边距值为20%。如果我们按照无限计算猜想:

  1. child的宽度取决于parent
  2. parent的宽度取决于child
  3. 但结果是Chrome停止了计算,结果是:

    enter image description here

    如果您尝试扩展&#34;结果&#34;在JSFiddle上水平放置面板,你会发现它们的宽度不会改变。请注意child中的内容包含在两行中(不是说,一行),为什么?我想Chrome只是在某处硬编码。如果您修改child内容以使其更多(JSFiddle),您会发现只要水平有额外的空间,Chrome就会将内容保留两行。

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

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

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

答案 3 :(得分:3)

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

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

如果没有滚动条,

100vw / 100vh等于100%宽度/ 100%高度(分别);如果有滚动条,则视口编号不会考虑到这一点(而%数字会这样做)。值得庆幸的是,几乎所有浏览器都使用17px({{3}})的滚动条大小,因此您可以使用css calc函数来解释此问题。如果您不知道是否会出现滚动条,则此解决方案将无效。

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

答案 4 :(得分:1)

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

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

我在tutorial on aspect ratios with CSS中对此进行了介绍。

具体地说,在Percentage Padding in Horizontal vs. Vertical Writing Modes上有一节。默认情况下,元素具有水平书写模式,其中文本从左到右水平(沿“内联”方向)流动。但是,实际上,您可以使用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 docs on writing modes

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

这是证据:

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

关于问题的原因,这里的其他帖子对此做了很好的介绍。