css菜雞的自我救贖

lhyt發表於2018-10-15

0. 前言

作為一個不喜歡寫樣式的前端,遇到了直接對外的活動頁面的需求,一下炸出一堆問題:

  • 單位亂用,rem、vh、vw、px亂用甚至混在一起用
  • html冗餘,有時候一個div只是為了取margin
  • 一個頁面用多種佈局方案,flex、float、relative+top、absolute+top、margin,自己坑自己
  • 各種隨意,不嚴格按照視覺稿 理論倒是熟悉,但用起來還是一塌糊塗。於是,回頭自我救贖一波,好好複習基礎。flex、grid後面不多作研究,尤其是grid這種一兩行就可以搞定很多複雜樣式。如果我們不知道新技術是為了什麼而來的,解決什麼痛點,沒有體驗一下刀耕火種的時代,又沒有一個良好的團隊合作能力,做起專案來還真的不一定是“寫頁面太簡單了”這種事情。

1. 一些實踐方案深入淺出

1.1 padding

看到百度的頂部,你會想到什麼方案呢?

css菜雞的自我救贖

我們看百度搜尋的頂部,頂部的#head(搜尋框這一行都是)是fixed的,緊接著的那個div是一個tab。當然fixed脫離文字流,就用padding把自己的主要內容頂到下面去,不然內容就直接置頂了。

沒錯,就是很簡單的一個css,實現的方法有很多。然後我們再看一下這個視覺效果要怎麼實現:

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

再看看百度的右邊欄

css菜雞的自我救贖

對於這個欄的左邊部分,用margin還是padding呢?這個情況當然是padding,因為有一個邊線?。對於這個欄的上面,是padding還是margin呢?實際上,在這個情況下都是一樣的,但是有一個潛在問題:如果有兩行,而且垂直方向還有其他盒子的margin,那麼就會發生垂直方向的margin坍塌(取較大值);或者當有父盒子包裹,他的margin會走到外面影響外面。這時候,又要加上轉化為bfc的程式碼。

  • case1:
    image
  • case2:
    1

還敢亂來居中嗎

比如,有一個設計稿是這樣的:

css菜雞的自我救贖
可能看起來是居中,然後很快寫出來子絕父相的萬金油居中。然後設計突然走過來說,怎麼總是感覺有點不對啊,於是看一下下半部分:
css菜雞的自我救贖
真的不是居中啊,水平方向的也是。那麼,這時候,寫死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;
}
複製程式碼

看一下對比:

css菜雞的自我救贖

聖盃與雙飛翼佈局

還是一樣的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自己佔一行,其他兩個佔一行。

css菜雞的自我救贖
接著,用到負margin,先把左邊到移動一行,即是-100%,右邊就移動一個身位-50px就ok,現在已經是視覺上的3列。最後,中間部分開頭被遮住,而且佔了100%行寬。那麼我們只能用容器的padding或者自己的margin壓自己。

css菜雞的自我救贖
如果是用容器padding,將左右兩邊騰出來,剛剛好放下lr兩個div。最後,l和r還是在m裡面,所以還要移一下,relative就好。這就是聖盃佈局

css菜雞的自我救贖

如果是用自己的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…

相關文章