color
也許你天天都在寫color: #xxx,但是,你是否還記得什么是color?你是不是第一反應(yīng):字體顏色。
如果是,很遺憾,color就是被你遺忘的CSS。
如果是,你是否曾想過,字體大小叫font-size,字體粗細叫font-weight,字體類型叫font-family……為何,偏偏字體顏色是color,而不是font-color呢?以及,font縮寫里為什么沒有color的位置?
一切只因color,不是字體顏色。
color,更好的叫法應(yīng)該是foreground-color,前景色。前景色這個詞,在CSS里,應(yīng)該很陌生,基本不會被人叫出來,而與之相對的是background-color,背景色。是的,這才是真正的color,與background-color相對的顏色。
問題就是,什么是前景色?不在背景上的顏色都是前景色。。。呵呵,有點放屁的感覺。
另外一個問題,哪些顏色是前景色?除了background-color,其他都是前景色。。。神經(jīng)病啊~~
好吧,除了background-color,有如下color是前景色:
- 字體顏色:并沒有font-color,只能通過color設(shè)定
- border-color:邊框顏色
- outline-color:輪廓顏色
- column-rule-color:列間邊框顏色
- text-decoration-color:下劃線顏色
- text-shadow:text-shadow中的顏色
- box-shadow:box-shadow中的顏色
除了1以外,這些前景色和color是什么關(guān)系呢?聰明的你,一定猜得到。是的,默認值。
在沒有設(shè)定以上2~7的color值時,瀏覽器對這些顏色的計算值是color。
舉個粟子:
http://component.sankuai.com/component/@mtfe/atom-button#~simpl

簡單看下其中一個填充色按鈕和描邊按鈕的CSS代碼:


對于這個組件,比如,我想要添加藍色填充按鈕和藍色描邊按鈕,那我需要為填充按鈕添加border-color和background-color,為描邊按鈕添加color和border-color,是否有更簡單的方式呢?答案是有。使用color就可以做到了。
<style>
.btn {
font-size: 20px;
padding: 1em 2em;
border-radius: 5px;
position: relative;
background-color: transparent;
outline: 0;
overflow: hidden;
border: 2px solid;
}
.btn.fill::after{
content: '';
box-sizing: border-box;
border-width: 2em;
border-style: solid;
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 0;
}
.btn.fill span {
color: white;
position: relative;
z-index: 1;
}
button.orange {
color: #f80;
}
.btn.green {
color: #06c1ae;
}
.btn.red {
color: #ec5300;
}
.btn.grey {
color: #d2d2d2;
}
</style>
<button class="btn orange fill"><span>按鈕0</span></button>
<button class="btn orange stroke">按鈕1</button>
<button class="btn green fill"><span>按鈕2</span></button>
<button class="btn green stroke">按鈕3</button>
<button class="btn red fill"><span>按鈕4</span></button>
<button class="btn red stroke">按鈕5</button>
<button class="btn grey fill"><span>按鈕6</span></button>
<button class="btn grey stroke">按鈕7</button>
border-style
使用border實現(xiàn)各類三角形,應(yīng)該是很多人都知道的小技巧。那使用border實現(xiàn)圓形、實現(xiàn)三橫線【照片4】,在Boostrap里做響應(yīng)式menu時可以看到)等呢?
簡單的一個圓形應(yīng)用:

我們看到,上下內(nèi)容之間,是有一條波浪分隔的,那如何實現(xiàn)這條波浪呢?
<style>
.up, .down {
height: 100px;
width: 100%;
position: relative;
padding:2em;
box-sizing: border-box;
}
.up {
background-color: #fecd0f;
color: #666;
}
.up::after {
content: '';
position: absolute;
bottom: -5px;
left: 0;
width: 100%;
border-bottom: 8px dotted white;
}
</style>
<div style="box-shadow:0 0 4px;width:250px;">
<div class="up">
上面的內(nèi)容在這里
</div>
<div class="down">
下面的內(nèi)容在這里
</div>
</div>
三橫線

的實現(xiàn):
<style>
.menu {
display: inline-block;
border-width: 9px;
border-bottom-style: double;
border-top: 3px solid;
border-color: #fecd0f;
width: 2em;
height: 3px;
}
</style>
<i class="menu"></i>
其他實現(xiàn):

<style>
.radio {
display: inline-block;
border: 9px double #fecd0f;
border-radius: 50%;
}
</style>
<i class="radio"></i>
錨點和:target
錨點,可以快速將頁面滾動至特定位置;:target選擇器可以選中當前錨點。
錨點定位是一種被忽略得很徹底的定位技術(shù),畢竟現(xiàn)在JS大行其道,前端總會有的沒的都寫幾行JS搞定,甚是方便。并不是說哪種好哪種壞,都沒有錯,“黑貓白貓,能抓到老鼠就是好貓”。
考慮一種場景,在手機端,使用Hybrid技術(shù)或Web頁面,如下圖:

當點擊底部價格旁邊的“明細”時,會出現(xiàn)如下蒙層

現(xiàn)在,有一個操作需要考慮:返回。返回有兩種方式:1. 點擊左上角的自定義的返回按鈕;2. 安卓用戶點擊手機自帶的返回按鈕。
當用戶返回時,最好的操作是僅關(guān)閉蒙層,顯示先前的頁面。要實現(xiàn)這樣的功能,方式1會相對簡單;方式2,對于Hybrid里通常會在JSBridge里直接添加一個“返回”的監(jiān)測功能,由Bridge去處理。
那問題是,真的需要這樣嗎?或者,如果它僅僅是Web頁面,沒有Hybrid的JSBridge怎么辦?
至少目前,JS沒辦法去監(jiān)聽系統(tǒng)級返回,而這時候,錨點和:target就可以很好的替我們實現(xiàn)這個功能了。
<style>
#click-target {
display: inline-block;
line-height: 3em;
width: 7em;
text-align: center;
background-color: #f80;
color: white;
outline: none;
}
.my-target {
position: fixed;
z-index: 10000;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, .8);
color: white;
transform: translateY(100%);
}
.my-target.width-animate-out {
transition: transform .2s ease-in-out;
}
.my-target:target {
transform: translateY(0);
}
</style>
<a href="#my-target" id="click-target">點一個</a>
<div id="my-target" class="my-target width-animate-out">哎呀,我彈出來了~~</div>
除了target具有“定位”功能外,input也是一個很好的定位Hack。有興趣的可以自行研究。
錨點當然有其問題,每個技術(shù)都有其適用場景。比如,錨點會產(chǎn)生歷史記錄,這是一個最需要考慮的問題了。其他的,你們用了就會發(fā)現(xiàn),這里不細說。
定時隱藏
通常,我們在處理頁面或某個操作的錯誤提醒時,都習(xí)慣性使用toast模式,會定個時,在特定時間后讓toast消失。對于前端來講,這是非常熟悉的應(yīng)用場景,我們的代碼也經(jīng)常是這樣的:
setTiimeout(function() {
? // 關(guān)閉嘍
? thatElement.style.display = 'none'
}, 1000)
拋開你已經(jīng)會的setTiimeout,是否可以想想,還有什么方法嗎?在CSS里,同樣存在著定時功能,只是我們通常會忽略,或者說我們沒有換個角度看。與時間有關(guān),CSS里是動畫。
是的,只是一個顯隱,一個transition或animation就可以做到了,只需要我們定義transition-delay或者animation-delay,這就是一個被我們忽略的定時。實現(xiàn)及代碼如下:
<style>
.toast-container {
position: relative;
border: 2px dashed #f33;
border-radius: .5em;
padding: 2.5em;
overflow: hidden;
}
.toast {
position: absolute;
top: -100%;
left: 0;
width: 100%;
text-align: center;
background: rgba(0, 0, 0, .7);
color: white;
pointer-events: none;
transition-property: top, opacity, transform;
transition-duration: .5s, 2s, .2s;
transition-delay: 0s, 1.5s, 3.5s;
transition-timing-function: ease-in-out;
transform: translateY(0);
opacity: 1;
padding: .5em 0;
}
#toast-trigger:checked ~ .toast {
top: 0;
opacity: 0;
transform: translateY(-100%);
}
</style>
<div class="toast-container">
<input type="checkbox" id="toast-trigger" />
<label for="toast-trigger">Show me toast</label>
<i class="toast">哈哈哈哈,我就是那個toast啊</i>
</div>
例子中使用的是transition,同樣的,你也可以使用animation去實現(xiàn)其他的定時任務(wù)。對于setInterval任何,我們只需要使用animation-iteration-count: infinite;即可。當然,太過復(fù)雜的定時任務(wù),還是使用setTimeout/setInterval或requestAnimationFrame會更好。還是那句話:各種技術(shù)都有其適用場景。
寬高等比縮放
在處理圖片時,我們有時候需要保證圖片的寬度和高度保持一定的比例R,當屏幕的寬度或者高度變化時,我們的圖片能夠按比例R進行縮放。比方說:
初始時,屏幕width = 1000px,圖片width = 屏幕width * 0.5 = 500px,height = 圖片width * 0.6 = 300px
縮放屏幕width = 800px,則按上述比例,需要圖片:width = 400px,height = 240px
比較笨的方法是:監(jiān)聽resize => 獲取屏幕寬度 => 計算出圖片寬高 => style賦值
這樣的方式,不僅笨,而且,很耗性能。不管是哪一步,都是相當耗性能的(性能相關(guān):瀏覽器渲染機制基礎(chǔ))
當一個功能有如下情況:
- 使用JS太耗性能
- 涉及太多樣式計算
時,你需要考慮是否可以使用CSS解決
放在這個場景上,既耗性能,又有太多計算,而且還是尺寸計算。監(jiān)聽resize,調(diào)用回調(diào),原本就是一個前端大忌。為此,可以想想,CSS能否解決呢?答案是肯定的。
這就涉及到另一個被我們遺忘的CSS了:padding和margin的百分比取值。
padding和margin是個很有意思的東西,而在取值上,它們卻給了我們一個不錯的玩法:(由于本例子中,我們只使用padding,以下只說padding)
當padding取值為百分比時,其計算值相對于包含塊的寬度
這是個很有趣的計算規(guī)則,意味著,我們的寬高等比縮放就可以完美得解決了。
首先,我們需要一個元素來定義寬高比:
<div style="width: 50%; padding-top: 30%; height: 0;"></div>
這里,我們將div的width定義為50%,這就是屏幕width * 0.5;然后,padding-top: 30%,這就是屏幕width * 0.3,正好等于圖片width * 0.6。這就是我們要的比例。而height: 0只是為了保證不被污染。
其次,我們需要一個子元素,讓它的寬高為100%,用于存放真正的content。
<div style="width: 50%; padding-top: 30%; height:0;">
<div style="width:100%;height:100%;">這里是Content</div>
</div>
很顯然,這樣我們只能得到如下的效果:(以下內(nèi)容比例做了調(diào)整并加了外框,請不要在意)

我們需要調(diào)整一下樣式,保證子元素能確切獲取父元素的寬高,由于我們的父元素沒有height,只有盒高,要獲得其盒高,就需要用到position。因此:
<div style="outline:1px dashed #f88;position:relative;width: 30%; padding-top: 150%; height:0;">
<div style="outline: 1px solid green;position:absolute;top:0;left:0;width:100%;height:100%;">這里是Content</div>
</div>
是的,我們給父元素添加position: relative,然后讓子元素相對于父元素絕對定位,這樣子元素就能切實獲取父元素的盒高了。處理后, 我們就得到了如下效果:

這樣,我們的寬高等比盒就OK了。
之前有人問:怎么讓padding的百分比按高度來計算。這就又涉及到一個幾乎不會被人使用的屬性了:writing-mode,這里就不再多說了。
禁用點擊
禁用點擊,指的是對用戶的點擊,不予響應(yīng)。在寫React時,我們經(jīng)常需要通過某個條件去判斷是否處理回調(diào)函數(shù)。比如:
<Demo onClick={evt => this.state.disabled ? null : this.demoClicked(evt)} />
這種通過碼方式來判斷,應(yīng)該是很常見的方式,這樣的禁用方式,我喜歡稱之為偽禁用。
實際上,我們可以用更簡便的方式來實現(xiàn)禁用,而且是真禁用。HTML里,禁用概念在表單元素里是十分常見的,我們會禁用一個checkbox,會禁用一個button,但是,我們又往往忘了,禁用button也就禁用了click事件的響應(yīng),這是一種真禁用。
對于上述的例子,我們可以更簡單的:
<button onClick={evt => this.demoClicked(evt)} disabled={this.state.disabled} />
前者我們關(guān)心的是點擊時候是否禁用了;而后者我們關(guān)心的是點擊是否禁用。從真正意義上講,后者才是合理的,所謂的職責分離。事件回調(diào)不應(yīng)該去處理狀態(tài),它只需要去響應(yīng)狀態(tài),狀態(tài)的維護交給組件處理。
表單相關(guān)
表單有很多的小巧運用,本文的篇幅已經(jīng)有點長了,就先這樣,下次續(xù)。