聖盃佈局和雙飛翼佈局是前端工程師須要平常掌握的重要佈局方式。二者的功能相同,都是爲了實現一個兩側寬度固定,中間寬度自適應的三欄佈局。
javascript
聖盃佈局來源於文章In Search of the Holy Grail,而雙飛翼佈局來源於淘寶UED。雖然二者的實現方法略有差別,不過都遵循瞭如下要點:css
<div>
標籤下面我將依次介紹聖盃佈局和雙飛翼佈局的實現方法,並在最後根據我的思考對原有方法作出一些修改,給出其它一些可行的方案。html
<div id="header"></div> <div id="container"> <div id="center" class="column"></div> <div id="left" class="column"></div> <div id="right" class="column"></div> </div> <div id="footer"></div>
首先定義出整個佈局的DOM結構,主體部分是由container
包裹的center
,left
,right
三列,其中center
定義在最前面。前端
假設左側的固定寬度爲200px,右側的固定寬度爲150px,則首先在container
上設置:java
#container { padding-left: 200px; padding-right: 150px; }
爲左右兩列預留出相應的空間,獲得以下示意圖:git
隨後分別爲三列設置寬度與浮動,同時對footer
設置清除浮動:github
#container .column { float: left; } #center { width: 100%; } #left { width: 200px; } #right { width: 150px; } #footer { clear: both; }
獲得以下效果:前端工程師
根據浮動的特性,因爲center
的寬度爲100%,即佔據了第一行的全部空間,因此left
和right
被「擠」到了第二行。框架
接下來的工做是將left
放置到以前預留出的位置上,這裏使用負外邊距(nagetive margin):ide
#left { width: 200px; margin-left: -100%; }
獲得:
隨後還須要使用定位(position)方法:
#left { width: 200px; margin-left: -100%; position: relative; right: 200px; }
這裏使用position: relative
和right: 200px
將left
的位置在原有位置基礎上左移200px,以完成left
的放置:
接下來放置right
,只需添加一條聲明便可:
#right { width: 150px; margin-right: -150px; }
獲得最終的效果圖:
至此,佈局效果完成。不過還須要考慮最後一步,那就是頁面的最小寬度:要想保證該佈局效果正常顯示,因爲兩側都具備固定的寬度,因此須要給定頁面一個最小的寬度,但這並不僅是簡單的200+150=350px。回想以前left
使用了position: relative
,因此就意味着在center
開始的區域,還存在着一個left
的寬度。因此頁面的最小寬度應該設置爲200+150+200=550px:
body { min-width: 550px; }
綜上所述,聖盃佈局的CSS代碼爲:
body { min-width: 550px; } #container { padding-left: 200px; padding-right: 150px; } #container .column { float: left; } #center { width: 100%; } #left { width: 200px; margin-left: -100%; position: relative; right: 200px; } #right { width: 150px; margin-right: -150px; } #footer { clear: both; }
關於聖盃佈局的示例,可參考:聖盃佈局
最後提醒一下不少朋友可能會忽略的小細節:在#center
中,包含了一條聲明width: 100%
,這是中間欄可以作到自適應的關鍵。可能會有朋友認爲不須要設置這條聲明,由於以爲center
在不設置寬度的狀況下會默認將寬度設置爲父元素(container
)的100%寬度。但須要注意到,center
是浮動元素,因爲浮動具備包裹性,在不顯式設置寬度的狀況下會自動「收縮」到內容的尺寸大小。若是去掉width: 100%
,則當中間欄不包含或者包含較少內容時,整個佈局會「崩掉」,而達不到這樣的效果:
<body> <div id="header"></div> <div id="container" class="column"> <div id="center"></div> </div> <div id="left" class="column"></div> <div id="right" class="column"></div> <div id="footer"></div> <body>
雙飛翼佈局的DOM結構與聖盃佈局的區別是用container
僅包裹住center
,另外將.column
類從center
移至container
上。
按照與聖盃佈局相同的思路,首先設置各列的寬度與浮動,而且爲左右兩列預留出空間,以及爲footer
設置浮動清除:
#container { width: 100%; } .column { float: left; } #center { margin-left: 200px; margin-right: 150px; } #left { width: 200px; } #right { width: 150px; } #footer { clear: both; }
獲得以下效果示意圖:
以上代碼將container
,left
,right
設置爲float: left
,而在container
內部,center
因爲沒有設置浮動,因此其寬度默認爲container
的100%寬度,經過對其設置margin-left
和margin-right
爲左右兩列預留出了空間。
將left
放置到預留位置:
#left { width: 200px; margin-left: -100%; }
獲得:
將right
放置到預留位置:
#right { width: 150px; margin-left: -150px; }
獲得最終效果:
最後計算最小頁面寬度:因爲雙飛翼佈局沒有用到position:relative
進行定位,因此最小頁面寬度應該爲200+150=350px。可是當頁面寬度縮小到350px附近時,會擠佔中間欄的寬度,使得其內容被右側欄覆蓋,以下所示:
所以在設置最小頁面寬度時,應該適當增長一些寬度以供中間欄使用(假設爲150px),則有:
body { min-width: 500px; }
至此雙飛翼佈局大功告成!其佈局總體代碼爲:
body { min-width: 500px; } #container { width: 100%; } .column { float: left; } #center { margin-left: 200px; margin-right: 150px; } #left { width: 200px; margin-left: -100%; } #right { width: 150px; margin-left: -150px; } #footer { clear: both; }
關於雙飛翼佈局的示例,可參考:雙飛翼佈局
經過對聖盃佈局和雙飛翼佈局的介紹能夠看出,聖盃佈局在DOM結構上顯得更加直觀和天然,且在平常開發過程當中,更容易造成這樣的DOM結構(一般<aside>
和<article>
/<section>
一塊兒被嵌套在<main>
中);而雙飛翼佈局在實現上因爲不須要使用定位,因此更加簡潔,且容許的頁面最小寬度一般比聖盃佈局更小。
其實經過思考不難發現,二者在代碼實現上都額外引入了一個<div>
標籤,其目的都是爲了既能保證中間欄產生浮動(浮動後還必須顯式設置寬度),又能限制自身寬度爲兩側欄留出空間。
從這個角度出發,若是去掉額外添加的<div>
標籤,可否完成相同的佈局呢?答案是確定的,不過這須要在兼容性上作出犧牲:
<div id="header"></div> <div id="center" class="column"></div> <div id="left" class="column"></div> <div id="right" class="column"></div> <div id="footer"></div>
去掉額外的<div>
標籤後,獲得的DOM結構如上所示,基於雙飛翼佈局的實現思路,只須要在center
上作出修改:
.column { float: left; } #center { margin-left: 200px; margin-right: 150px; width: calc(100% - 350px); }
經過calc()
能夠十分方便地計算出center
應該佔據的自適應寬度,目前calc()
支持到IE9。
.column { float: left; } #center { padding-left: 200px; padding-right: 150px; box-sizing: border-box; width: 100%; }
使用border-box
能夠將center
的整個盒模型寬度設置爲父元素的100%寬度,此時再利用padding-left
和padding-right
能夠自動獲得中間欄的自適應寬度。不過須要注意的是,因爲padding是盒子的一部分,因此padding部分會具備中間欄的背景色,當中間欄高於側欄時,會出現這樣的狀況:
目前box-sizing
支持到IE8。
這裏使用flex仍是須要與聖盃佈局相同的DOM結構,不過在實現上將更加簡單:
<!-- DOM結構 --> <div id="container"> <div id="center"></div> <div id="left"></div> <div id="right"></div> </div>
CSS代碼以下:
#container { display: flex; } #center { flex: 1; } #left { flex: 0 0 200px; order: -1; } #right { flex: 0 0 150px; }
以上就是本人在學習聖盃佈局和雙飛翼佈局過程當中的一些總結和認識,文章若有錯誤,歡迎你們多多指教~