今天聊聊一個經典的佈局實例:實現一個三列佈局,其中左側和右側的部分寬度固定,中間部分寬度隨瀏覽器寬度的變化而自適應變化可能很多朋友已經笑了,這玩意兒通過雙飛翼佈局就能輕鬆實現。不過,還請容我在雙飛翼之外,循序漸進地介紹一下我們可以如何實現一個三列佈局。1. 首先,使用浮動佈局來實現一下See ...
今天聊聊一個經典的佈局實例:
實現一個三列佈局,其中左側和右側的部分寬度固定,中間部分寬度隨瀏覽器寬度的變化而自適應變化
可能很多朋友已經笑了,這玩意兒通過雙飛翼佈局就能輕鬆實現。不過,還請容我在雙飛翼之外,循序漸進地介紹一下我們可以如何實現一個三列佈局。
1. 首先,使用浮動佈局來實現一下
See the Pen float-three-columns by xal821792703 (@honoka) on CodePen.
- 左側元素與右側元素優先渲染,分別向左和向右浮動
- 中間元素在文檔流的最後渲染,並將 width 設為 100%,則會自動插入到左右兩列元素的中間,隨後設置 margin 左右邊距分別為左右兩列的寬度,將中間元素調整到正確的位置。
這是一種比較便利的實現方式,無需額外的元素輔助定位,同時相容性也比較優秀。但有一個缺點就是該佈局方式只能實現左右兩列寬度固定,中間自適應這一種三列佈局,靈活性不強。
2. 其實,也可以試試利用 BFC
See the Pen bfc-three-columns by xal821792703 (@honoka) on CodePen.
昨天的《CSS 佈局實例系列(二)如何通過 CSS 實現一個左邊固定寬度、右邊自適應的兩列佈局》已經談到了利用 BFC 原理實現多列佈局的方法。BFC 元素不會與浮動元素疊加,自然也可以利用 BFC 原理完成這個實例。
- 同樣的左右兩列元素優先渲染,並分別左右浮動。
- 接下來將中間元素設置 overflow: hidden; 成為 BFC 元素塊,不與兩側浮動元素疊加,則自然能夠插入自己的位置啦。
3. 接下來就嘗試一下大名鼎鼎的雙飛翼佈局吧
See the Pen grid-three-columns by xal821792703 (@honoka) on CodePen.
雙飛翼是由淘寶玉伯等前端大牛提出的一種多列佈局方法,主要利用了浮動、負邊距、相對定位三個佈局屬性,使三列佈局就像小鳥一樣,擁有中間的身體和兩側的翅膀。
接下來就簡單介紹一下雙飛翼的實現過程:
- 假設我們現在需要一個如實例說明一樣的三列佈局,寫出如下 div 結構:
<div class="grid"> <div id="div-middle-02"><span>div-middle</span></div> <div id="div-left-02"><span>div-left</span></div> <div id="div-right-02"><span>div-right</span></div> </div>
- 首先我們將中間元素放在文檔流最前面優先渲染,然後使其向左浮動,並設置 width 為 100%:
#div-middle-02 { float: left; background-color: #fff9ca; width: 100%; height: 50px; }
中間元素直接占滿全列,形成小鳥的身體。
- 接下來我們開始為小鳥加上雙翼,將左右兩列元素均設為左浮動,然後通過調整負邊距將其定位在各自的位置上:
#div-middle-02 { float: left; background-color: #fff9ca; width: 100%; height: 50px; } #div-left-02 { float: left; background-color: red; width: 150px; margin-left: -100%; height: 50px; } #div-right-02 { float: left; background-color: yellow; width: 200px; margin-left: -200px; height: 50px; }
看起來,雙翼安裝成功啦。
- 這樣三列佈局就大功告成了?No,no,no,仔細看看上面的效果圖,可以發現 div-middle 的字塊消失了。這是因為通過負邊距調整浮動元素位置時,會產生層疊的效果,上面的佈局其實只是左右兩列元素分別定位在自己的位置上並覆蓋中間元素的那部分而已,中間元素的定位並未成功。中間元素要怎樣定位在自己的位置上呢?小鳥的身體不是還缺少骨架嘛,那麼我們在小鳥體內加上骨架吧:
<div id="div-middle-02"> <div id="middle-wrap-02"><span>div-middle</span></div> </div>
在中間元素中再增加一層包裹,通過這層骨架我們就可以方便地控制小鳥身體的位置啦,方法就是調整骨架的左右邊距,使其分別等於左右兩列的寬度:
#div-middle-02 { float: left; background-color: #fff9ca; width: 100%; height: 50px; } #middle-wrap-02 { margin: 0 200px 0 150px; } #div-left-02 { float: left; background-color: red; width: 150px; margin-left: -100%; height: 50px; } #div-right-02 { float: left; background-color: yellow; width: 200px; margin-left: -200px; height: 50px; }
好啦,一個左右定寬,中間自適應的三列佈局以雙飛翼的方式成功完成。
- 總結整個過程,就是先放好身體,再加上翅膀,然後讓身體包裹一層骨架,通過骨架將身體定位到正確的位置。這就是雙飛翼佈局的完全體嗎?當然不是,接下來我們要請出大殺器相對佈局啦,就像小鳥可以通過各種不同的姿勢飛翔一般,通過 position: relative; 雙飛翼可以實現任意的三列或雙列佈局。本實例加上相對定位,便成為了這樣的完全體:
#div-middle-02 { float: left; background-color: #fff9ca; width: 100%; height: 50px; } #middle-wrap-02 { margin: 0 200px 0 150px; } #div-left-02 { float: left; position: relative; background-color: red; width: 150px; margin-left: -100%; height: 50px; } #div-right-02 { float: left; position: relative; background-color: yellow; width: 200px; margin-left: -200px; height: 50px; }
- 雙飛翼能夠相容到 IE6,其可以實現的各種佈局在此便不作展開了,有興趣可以參考玉伯分享的 DEMO
4. 跟上潮流,試試 flex
See the Pen flex-three-columns by xal821792703 (@honoka) on CodePen.
看完了強大的雙飛翼佈局,是不是已經心急火燎地想親手試試啦。別急,客官,再聽我嘮嘮 CSS3 的新佈局 flex 唄。先讓我說明一下上面的 DEMO 中是怎樣實現本次實例的:
- 設計一個彈性容器包裹需定位的三個元素,然後將該彈性容器的排列屬性設為水平排列(flex-flow: row)
- 現在三個元素已經是三列佈局了,再將三列元素分別設定一下寬度就行了,左右元素設定為定寬,自適應的中間元素設定為 100%。
.flex { display: flex; flex-flow: row; } #div-left-03 { background-color: red; width: 150px; height: 50px; } #div-middle-03 { background-color: #fff9ca; width: 100%; height: 50px; } #div-right-03 { background-color: yellow; width: 200px; height: 50px; }
效果如下圖:
- 搞定收工!大哥你瞪著我是怎麼回事兒?~ 什麼?效果不對?我的代碼怎麼可能不對?!~ 哎呦,別打我,我馬上檢查(哭)好吧,寬度不對,左右兩側的寬度均不符合設定的定值。什麼情況呢?原來在 flex 佈局中不能將被定位的元素寬度或高度設定為 100%,這樣會影響其他定值大小的元素。那麼該如何設置中間元素的寬度呢,flex: 1; 即可,可以試一下 DEMO 中去掉註釋與不去掉的區別。
- 最後簡單介紹一下 flex:flex 是 CSS3 的一種彈性容器佈局,通過 flex,幾行簡單的 CSS 語句便可以實現各種佈局(對!我就是 flex NC粉~被拍飛~)。那麼 flex 有什麼缺點呢?對,就是相容性!
- 所以在使用 flex 的時候還請註意是否相容當前瀏覽器,是否需要 -webkit- 標簽。flex 的具體語法和各類實例因為篇(lan)幅(de)過(xie)多的原因,也不做過多介紹了,可以參考阮一峰老師的博文:
最後感謝大家的閱讀,歡迎前往我的 repo 查看源代碼整理,有任何問題也請盡情向我吐槽。