css菜雞的自我救贖
作為一個不喜歡寫樣式的前端,遇到了直接對外的活動頁面的需求,一下炸出一堆問題:
- 單位亂用,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,因為有一個邊線:blush:。對於這個欄的上面,是padding還是margin呢?實際上,在這個情況下都是一樣的,但是有一個潛在問題:如果有兩行,而且水平方向還有其他盒子的margin,那麼就會發生水平方向的margin坍塌(取較大值);或者當有父盒子包裹,他的margin會走到外面影響外面。這時候,又要加上轉化為bfc的程式碼。
- case1:
- case2:
還敢亂來居中嗎
比如,有一個設計稿是這樣的:

可能看起來是居中,然後很快寫出來子絕父相的萬金油居中。然後設計突然走過來說,怎麼總是感覺有點不對啊,於是看一下下半部分:

真的不是居中啊,水平方向的也是。那麼,這時候,寫死margin不就搞定了,保證視覺不來找你。
:bird:...許多天後,測試說,某某手機視覺就出問題了。當然,寫死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 id="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,完美解決。這就是雙飛翼佈局。
<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; } 複製程式碼
當然,只是娛樂而已,專案上誰會寫這個。某些小裝飾可能有機會上
又瞎搞一堆亂七八糟的,先冷靜一下