一個元素若是設置了'position: absolute;', 但沒有設置top, right, bottom, left, 此元素的位置在哪?css
在涉及到絕對定位元素的位置問題時, 一個重要的概念是containing block, 想要了解元素的位置, 還得找到此元素的containing block才行. 以下是我進行的一系列測試, 以及對測試結果的試探性解釋. html
文中的英文術語都不翻譯, 方便直接查W3C或者其餘技術文檔.
請持有懷疑精神閱讀此文, 歡迎討論.css3
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狀況下的專屬, 應該能夠排除了.
注:
'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內部的第一個空白符(是個空格)去掉了, 留下了兩個 .
<section class="demo"> <span class="left">Beginning of body contents.</span> <span class="inner" style="position: absolute;"> 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;"> 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"> Inner contents.</span><span style="top: -10px;" class="inbox"> 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的左邊緣仍然知足前面的結論.
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裏時:
未設置的方向(top, right, bottom, left)的值是auto.
此元素containing block的左邊緣應該是該元素前一個元素(空白符除外)的margin右邊緣.
此元素containing block的上邊緣應該是該元素所在的line box的content box的上邊緣
若是left的值爲auto, 則該元素會定位到其containing block的左邊緣. 若是top的值爲auto, 則該元素會定位到其containing block的上邊緣.
當絕對定位且不設置方向值的元素在block box裏時:
未設置的方向(top, right, bottom, left)的值是auto.
此元素的containing block的左邊緣應該是其父元素建立的content box的左邊緣.
若是該元素前面存在一個與其相鄰的block box, 則該元素的containing block的上邊緣應該是這個block box的margin下邊緣.
若是該元素是其父元素的第一個子元素, 則該元素的containing block的上邊緣應該是其父元素建立的content box的上邊緣.
若是left的值爲auto, 則該元素會定位到其containing block的左邊緣. 若是top的值爲auto, 則該元素會定位到其containing block的上邊緣.
本文只探討了元素分別在line box和block box裏的containing block的左邊緣和上邊緣(文本的'direction'爲默認的'ltr', 即從左到右), 還有更多有待探討.
本文所探討的問題我沒有找到直接相關的W3C規範, 若是有請必定要@bolo :)