咱们都知道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-child的margin-top值设置为10%。在chrome开发者工具中,咱们能看到其margin-top计算后的值为40px。而咱们的margin-child宽高分别为200px、100px,margin-container宽高分别为400px、200px。因此咱们能够得出结论margin-child所对应的margin-top为10%,是其父元素margin-container宽度400px的百分之十。因此以上两个问题对应的答案为:文档
固然,若是你再看看padding-top的设置。也会获得相同的结果。为何?为何会是基于宽度而非高度来计算?为何是基于父元素而非子元素来进行计算?(此处另外若是你们注意观察的话,咱们设置的是margin-child的margin-top为10%,我直觉上应该是会在margin-child与margin-container之间会有10%的距离,可是从渲染结果看,实际上是margin-container与body的距离为10%,此处涉及margin合并的问题。若是不清楚能够自行查阅相关问题。
)
咱们从W3C规范文档中能够知道:
规范当中就是这么规定的,也就是浏览器或者说浏览器的渲染引擎(注:也许这么叫不是很恰当)就是这么来实现的。那为何要这么规定?基于高度计算会有什么问题?
这篇文章给出了相应的一些说明,总结出来两点:
咱们着重说一说第二点。
假设咱们在一开始的示例中,没有给margin-container设置宽高
.margin-container { background: #333; color: #fff; }
<div class="margin-container"> <div class="margin-child"> margin content </div> </div>
此时父元素的宽为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>
运行结果为:
此时的父元素包含了两个子元素。父元素的高度计算为子第一个元素的高度+第二个子元素高度+第二个子元素的margin-top
。
那按照刚才的说法,若是浏览器引擎在解析css的时候是按照 解析子元素高度 -> 计算父元素高度 -> 计算子元素margin
这样的顺序的话,子元素高度和200px -> 父元素高度200px -> 子元素margin-top为10%=20px
。再结合刚才运行的结果,父元素的高度计算为子第一个元素的高度+第二个子元素高度+第二个子元素的margin-top
,此时父元素高度又发生了改变,那子元素的margin值还须要改变吗? 若是还须要改变的话,父元素的高度又会发生变化,此时就行程的循环依赖。
因此,你真的弄懂css中的margin和padding了吗?
以上为我的的浅见,其实有一些不严谨的地方,浏览器针对css解析以及渲染的顺序流程等,这儿权当是抛出了问题,不对的地方还望指出改正,一块儿探讨学习。