为何margin-top设置百分比基于父元素的宽度计算的?

margin-top和padding-top设置百分比问题

咱们都知道css很简单。因此在平时的开发当中,也没有在乎一些具体的细节。咱们知道某一个属性值大概的含义。好比咱们知道css的盒模型,是由margin, border, padding, content 四个部分组成。若是咱们想要设置一个元素的外边距,只须要设置margin值就能够。css

margin取值能够为数值、百分比以及auto。margin为简写的形式,咱们还能够分别设置margin的top、right、bottom、left值。好比咱们写以下的代码:chrome

<style>
        .margin-container {
            background: #333;
            width: 400px;
            height: 200px;
            color: #fff;
        }
        .margin-child {
            margin-top: 10%;
            width: 200px;
            height: 100px;
            background-color: black;
        }
    </style>
<div class="margin-container">
        <div class="margin-child">
            margin content
        </div>
    </div>

那么问题来了,其中margin-top: 10%;这个百分比,到底是基于谁来计算的百分比呢?浏览器

再来看一个例子:工具

<style>
        .padding-container {
            background: #333;
            width: 400px;
            height: 200px;
            color: #fff;
        }
        .padding-child {
            padding-top: 20%;
            width: 200px;
            height: 100px;
            background-color: black;
        }
    </style>
<div class="padding-container">
        <div class="padding-child">
            padding content
        </div>
    </div>

此处的padding-top: 20%;又是基于谁来计算的百分比呢? 学习

若是你已经清楚答案了, 那可能没有再继续阅读下去的必要。可是若是你还有疑问的话,那咱们接下来就一探究竟。spa

结果分析

咱们先不看结果,按照常规的思惟来想想。页面当中有一个.margin-container容器元素,一个.margin-child子元素。容器元素以及子元素都设置了相应的宽高。咱们都知道块级元素在页面中是按照垂直方向挨个排列的,而margin-top是当前设置元素的外上边距,因此应该是在垂直方向上设置的一个距离。设置为百分比的话应该是根据元素的高度来进行相应的计算的。咱们暂且先无论对错。code

此处有两个问题:blog

  • margin-top设置百分比时是基于自身元素仍是容器元素的值来计算的?
  • margin-top设置百分比时是基于height,仍是width计算的?

接下来然咱们看看具体的结果:开发

image.png

其实咱们从这个图当中就能获取到咱们想要的答案。
首先咱们看margin-child的margin-top值设置为10%。在chrome开发者工具中,咱们能看到其margin-top计算后的值为40px。而咱们的margin-child宽高分别为200px、100px,margin-container宽高分别为400px、200px。因此咱们能够得出结论margin-child所对应的margin-top为10%,是其父元素margin-container宽度400px的百分之十。因此以上两个问题对应的答案为:文档

  • margin-top设置百分比时是基于容器元素的值来计算的
  • margin-top设置百分比时是基于width计算的

固然,若是你再看看padding-top的设置。也会获得相同的结果。为何?为何会是基于宽度而非高度来计算?为何是基于父元素而非子元素来进行计算?(此处另外若是你们注意观察的话,咱们设置的是margin-child的margin-top为10%,我直觉上应该是会在margin-child与margin-container之间会有10%的距离,可是从渲染结果看,实际上是margin-container与body的距离为10%,此处涉及margin合并的问题。若是不清楚能够自行查阅相关问题。)

咱们从W3C规范文档中能够知道:
image.png
image.png

规范当中就是这么规定的,也就是浏览器或者说浏览器的渲染引擎(注:也许这么叫不是很恰当)就是这么来实现的。那为何要这么规定?基于高度计算会有什么问题?

这篇文章给出了相应的一些说明,总结出来两点:

  • margin/padding计算都基于一个值,width进行计算,这样可以保证top,right,bottom,left四个值的一致性
  • 因为父元素的高度是根据其所包含的子元素进行计算的,若是子元素的margin/padding是基于父元素高度计算的话,那么会引发高度计算的循环依赖。

咱们着重说一说第二点。

假设咱们在一开始的示例中,没有给margin-container设置宽高

.margin-container {
    background: #333;
    color: #fff;
}
<div class="margin-container">
    <div class="margin-child">
        margin content
    </div>
</div>

image.png

image.png

此时父元素的宽为714px,高度为100px。由于目前只有一个子元素,子元素高度为100px,子元素的margin-top为父元素宽度的10%,计算后为71.4px。因为会存在偏差因此渲染出来显示71.391px,而且子元素的margin与父元素的margin进行了合并,因此看起来是父元素距离body顶部71.391px。因此父元素的高度为100px。

试想若是咱们按照高度来计算margin百分比的话,此时margin-child的margin-top值应该为100px*10%=10px。看起来彷佛没有问题,可是,咱们渲染的时候知道body宽度,因为没有设置margin-container的宽高,在渲染margin-contaner的时候须要计算它的宽高,此时咱们能够肯定其宽度为body宽度714px。高度未知,高度须要根据子元素的高度来进行计算,因此紧接着去进行margin-child的解析计算,发现child的高度为100px,margin-top为父元素高度的10%,而此时父元素高度又不肯定,因此margin-child的margin-top应该是多少呢?

那有的人可能会说,父元素高度不是根据子元素高度计算么?子元素的高度为100px,因此父元素高度为100px,因此子元素的margin-top值为10px。若是浏览器引擎在解析css的时候是按照 解析子元素高度 -> 计算父元素高度 -> 计算子元素margin 这样的顺序的话,好像也是能够说的通的。

那咱们再看看下面的例子:

.margin-container {
    background: #333;
    color: #fff;
}
.margin-child {
    margin-top: 10%;
    width: 200px;
    height: 100px;
    background-color: black;
}
<div class="margin-container">
    <div class="margin-child">
        margin content
    </div>
    <div class="margin-child">
        margin content 2
    </div>
</div>

运行结果为:

image.png

此时的父元素包含了两个子元素。父元素的高度计算为子第一个元素的高度+第二个子元素高度+第二个子元素的margin-top

那按照刚才的说法,若是浏览器引擎在解析css的时候是按照 解析子元素高度 -> 计算父元素高度 -> 计算子元素margin 这样的顺序的话,子元素高度和200px -> 父元素高度200px -> 子元素margin-top为10%=20px。再结合刚才运行的结果,父元素的高度计算为子第一个元素的高度+第二个子元素高度+第二个子元素的margin-top,此时父元素高度又发生了改变,那子元素的margin值还须要改变吗? 若是还须要改变的话,父元素的高度又会发生变化,此时就行程的循环依赖。

因此,你真的弄懂css中的margin和padding了吗?

以上为我的的浅见,其实有一些不严谨的地方,浏览器针对css解析以及渲染的顺序流程等,这儿权当是抛出了问题,不对的地方还望指出改正,一块儿探讨学习。

相关文章
相关标签/搜索