【CSS黑科技2】CSS百分比實現高度佔位自適應(margin/padding)

| 導語 在不少場景下,咱們都須要給容器設定寬高比,實現自適應佔位,巧用margin/padding可讓咱們實現咱們的需求css

 

基本知識點css3

本文依賴於一個基礎卻又容易混淆的css知識點:當padding/margin取形式爲百分比的值時,不管是left/right,仍是top/bottom,都是以父元素的width爲參照物的!瀏覽器

哈,top/left以父元素的width爲參照物還好理解,但top/bottom不是以height更符合咱們的預期嗎?有疑惑很簡單,看官方解釋sass

 

 

 

舉個栗子測試

咱們有個頁面,以下圖,若是是在PC端好辦,容器的寬高都寫死是多少px,這樣即便圖片加載不出來容器都不會變型。可是在移動端,因爲各機型分辨率相差太大,寫死px是絕對不可能的,終究還得靠百分比來實現的:優化

 

 

  1. 一行2列的容器寬度設個50%吧,這樣一行放倆容器,各佔屏幕寬度一半,沒問題。
  2. 圖片寬度設個100%取容器的寬度,沒問題。
  3. 容器高度無法設置啊,由於容器寬高的參照物不同,並且需求是高度與寬度一致,因此沒法經過爲容器高度設置百分比來達成,那就只能靠內容高度撐開了。
  4. 容器的內容高度就是圖片的高度,若圖片是正方形,則圖片高度與圖片寬度一致,也即與容器寬度一致,看起來沒問題是吧?實際上,在瀏覽器把圖片加載出來之前,圖片的高度是零,那可就沒辦法把容器撐開了,以下圖所示:

 

 

這樣一來,即便圖片加載速度再快,也會有個高度撐開的過程,若是圖片沒有加載成功,那更慘,整個頁面的結構都有可能會有問題,這確定會被測試同窗報bug的啦spa

如今問題很明顯了,就是怎麼不用圖片能夠撐開容器高度,並且是高度可控,好比寬高比是個1:2什麼的3d

給容器設置padding-top/bottomcode

啦啦啦,上文說的padding-top/bottom的百分比值,是依賴父容器寬度的,這樣容器的寬度和高度均可以統一同一個參照物了(父元素的寬度)blog

舉個例子,圖片寬高比是1:1,一行放2個容器

視覺結果以下:

 

容器的盒子模型以下:

 

 

從盒子模型能夠看出,雖然容器的內容高度爲0,但因爲有了跟內容寬度一致的padding,所以總體視覺效果上像是被撐開了。咱們達成了最初的夢想

此方案瀏覽器兼容性很不錯,惟一的缺陷是沒法給容器設置max-height屬性了,由於max-height只能限制內容高度,而不能限制padding!!,以下這個項目:

 

 

這個頭圖是按寬高比設置的大小,可是還須要考慮橫屏的狀況,以下圖:

 

 

咱們是不會輕易的狗帶的!!

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

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

咱們再來看看此時的盒子模型:

 

 

完美,能夠看出,此時容器的內容高度與內容寬度一致,媽媽不再用擔憂我沒法經過max-height來限制容器高度了。

上面那個項目也是這樣解決了不能設置max-height的痛點

 

 

 

另外,使用margin的話須要考慮margin摺疊的問題(參考代碼BFC相關),padding則無此煩惱。

哈,容器就給你了,要往容器內添加內容,但不能添加額外高度,那隻能是使用position:absolute啦~

最後,奉上sass以下:

//佔位 是否可控高度:false(沒法控制min-height,但沒有多餘結構) true(可控制min-height,但要增長結構)
@mixin proporBox($arg:1, $type:false, $ele:':before'){
    position: relative;
    @if $type == true {
        &#{$ele}{
            content: '';
            display: block;
            width: 100%;
            padding-top: percentage($arg);
        }
    }@else{
        padding-top: percentage($arg);
    }   
}