本文介紹了絕對定位元素其定位對其寬度的影響情況,並且根據絕對定位元素的內容類型不同進行探討,給出了自己總結的規律,以解決元素寬度顯示不對的問題。 ...
一、問題來源 自己編寫輪播圖切換的時候前一幅圖滑動時後邊出現空白直到前一幅圖全部滑出後第二幅圖才出現。剛開始出現問題到網上搜發現有的說定時器動畫可能會造成這種情況,於是我在代碼調試里註釋掉了定時器,讓圖片只走一步就停下來,發現後邊還是有空白,所以確定不是定時器的問題。於是我查看了一下盒模型,發現包裹img的容器寬度div#main並不是我理想中六張圖片寬度的總和,原來是我沒有顯式設置這個容器div#main的寬度。但是問題來了,沒有顯式地設置容器寬度,大家可能就會感性的認為容器的寬度不應該是被其內容填充而適應的麽?根據前面所述的現象,答案自然是否定的,也可以說不是所有情況均是如此,因為實際上定位對容器的寬度也是具有影響的。下麵討論一下絕對定位元素的大小與放置情況的聯繫。 二、包含塊 首先我們先回顧一下包含塊(定位上下文)的基本概念: 1.初始包含塊(根元素的包含塊)由用戶代理確定。 2.浮動元素包含塊定義為最近的塊級祖先元素。 3.相對定位或靜態定位元素包含塊由最近的塊級框、表單元格、或行內塊框祖先元素(任何類型)內容邊界構成。 4.絕對定位元素包含塊設置為最近的定位不是static的祖先元素(任何類型)的邊框界定(對塊級父元素)或內容邊界界定(對行內父元素)。 三、寬度與偏移 一般的,元素的大小和位置取決於其包含塊。定位就是元素各外邊距邊界相對於其包含塊相應邊(內邊界與邊框相鄰邊)進行偏移,影響的是元素的所有一切(外邊距、邊框、內邊距、內容)都會移動。故對於一個定位元素有如下等式(後邊的計算均基於該式): left+margin-left+border-left-width+padding-left+width+padding-right+border-right-width+margin-right+right=包含塊的width (式1-1) 據此,在未定義元素的寬度width和高度height時,其值大小都會受到定位影響。對於定位元素來說,是否需要設置其寬度高度應根據情況確定。考慮以下幾種情況其寬度高度各是多少的確定規則: 1.如果將偏移屬性top,left,bottom,right都進行了確定,而未設置外邊距,內邊距和邊框的時候,是否顯式設置寬度高度,其值都是由偏移屬性確定的;反之若設置了外邊距或內邊距(auto也算),邊框時,高度寬度就是其顯式設置值,未顯式設寬高的仍由偏移屬性確定。 2.對於非替換元素水平軸行為: 1)如果left,width,right都為auto,且沒有設置內外邊距,邊框,則經過計算元素左邊位於其靜態位置(從左往右讀),width“恰當收放”,根據上述等式right為餘下的水平距離; 2)當等式中所有值為固定值時,若元素“過度受限”則right會根據上式重置; 3)當上述等式中只有一個屬性值為auto時,元素“過度受限”時就會重置這一屬性值以滿足等式; 4)垂直軸規則類似,但要註意只有top可以取靜態位置,bottom做不到。 3.對於替換元素(註意這裡沒有“恰當收放”的概念,因為替換元素有固有寬高): 1)先看其width(height)是否顯式聲明,顯式聲明則為該值,否則由元素內容實際大小(寬高)決定; 2)再看left,top若為auto則替換為靜態位置; 3)再看如果left和bottom值如果還為auto,則令margin的auto都置0,若未被置0就設置為左右相等,上下相等; 4)在此之後如果只剩下一個auto值,則同非替換元素類似,根據等式重置該auto值。 5)當元素“過度受限”時,與非替換元素處理一樣,用戶代理會忽略right(從左向右讀)和bottom。 以上就是對一個絕對定位元素實際顯示的寬度高度的影響因素情況分析,當你發現界面顯示的效果與你預想的不一致時,可以考慮從上述角度分析一下看是否需要重新確定元素的寬度高度值,或以上其它屬性的值。 四、一種常見的情形分析 現在來結合一下我在項目中遇到的寬度高度問題實際例子分析。這裡討論的假定情形為:設置好寬高的最外層div#rel為相對定位,其子div#abs僅設置left為固定值而未設置寬度(沒有內外邊距邊框前提下),div#abs內部包含不同類型的元素。 1.先討論最內層包裹的是塊級元素的情況,代碼見下:
<div id="rel1"> <div id="abs1"> <div id="box1"></div> <div id="box2"></div> </div> </div>
*{margin:0;padding: 0} #rel1{position: relative;width: 120px;height: 50px;background-color: yellow;} #abs1{position: absolute;top: 0;left: -15px} #box1{width: 50px;height: 50px;background-color: red} #box2{width: 50px;height: 50px;background-color: blue}由代碼可知,我們將絕對定位元素的margin,padding都置0,且無邊框,則上述式1-1簡化為: 絕對定位元素div#abs的 left+width+right = 包含塊div#rel的 width 由於絕對定位元素的left是定值,而未設width和right,所以後兩個都是初始值auto,根據非替換軸的水平行為1)可知,先將width恰當收放,也就是以絕對定位元素的子元素內容剛好放好為準,再自動計算right的值,使三個屬性之和剛好等於絕對定位的包含塊div#rel的寬度120px。因此,此時絕對定位的元素div#abs的寬度width的值由其內容決定,在如下圖兩種情形下(通過代碼改變子div#box1的寬度進行測試),絕對定位元素的width始終等於子div中寬度最大的那個值。且不受left值的影響,因為無論left值為多少,其right的值都會自動調整,從而不影響width的值。 2.再來看最內層包裹的是替換行內元素的情況,代碼及示意圖如下:
<div id="rel2"> <div id="abs2"> <img src="images/pic1.jpeg" alt="" id="img1"> <img src="images/pic2.jpeg" alt="" id="img2"> </div> </div>
*{margin:0;padding: 0} #rel2{position: relative;width: 120px;height: 50px;background-color: yellow;} #abs2{position: absolute;top: 0;} img{float:left} #img1{width: 50px;height: 50px} #img2{width: 50px;height: 50px}其中,絕對定位元素的left將被設為定值,而width根據“恰當收放”的原則,它的最大值應該是行內子元素寬度之和,最小值應該是子元素中寬度最大者的寬度值,而right的值情況有一點複雜,因為預設情況下,塊級元素是垂直排列而行內元素都是一個挨著一個(中間的縫隙可以用:float:left清除)從左向右排列,且中間沒有換行符。所以行內元素放在絕對定位的塊級元素內作為元素內容寬度過寬時,會由於其行內元素的特點將內容撐開一直到其包含塊內容區右邊界(從左向右讀),因此當行內子元素(即絕對元素的內容)受限出現折行時right的值為0,式1-1便簡化為如下: 絕對定位元素div#abs的 left+width = 包含塊div#rel的 width 當然這種情況應該是在left設定值在一定範圍內的前提下(因為寬度沒有設置,是auto的),那麼如何確定這個範圍呢?當絕對定位元素的寬度剛好等於其最小值和最大值時,利用上面的公式求出left的範圍設置在(包含塊width-最大絕對定位元素width)~(包含塊width-最小絕對定位元素width)之間時,絕對定位元素的寬度是受left值影響的,可以通過上面的公式求出當left為某一特定值時的絕對定位元素的width。 當left的值設定在上面所說的範圍之外時,絕對定位元素的width已經達到了極值,就不會再受left變化而影響了,此時right就不再是0,而會自動進行計算以滿足下述公式: 絕對定位元素div#abs的 left+width+right = 包含塊div#rel的 width 3.總結來說,在前提假定的情形下: 1)如果絕對定位元素包裹塊級元素,則其width值始終等於子元素中寬度最大者的值。 2)如果絕對定位元素包裹的行內元素,則其width值最大為子元素寬度之和,最小為子元素寬度最大者的值;並需先求出影響width值的left區間,在用其包含塊的寬度-left值來求其寬度。
五、總結
兜兜轉轉說了這麼多,其實就是一個道理,如果你擔心絕對定位元素的寬度出現問題的話,最好顯式地給它設定一個width固定值,因為根據規則1,在沒有將四個偏移屬性全部設置的前提下,顯式的width值是管用噠~然而在實際環境中,設置寬度高度對定位元素來說不一定必要,所以理解寬度高度的影響因素將會對遇到的一些關於效果顯示的問題更有幫助。這是我第一次寫科技博文,首先我要向替我審校的本人優雅的攻城獅男友致以最真摯的謝意,同時感謝O’Reilly叢書《CSS權威指南第三版》的作者及其相關工作人員,本文大量內容均是參考該書並加以自己的理解所寫,初次發文如有問題,還請大家批評指正,非常感謝各位~