前端開發(fā),離不開日常的網(wǎng)頁結(jié)構(gòu)布局,現(xiàn)下有很多第三方的組件庫,也自帶著很多布局的方案,例如Ant Design中就擁有一套自己的Grid 24柵格系統(tǒng)和Layout布局,方便我們進(jìn)行網(wǎng)頁排版。
接下來,我們從前端技術(shù)角度上,去分析一下3種經(jīng)典布局的實(shí)現(xiàn)方案。
首先,我們列出一些比較常規(guī)的布局:
- 圣杯布局
- 雙飛翼布局
- 多列等分布局
1. 圣杯布局
圣杯布局: 左右兩欄的寬度固定不變,中間那一欄寬度自適應(yīng),且中間盒子的內(nèi)容優(yōu)先渲染。
最早的圣杯布局的實(shí)現(xiàn)方案是:利用
浮動和負(fù)邊距來實(shí)現(xiàn)。父級元素設(shè)置左右的 padding,三列均設(shè)置向左浮動,中間一列放在最前面,寬度設(shè)置為父級元素的寬度,因此后面兩列都被擠到了下一行,通過設(shè)置
margin 負(fù)值將其移動到上一行,再利用相對定位,定位到兩邊。
圣杯布局的優(yōu)缺點(diǎn):
- 優(yōu)點(diǎn):不需要額外的DOM結(jié)構(gòu),中間欄放在文檔流前面是優(yōu)先渲染
- 缺點(diǎn):特殊情況下,當(dāng)中間盒子寬度小于左盒子的時(shí)候 就會發(fā)生布局混亂
我們可以通過3種技術(shù)方案來實(shí)現(xiàn)圣杯布局的布局效果,分別是float、float優(yōu)化、Flex
實(shí)現(xiàn)代碼:
HTML結(jié)構(gòu):
<div class="main">
<!-- 如果是圣杯布局的原始方案,此處的center盒子要放在最前面 -->
<div class="center"></div>
<div class="left"></div>
<div class="right"></div>
</div>
- 實(shí)現(xiàn)方案1:
float+position+負(fù)邊距
.main {
height: 200px;
/* 外層大盒子設(shè)置左右的padding,給兩側(cè)小盒子預(yù)留出位置 */
padding: 0 200px;
}
.center, .left, .right {
/* 三個(gè)盒子統(tǒng)一左浮動 */
float: left;
}
/* 注意,在HTML結(jié)構(gòu)中,center盒子一定要位于left和right盒子之前 */
.center {
/* 中間盒子占據(jù)父盒子寬度的100% */
width: 100%;
height: 100%;
background: lightgreen;
}
.left {
width: 200px;
height: 100%;
background: lightseagreen;
/* left被center盒子擠到了下方,設(shè)置margin負(fù)值會讓三個(gè)盒子在一行上顯示 */
margin-left: -100%;
/* 通過定位負(fù)值讓left盒子位于main盒子預(yù)留出的padding的位置 */
position: relative;
left: -200px;
}
.right {
width: 200px;
height: 100%;
background: lightskyblue;
/* right被center盒子擠到了下方,設(shè)置margin負(fù)值會讓三個(gè)盒子在一行上顯示 */
margin-left: -200px;
/* 通過定位負(fù)值讓right盒子位于main盒子預(yù)留出的padding的位置 */
position: relative;
right: -200px;
}
- 實(shí)現(xiàn)方案2:
float優(yōu)化
.main {
width: 100%;
height: 100px;
}
.left {
width: 200px;
height: 100%;
background: lightcoral;
/* 左盒子左浮動 */
float: left;
}
.right {
width: 200px;
height: 100%;
background: lightgreen;
/* 右盒子右浮動 */
float: right;
}
.center {
height: 100%;
background: lightsalmon;
/* 中間盒子左浮動 */
float: left;
/* 中間盒子使用css的calc()去自動計(jì)算寬度,思想為:父盒子寬度100% - (左盒子 + 右盒子) */
/* 注意:如果網(wǎng)頁中在意極致加載速度等優(yōu)化效率時(shí),盡量不要大量使用calc()函數(shù) */
width: calc(100% - 400px);
}
- 實(shí)現(xiàn)方案3:
Flex
.main {
width: 100%;
height: 100px;
/* 父盒子轉(zhuǎn)為flex彈性盒子 */
display: flex;
/* 子元素居中 */
justify-content: center;
align-items: center;
}
.left {
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
width: 200px;
height: 100%;
background: lightgreen;
}
.center {
height: 100%;
background: lightsalmon;
/* 中間盒子占據(jù)剩下的全部空間 */
flex: 1;
}
當(dāng)然,實(shí)現(xiàn)圣杯布局的效果,還可以使用其它的方案,比如Grid布局方式,只要能夠?qū)崿F(xiàn)其圣杯布局的效果,用什么方式均可以。
2. 雙飛翼布局
概念:雙飛翼布局最早是淘寶團(tuán)隊(duì)提出的,是針對圣杯局部優(yōu)化的解決方案。主要是優(yōu)化了圣杯布局中開啟定位的問題
雙飛翼布局的實(shí)現(xiàn),本質(zhì)上也是利用了浮動和外邊距負(fù)值的思想。
雙飛翼布局與圣杯布局的不同之處在于,圣杯布局的左中右三列容器,中間center盒子多了一個(gè)子容器,通過控制center中子容器的margin空出左右兩列的寬度。
<body>
<div class="main">
<div class="center">
<div class="inner"></div>
</div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
.main {
height: 200px;
}
.center,
.left,
.right {
/* 三個(gè)盒子統(tǒng)一左浮動 */
float: left;
}
.center {
/* 中間大盒子占據(jù)父盒子寬度的100% */
width: 100%;
height: 100%;
background: lightgreen;
}
.center .inner {
height: 100%;
/* 預(yù)留出左右兩個(gè)盒子的空間 */
margin: 0 200px;
background: lightcoral;
}
.left {
width: 200px;
height: 100%;
background: lightseagreen;
/* left被center盒子擠到了下方,設(shè)置margin負(fù)值會讓三個(gè)盒子在一行上顯示 */
margin-left: -100%;
}
.right {
width: 200px;
height: 100%;
background: lightskyblue;
/* right被center盒子擠到了下方,設(shè)置margin負(fù)值會讓三個(gè)盒子在一行上顯示 */
margin-left: -200px;
}
3. Flex實(shí)現(xiàn)多列等分布局
關(guān)鍵點(diǎn):列數(shù)可自由控制(無固定寬度)
<div class="main">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
.main {
width: 100%;
display: flex;
/* 設(shè)置換行 */
flex-wrap: wrap;
/* 用來設(shè)置網(wǎng)格行與列之間的間隙,是row-gap(行間隙)和column-gap(列間隙)的簡寫形式 */
gap: 20px;
}
.main .item {
height: 200px;
/* 關(guān)鍵點(diǎn)在于子盒子寬度的計(jì)算上 */
/* flex: 0 0 calc((父元素寬度 - 列之間的寬度*(列數(shù)-1)) / 列數(shù)); */
flex: 0 0 calc((100% - 20px * 3) / 4);
background: lightskyblue;
}
以上3中布局,是我們開發(fā)中經(jīng)常見到的布局方式,每種布局方式,都不僅限于一種技術(shù)來實(shí)現(xiàn),可以是Float和Position,也可以是Flex,還可以是Grid,甚至有的開發(fā)者對Boostrap很熟悉,也是一種實(shí)現(xiàn)方式。
個(gè)人認(rèn)為,每種技術(shù)方案的使用,都有其優(yōu)缺點(diǎn),或考慮兼容性,或考慮性能,選擇適合當(dāng)下項(xiàng)目的內(nèi)容,適當(dāng)做取舍,才是最關(guān)鍵的。
關(guān)注我,下期我們一起探討Grid和Flex的不同之處。