0. 前言
作為一個不喜歡寫樣式的前端,遇到了直接對外的活動頁面的需求,一下炸出一堆問題:
- 單位亂用,rem、vh、vw、px亂用甚至混在一起用
- html冗餘,有時候一個div只是為了取margin
- 一個頁面用多種佈局方案,flex、float、relative+top、absolute+top、margin,自己坑自己
- 各種隨意,不嚴格按照視覺稿 理論倒是熟悉,但用起來還是一塌糊塗。於是,回頭自我救贖一波,好好複習基礎。flex、grid後面不多作研究,尤其是grid這種一兩行就可以搞定很多複雜樣式。如果我們不知道新技術是為了什麼而來的,解決什麼痛點,沒有體驗一下刀耕火種的時代,又沒有一個良好的團隊合作能力,做起專案來還真的不一定是“寫頁面太簡單了”這種事情。
1. 一些實踐方案深入淺出
1.1 padding
看到百度的頂部,你會想到什麼方案呢?
我們看百度搜尋的頂部,頂部的#head(搜尋框這一行都是)是fixed的,緊接著的那個div是一個tab。當然fixed脫離文字流,就用padding把自己的主要內容頂到下面去,不然內容就直接置頂了。
沒錯,就是很簡單的一個css,實現的方法有很多。然後我們再看一下這個視覺效果要怎麼實現:
img+脫離文字流的方法?雙div+定位?其實,一個div+padding馬上解決,div背景100%然後center+padding-top,div裡面的文字就自然到下面去了,然後定位定準就好了。另外,文字換成偽元素也可以。
控制寬高比
一些人也知道,padding的百分比相對於width,那麼這樣就可以實現了一個等比例的盒子,然後隨便縮放都可以了。比如做一個正方形,邊長是螢幕寬度一半:
.scale50 {
background: #aaa;
width: 50%;
height: 0;
text-align: center;
padding-top: 50%;
}
複製程式碼
很多時候,我們需要什麼4:3,16:9的圖片,就可以用這樣的方法解決了。
1.2 margin
再看看百度的右邊欄
對於這個欄的左邊部分,用margin還是padding呢?這個情況當然是padding,因為有一個邊線?。對於這個欄的上面,是padding還是margin呢?實際上,在這個情況下都是一樣的,但是有一個潛在問題:如果有兩行,而且垂直方向還有其他盒子的margin,那麼就會發生垂直方向的margin坍塌(取較大值);或者當有父盒子包裹,他的margin會走到外面影響外面。這時候,又要加上轉化為bfc的程式碼。
- case1:
- case2:
還敢亂來居中嗎
比如,有一個設計稿是這樣的:
可能看起來是居中,然後很快寫出來子絕父相的萬金油居中。然後設計突然走過來說,怎麼總是感覺有點不對啊,於是看一下下半部分: 真的不是居中啊,水平方向的也是。那麼,這時候,寫死margin不就搞定了,保證視覺不來找你。?...許多天後,測試說,某某手機視覺就出問題了。當然,寫死px肯定藥丸啊,所以移動端就是要用rem解決。我這裡一個rem等於50px,那換算一下,圖上第一個div(綠色的鉤)的margin就是176 148 0 151,換成rem是3.52 2.96 0 3.02,後面的樣式問題只要不是橫屏或者ipad的(無視覺稿的前提)都不是你的鍋了。
負的margin
正的就是撐開整個margin-box,那負的我們就可以想象出來,吃掉這個margin-box。一般的情況下,就是平移。如果加上了float就神奇了,還能跨行平移。雙飛翼和聖盃佈局其中一部分就是利用這個原理
前面都是廢話,不就是一個盒子模型嘛。沒錯,盒子模型,誰都知道,但是用起來誰用的好,這就難說了
2. 開始試試水
接下來,準備用n種方法實現三列布局,中間自適應,兩邊固定寬度
絕對定位
html:
<div class="container">
<div class="m">中間</div>
<div class="l">左邊</div>
<div class="r">右邊</div>
</div>
複製程式碼
css:
.container{
position: relative;
height: 100px;
}
.l, .m, .r {
height: 100px;
position: absolute;
}
.l {
background: #f00;
width: 100px;
}
.m {
background: #0f0;
width: calc(100% - 150px);
margin: 0 50px 0 100px;
}
.r {
background: #00f;
width: 50px;
right: 0;
}
複製程式碼
分析:不論順序,流式佈局,中間先載入,但用了calc
"calc?! 避免recalculate啊"
這時候,去吧,ie盒模型:
.m {
background: #0f0;
width: 100%;
box-sizing: border-box;
padding: 0 50px 0 100px;
}
複製程式碼
看一下對比:
聖盃與雙飛翼佈局
還是一樣的html
.container {
height: 100px;
width: 100%;
padding: 0 50px 0 100px;
}
.m, .l, .r {
height: 100px;
float:left;
}
.m {
background: #f00;
width: 100%;
}
.l {
background: #0f0;
width: 100px;
margin-left: -100%;
position: relative;
left: -100px;
}
.r {
background: #00f;
width: 50px;
margin-right: -50px;
}
複製程式碼
很多人說這個難懂,其實我們可以一步步來:先放好容器設好寬高背景,三個div是mlr順序。然後float,顯然m自己佔一行,其他兩個佔一行。
接著,用到負margin,先把左邊到移動一行,即是-100%,右邊就移動一個身位-50px就ok,現在已經是視覺上的3列。最後,中間部分開頭被遮住,而且佔了100%行寬。那麼我們只能用容器的padding或者自己的margin壓自己。 如果是用容器padding,將左右兩邊騰出來,剛剛好放下lr兩個div。最後,l和r還是在m裡面,所以還要移一下,relative就好。這就是聖盃佈局如果是用自己的margin壓自己,那麼就需要多一個div包住自己。前面步驟一樣,包住自己的div佔滿一行,但是自身有margin,完美解決。這就是雙飛翼佈局。圖示和上圖基本一模一樣,只是最外那層不是container而是m,真正的展示出來的中間部分是m裡面的div,另外,l和r也不用relative了。
<div class="m">
<div class="margin-setting">
中間
</div>
</div>
複製程式碼
這是傳統css+div的一套比較好的解決方案,不過我們愁的是高的問題了,需要自己設
float+calc
<div class="container">
<div class="l">左邊</div>
<div class="m">這是中間內容</div>
<div class="r">右邊</div>
</div>
複製程式碼
這次的html不能調換順序寫了
.container {
height: 100px;
width: 100%;
}
.m, .l, .r {
height: 100px;
float: left;
}
.m {
background: #f00;
width: calc(100% - 150px);
}
.l {
background: #0f0;
width: 100px;
}
.r {
background: #00f;
width: 50px;
}
複製程式碼
類似於前面的absolute方案,calc可以用ie盒子替代
行內元素
是不是遇到過行內元素總是有間隔的問題,html加註釋就可以去掉分隔符,當然這裡要實現3列布局:
<div class="l">左邊</div><!--
--><div class="m">中間</div><!--
--><div class="r">右邊</div>
複製程式碼
css:
.l, .m, .r {
height: 100px;
display: inline-block;
}
.l {
background: #f00;
width: 50px;
}
.m {
background: #0f0;
width: calc(100% - 150px);
}
.r {
background: #00f;
width: 100px;
}
複製程式碼
特點:樣式及其脆弱,內容換行馬上崩了,只能在沒文字的情況好一點。calc還是一樣的方法,ie盒子完美解決
兩個div實現三列
<div class="container" l="左邊">中間</div>
<div class="r">右邊</div>
複製程式碼
左邊的內容用attr抓
.container {
float: left;
height: 100px;
background: #f00;
}
.container::before {
content: attr(l);
display: block;
width: 100px;
float: left;
height: 100px;
background: #0f0;
}
.r {
height: 100px;
width: 50px;
float: left;
background: #00f;
margin-right: -100%;
}
複製程式碼
用content做的內容,註定了左邊不能再放html元素了
flex與grid
html還是按順序:
<div class="container">
<div class="l">左邊</div>
<div class="m">這是中間內容
</div>
<div class="r">右邊</div>
</div>
複製程式碼
大家都知道的flex實現:
.container {
display: flex;
height: 100px;
}
.l {
background: #f00;
min-width: 100px;
}
.m {
background: #0f0;
}
.r {
background: #00f;
min-width: 50px;
}
複製程式碼
不過,我更看好grid,符合程式設計師思維,一個配置,兩行程式碼,基本搞定大部分場景
.container {
display: grid;
grid-template-columns: 100px auto 50px;
grid-template-rows: 100px;
}
.container div:nth-of-type(1) {
background: #f00;
}
.container div:nth-of-type(2) {
background: #0f0;
}
.container div:nth-of-type(3) {
background: #00f;
}
複製程式碼
一個div實現
css:
div {
background: #f00;
height: 100px;
margin: 0 50px 0 100px;
position: relative;
}
div::before {
content: '左邊';
display: block;
background: #0f0;
height: 100px;
width: 100px;
position: absolute;
left: -100px;
}
div::after {
content: '右邊';
display: block;
background: #00f;
height: 100px;
width: 50px;
position: absolute;
right: -50px;
top: 0;
}
複製程式碼
當然,只是娛樂而已,專案上誰會寫這個。某些小裝飾可能有機會上
又瞎搞一堆亂七八糟的,先冷靜一下
我的部落格即將同步至騰訊雲+社群,邀請大家一同入駐:cloud.tencent.com/developer/s…