基本知識點
本文依賴於一個基礎卻又容易混淆的css知識點:當padding/margin取形式為百分比的值時,無論是left/right,還是top/bottom,都是以父元素的width為參照物的!
哈,top/left以父元素的width為參照物還好理解,但top/bottom不是以height更符合我們的預期嗎?有疑惑很簡單,看官方解釋:
舉個栗子
我們有個頁面,如下圖,如果是在PC端好辦,容器的寬高都寫死是多少px,這樣即使圖片加載不出來容器都不會變型。但是在移動端,由於各機型分辨率相差太大,寫死px是絕對不可能的,終究還得靠百分比來實現的:
- 一行2列的容器寬度設個50%吧,這樣一行放倆容器,各占屏幕寬度一半,沒問題。
- 圖片寬度設個100%取容器的寬度,沒問題。
- 容器高度沒法設置啊,因為容器寬高的參照物不一樣,而且需求是高度與寬度一致,所以無法通過為容器高度設置百分比來達成,那就只能靠內容高度撐開了。
- 容器的內容高度就是圖片的高度,若圖片是正方形,則圖片高度與圖片寬度一致,也即與容器寬度一致,看起來沒問題是吧?實際上,在瀏覽器把圖片加載出來以前,圖片的高度是零,那可就沒辦法把容器撐開了,如下圖所示:
這樣一來,即使圖片加載速度再快,也會有個高度撐開的過程,如果圖片沒有加載成功,那更慘,整個頁面的結構都有可能會有問題,這肯定會被測試同學報bug的啦
現在問題很明顯了,就是怎么不用圖片可以撐開容器高度,而且是高度可控,比如寬高比是個1:2什么的
給容器設置padding-top/bottom
啦啦啦,上文說的padding-top/bottom的百分比值,是依賴父容器寬度的,這樣容器的寬度和高度都可以統一同一個參照物了(父元素的寬度)
舉個例子,圖片寬高比是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如下:
position: relative; @if $type == true { &#{$ele}{ content: ''; display: block; width: 100%; padding-top: percentage($arg); } }@else{ padding-top: percentage($arg); } }