歡迎光臨
每天分享高質量文章

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

作者:bolo的前端blog

網址:http://segmentfault.com/a/1190000003109367

一個元素如果設置了’position: absolute;’, 但沒有設置top, right, bottom, left, 此元素的位置在哪?

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

文中的英文術語都不翻譯, 方便直接查W3C或者其他技術文件.

請持有懷疑精神閱讀此文, 歡迎討論.

在inline box里的情況

http://jsfiddle.net/medifle/s00Laa0a/3

上面的例子沒有對任何元素設置’position: absolute;’

http://jsfiddle.net/medifle/9qnp9uh4/1

增加如下代碼

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;’後, 多出一個空白符. 再次勾選後, 多出的那個空白符消失. 這個消失的空白符是誰? 為什麼會消失?

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

消失原因得從上面的一堆屬性種找共同點: BFC(block formatting context). 上面的每一個屬性(包括’position: absolute;’)都能夠觸發一個新的BFC, 所以span.inner里的內容進入了BFC後成為了新的一行, 而根據W3C的規範:

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

即行首部分的一個或多個可摺疊(collapsible)的空白符是被移除的. 我想這就是消失的原因. 所以, 這個現象並不是’position: absolute;’沒有設置top, right, bottom, left情況下的專屬, 應該可以排除了.

註:

  • ‘overflow: hidden;’ 不能應用於inline box, 不滿足觸發BFC的條件. 詳情見flow-root BFC
  • ‘display: table;’通過產生anonymous ‘table-cell’ box觸發一個新的BFC.

從上面的例子里, 似乎span.inner的containing block的左邊緣就是span.inner前面緊挨著的那個元素的margin右邊緣. 情況是這樣嗎? 繼續看下一個例子.

https://jsfiddle.net/medifle/t22sng4a/

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

Beginning of body contents.

  Inner contents.

現在, 嘗試用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的那個去掉的空白符(是個空格).

Beginning of body contents.   Inner contents.

現在測試的是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如下:

Beginning of body contents.

  Inner contents.   Inner contents.

此例的第二個’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/

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內:

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

小結

當絕對定位且不設置方向值的元素在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. 如果left的值為auto, 則該元素會定位到其containing block的左邊緣. 如果top的值為auto, 則該元素會定位到其containing block的上邊緣.

本文只探討了元素分別在line box和block box里的containing block的左邊緣和上邊緣(文本的’direction‘為預設的’ltr’, 即從左到右), 還有更多有待探討.

本文所探討的問題我沒有找到直接相關的W3C規範, 如果有請一定要@bolo 🙂

赞(0)

分享創造快樂