探究:絕對定位沒有設置 top, right, bottom, left 的世界是怎樣的?

一個元素若是設置了'position: absolute;', 但沒有設置top, right, bottom, left, 此元素的位置在哪?css

在涉及到絕對定位元素的位置問題時, 一個重要的概念是containing block, 想要了解元素的位置, 還得找到此元素的containing block才行. 以下是我進行的一系列測試, 以及對測試結果的試探性解釋. html

文中的英文術語都不翻譯, 方便直接查W3C或者其餘技術文檔.
請持有懷疑精神閱讀此文, 歡迎討論.css3

在inline box裏的狀況

http://jsfiddle.net/medifle/s00Laa0a/3
上面的例子沒有對任何元素設置'position: absolute;'chrome

http://jsfiddle.net/medifle/9qnp9uh4/1
增長以下代碼svg

span.left {
  margin-right: 10px;
  padding-right: 10px;
}
span.inner {
  position: absolute;
}

span.inner 只設置'position: absolute;', 沒有設置top, right, bottom或left. 此時top, right, bottom或left的initial value是auto.工具

如今, 嘗試用chrome開發者工具對span.inner元素的'position: absolute;'進行勾選或者取消勾選, 看看發生了什麼? (提醒: 在這個例子裏, span.inner與span.left元素之間是沒有空白符(white space)的, span.inner內部有一個空格, 兩個 .)測試

取消勾選'position: absolute;'後, 多出一個空白符. 再次勾選後, 多出的那個空白符消失. 這個消失的空白符是誰? 爲何會消失?flex

如今咱們先把span.inner的'position: absolute;'取消勾選. 若是咱們再嘗試對span.inner分別設置'float: left;', 'display: inline-block;', 'display: table-cell;', 'display: table;', 'display: inline-table;', 'display: inline-flex;', 你會發現span.inner內的第一個空白符(是一個空格)都會發生一樣的現象: 消失.spa

消失緣由得從上面的一堆屬性種找共同點: BFC(block formatting context). 上面的每個屬性(包括'position: absolute;')都可以觸發一個新的BFC, 因此span.inner裏的內容進入了BFC後成爲了新的一行, 而根據W3C的規範:.net

a sequence of collapsible spaces at the beginning of the line is removed

即行首部分的一個或多個可摺疊(collapsible)的空白符是被移除的. 我想這就是消失的緣由. 因此, 這個現象並非'position: absolute;'沒有設置top, right, bottom, left狀況下的專屬, 應該能夠排除了.

注:

從上面的例子裏, 彷佛span.inner的containing block的左邊緣就是span.inner前面緊挨着的那個元素的margin右邊緣. 狀況是這樣嗎? 繼續看下一個例子.

https://jsfiddle.net/medifle/t22sng4a/
此例中CSS未變, HTML的span.inner與span.left之間多了一個空白符, span.inner內部的第一個空白符(是個空格)去掉了, 留下了兩個 .

<section class="demo"> 
    <span class="left">Beginning of body contents.</span>
    <span class="inner" style="position: absolute;">&nbsp;&nbsp;Inner contents.</span>
</section>

如今, 嘗試用chrome開發者工具對span.inner元素的'position: absolute;'進行勾選或者取消勾選, 看看發生了什麼?

這一次, 若是取消'position: absolute;'後再嘗試對span.inner分別設置'float: left;', 'display: inline-block;', 'display: table-cell;', 'display: table;', 'display: inline-table;', 'display: inline-flex;', 結果是: 沒變化.

此例與上例的惟一改變就在於空白符的位置, 這說明了 span.inner的containing block的左邊緣應該是span.inner前面緊挨着的那個元素(不考慮空白符)的margin右邊緣. 而且left的initial value, 即'auto', 會把span.inner定位到它的containing block的左邊緣 (本文只考慮文本的'direction'爲'left-to-right'的狀況).

https://jsfiddle.net/medifle/sccpersL/
html有改動, 加了兩個圖片, span與span元素之間沒有空白符, 恢復span.inner的那個去掉的空白符(是個空格).

<section class="demo">
  <p>
    <span class="left">Beginning of body contents.</span><span class="inner" style="position: absolute;"> &nbsp;&nbsp;Inner contents.</span><img class="img1" src="https://upload.wikimedia.org/wikipedia/commons/e/e7/Mozilla_Firefox_3.5_logo_256.png" width="55"><img class="img2" src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Stack_Overflow_logo.svg/2000px-Stack_Overflow_logo.svg.png" width="300px">
  </p>
</section>

如今測試的是span.inner(別忘了它只設置了'position: absolute;'且不設置top, right, bottom, left)的containing block的上邊緣.

嘗試用chrome開發者工具對span.inner元素的’position: absolute;’進行勾選或者取消勾選, 看看發生了什麼?

span.inner在被賦予’position: absolute;’的時候, 其在垂直方向上的表現與對其設置'vertical-align: top;'沒有差別. 從上述測試結果看, span.inner的containing block的上邊緣應該與其所處的line box的content box的上邊緣在位置上是一致的.

兩個驗證例子:
http://jsfiddle.net/medifle/3y7ucLLy/
http://jsfiddle.net/medifle/proa0fru/

對於上述的第二個例子, 嘗試用chrome開發者工具對img.img1元素的’position: absolute;’進行勾選或者取消勾選, 看看發生了什麼? (留意: img.img1和img.img2都設置了'position: absolute;'且沒有設置top, right, bottom, left).

結果說明, 對一個元素(img.img1)進行絕對定位會影響到另外一個絕對定位的元素(img.img2)的位置, 固然, 這個'絕對定位'是沒有設置四個方向屬性的值的狀況.

http://jsfiddle.net/medifle/upg4da8o/
此例CSS變更以下:

.inbox {
    color: blue;
    position: absolute;
    top: -10px;
}
.floatele {
    float: right;
    width: 300px;
    height:50px;
    background: tomato;
    padding: 10px;
}
.demorel {
    position: relative;
}

HTML以下:

<section class="demo demorel">
      <p>Beginning of body contents.
        <div class="floatele">
          <span class="inner"> &nbsp;&nbsp;Inner contents.</span><span style="top: -10px;" class="inbox"> &nbsp;&nbsp;Inner contents.</span>
        </div>
    </p>
</section>

此例的第二個'Inner contents.', 即span.inbox設置了top: -10px; 其餘三個方向仍然不設置, 即爲auto. section.demorel設置了'position: relative;'. div.floatele設置了'float: right;', 此時span.inbox的containing block的左邊緣仍然知足前面的結論.

在block box裏的狀況

http://jsfiddle.net/medifle/26dgo5k7/

<section class="demo demorel">
  <div class="floatele">
    <div class="inbox2"></div>
  </div>
</section>

CSS主要有:

.inbox2 {
    background: #6c4ecd;
    width: 50px;
    height: 50px;
    position: absolute;
}
.floatele {
    float: right;
    width: 300px;
    height:50px;
    background: tomato;
    padding: 10px;
}
.demorel {
    position: relative;
}

div.inbox2的containing block的左邊緣和上邊緣都是其直系父元素content box的左邊緣和上邊緣 (content box的邊緣又稱content edge).

但值得注意的是, 此例與常規絕對定位狀況下的區別:
http://jsfiddle.net/medifle/j7xevk78/

CSS有改變, 包含在HTML內:

<section class="demo demorel">
  <div style="position: relative;" class="floatele">
    <div style="left: 0; top: 0;" class="inbox2"></div>
  </div>
</section>

這是一個常規的絕對定位例子, 由於設置了top和left的值. 值得注意的一點是, 此時div.inbox2的containing block的左邊緣和上邊緣是其直系父元素的padding edge.

若是div.inbox2的前面有一個block box:
https://jsfiddle.net/medifle/dvcfev3s/3/

此例中有兩個div.inbox2, 在它們以前分別有一個block box, 一個是div.blockbox, 另外一個是p元素.

從這個例子能夠發現, 若是div.inbox2不是其父元素的第一個元素, 且前面是一個block box, 則div.inbox2的containing block的上邊緣是div.blockbox的margin下邊緣.

小結

當絕對定位且不設置方向值的元素在inline box裏時:

  1. 未設置的方向(top, right, bottom, left)的值是auto.

  2. 此元素containing block的左邊緣應該是該元素前一個元素(空白符除外)的margin右邊緣.

  3. 此元素containing block的上邊緣應該是該元素所在的line box的content box的上邊緣

  4. 若是left的值爲auto, 則該元素會定位到其containing block的左邊緣. 若是top的值爲auto, 則該元素會定位到其containing block的上邊緣.

當絕對定位且不設置方向值的元素在block box裏時:

  1. 未設置的方向(top, right, bottom, left)的值是auto.

  2. 此元素的containing block的左邊緣應該是其父元素建立的content box的左邊緣.

  3. 若是該元素前面存在一個與其相鄰的block box, 則該元素的containing block的上邊緣應該是這個block box的margin下邊緣.

  4. 若是該元素是其父元素的第一個子元素, 則該元素的containing block的上邊緣應該是其父元素建立的content box的上邊緣.

  5. 若是left的值爲auto, 則該元素會定位到其containing block的左邊緣. 若是top的值爲auto, 則該元素會定位到其containing block的上邊緣.

本文只探討了元素分別在line box和block box裏的containing block的左邊緣和上邊緣(文本的'direction'爲默認的'ltr', 即從左到右), 還有更多有待探討.

本文所探討的問題我沒有找到直接相關的W3C規範, 若是有請必定要@bolo :)

相關文章
相關標籤/搜索