巧用margin/padding的百分比值實現高度自適應(多用於佔位,避免閃爍)

一個基礎卻又容易混淆的css知識點

本文依賴於一個基礎卻又容易混淆的css知識點:當margin/padding取形式爲百分比的值時,不管是left/right,仍是top/bottom,都是以父元素的width爲參照物的!
也許你會說,left/right以父元素的width爲參照物好理解,可是top/bottom爲何也是以父元素的width爲參照物的呢?網上衆說紛紜,關鍵仍是看W3C的規範css

Note that in a horizontal flow, percentages on ‘margin-top’ and ‘margin-bottom’ are relative to the width of the containing block, not the height (and in vertical flow, ‘margin-left’ and ‘margin-right’ are relative to the height, not the width).html

Note that percentages on ‘padding-top’ and ‘padding-bottom’ are relative to the width of the containing block, not the height (at least in a horizontal flow; in a vertical flow they are relative to the height).css3

權威一出,記住就好,科科。瀏覽器

高度自適應佔位

假設有這麼個場景:佈局

如上圖所示,有這麼一種用來放圖片的容器,圖片都是正方形(爲了方便舉例用正方形,實際上只要固定長寬比例便可)。在PC端好辦,容器的寬高都寫死是多少px,這樣即便圖片加載不出來容器都不會變型。可是在移動端,因爲各機型分辨率相差太大,寫死px是絕對不可能的,終究還得靠百分比來實現自適應:優化

  1. 容器寬度設個50%吧,這樣一行放倆容器,各佔屏幕寬度一半,沒問題。spa

  2. 圖片寬度設個100%取容器的寬度,沒問題。code

  3. 容器高度無法設置啊,由於容器寬高的參照物不同,並且需求是高度與寬度一致,因此沒法經過爲容器高度設置百分比來達成,那就只能靠內容高度撐開了。htm

  4. 容器的內容高度就是圖片的高度,若圖片是正方形,則圖片高度與圖片寬度一致,也即與容器寬度一致,看起來沒問題是吧?實際上,在瀏覽器把圖片加載出來之前,圖片的高度是零,那可就沒辦法把容器撐開了,以下圖所示:blog

這樣一來,即便圖片加載速度很快,容器在圖片加載先後都會有一個變型的過程,也就是俗稱的「閃爍」,而若是圖片加載不出來,總體佈局就更是難看了。如今問題已經出來了,就是如何作到不靠圖片自己就能把容器的高度撐開。

設置容器的padding-bottom/top

使用margin/padding的百分比值來解決自適應高度的關鍵在於:容器margin/padding的百分比參照物是父元素的寬度,而容器的width的百分比參照物也是父元素的寬度,倆屬性參照物一致,那麼想要把這倆屬性的值統一塊兒來就很簡單了。優化方案是這樣的:給容器設置padding-top/padding-bottom跟width一致的值(百分比)。

#container { width: 50%; //父元素寬度的一半 background-color: red; //僅爲了方便演示 } .placeholder { padding-top: 50%; //與width: 50%;的值保持一致,也就是至關於父元素寬度的一半。 }
<div id="container" class="placeholder"></div>

結果,容器的視覺效果以下:

容器的盒子模型以下:

從盒子模型能夠看出,雖然容器的內容高度爲0,但因爲有了跟內容寬度一致的padding,所以總體視覺效果上像是被撐開了。此方案瀏覽器兼容性很不錯,惟一的缺陷是沒法給容器設置max-height屬性了,由於max-height只能限制內容高度,而不能限制padding(我原覺得設置box-sizing: border-box;可讓max-height限制padding,不過親測無效,明白的朋友麻煩告知一下緣由)。

給子元素/僞元素設置margin/padding撐開容器

從上面的方案看出max-height失效的緣由是容器的高度原本就是padding撐的,而內容高度爲0,max-height沒法起做用。那想要優化這一點,惟一的方法就是利用內容高度來撐開而非padding,這個方案跟消除浮動所用的方案很是類似:給容器添加一個子元素/僞元素,並把子元素/僞元素的margin/padding設爲100%,使其實際高度至關於容器的寬度,如此一來,便能把容器的高度撐至與寬度一致了。因爲添加子元素與HTML語義化相悖,所以更推薦使用僞元素(:after)來實現此方案。

#container { width: 50%; position: relative; background-color: red; overflow: hidden; //須要觸發BFC消除margin摺疊的問題 } .placeholder:after { content: ''; display: block; margin-top: 100%; //margin 百分比相對父元素寬度計算 } 
<div id="container" class="placeholder"></div>

此時視覺效果上與上一方案無異,重點來看看此時容器的盒子模型:

能夠看出,此時容器的內容高度與內容寬度一致,媽媽不再用擔憂我沒法經過max-height來限制容器高度了。
另外,使用margin的話須要考慮margin摺疊的問題(參考),padding則無此煩惱。

容器內部如何添加內容

上述方案只說起如何不依賴容器內容來撐開容器,那麼,在撐開容器後,如何給容器添加內容(圖片、文本等)呢?
答案很簡單,那就是利用position: absolute;

#container { width: 50%; position: relative; background-color: red; overflow: hidden; //須要觸發BFC消除margin摺疊的問題 } .placeholder:after { content: ''; display: block; margin-top: 100%; //margin 百分比相對父元素寬度計算 } img { position: absolute; top: 0; width: 100%; }
<div id="container" class="placeholder"> <img src="http://img.arrayhuang.cn/product/miya-1060079/multiple/0.jpg@1e_415w_415h_1c_0i_1o_1x.jpg" /> </div>

效果以下:

後補

寬高不一致的自適應怎麼作?

有朋友可能會問,上面提到的都是寬度與高度一致的狀況,若是不一致那怎麼辦呢?其實自適應的重點在於,元素的寬高必須維持一個固定的比例,好比說寬高一致比例就是1:1,寬是高的兩倍那就是2:1,只要這個比例是明確並且固定的,那麼只須要相應地修改margin/padding的百分比值便可適應不一樣的寬高比例。

還有其它的寬高自適應方案嗎?

固然有,好比說css3新推出的長度單位vw,就是以屏幕寬度爲參照物的,只要給元素的width和height都用上vw單位,那width跟height就能夠輕易設成同樣的了,不過既然是css3,瀏覽器兼容性確定成問題:

總結

相關文章
相關標籤/搜索