爲何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解析以及渲染的順序流程等,這兒權當是拋出了問題,不對的地方還望指出改正,一塊兒探討學習。

相關文章
相關標籤/搜索