此文已由作者鄭海波授權網易雲社群釋出。
歡迎通路網易雲社群,了解更多網易技術産品營運經驗
一、前言
雖然首頁沒有開始做,昨天仍決定将[MCSS](https://github.com/NetEaseWD/mcss)從身邊的基友們開始向杭研推廣了,從開始做這個直到現在推廣遇到最多的問題是:
> __不是有LESS了嗎?__
這個問題回答了很多遍了,但是覺得回答的都不夠好,是以覺得寫一篇文章解釋一下。其實很多答案也都可以從基于MCSS封裝的函數庫[mass](https://github.com/leeluolee/mass)中得到解答,本文針對MCSS的例子都可以在這個[Try-Page](http://leeluolee.github.io/mcss/)中進行嘗試。
<!-- more -->
-------------------
二、LESS特性在MCSS中的對應
首先解答下LESS的特性在MCSS中的對應,這幾乎也囊括了在實際生産使用時的80%的功能(實際生産并不包含基礎類庫封裝)
1. 嵌套
MCSS與LESS等其它預處理器的嵌套規則完全一緻,支援`&`占位符,例如:
```
.m-home{
display: block;
div, ul{
+ div{
margin-top: 20px;
}
border: 2px solid #ccc;
> a{
color: #fff;
&:hover{
text-decoration: none;
}
~ span{
display: block;
}
}
}
}
```
MCSS同時支援另一個占位符`%`,與`&`類似,但它不包含頂級的選擇器
比如有時候,我們需要在`.ms-form`的擴充類`.ms-form-stack`中修改某層節點的樣式,這時我們不需要重新重複一次書寫,例如
```
.ms-form{
input[type="text"],
input[type="password"],
input[type="email"],
input[type="url"],
select{
display: inline-block;
.ms-form-stack %{
display: block;
}
}
// other ruleset
}
```
__outport__
```css
.ms-form input[type="text"],
.ms-form input[type="password"],
.ms-form input[type="email"],
.ms-form input[type="url"],
select{
display:inline-block;
}
.ms-form-stack input[type="text"],
.ms-form-stack input[type="password"],
.ms-form-stack input[type="email"],
.ms-form-stack input[type="url"],
select{
display:block;
}
```
__另外MCSS也可以進行`@media`的條件嵌套__
2. 變量
變量是CSS Preprocessor的最基本功能,LESS的變量占用了CSS規範中的[at-keyword](http://dev.w3.org/csswg/css-syntax/#at-rule-diagram) (例如`@name`)并以`:`作為分隔, 例如
@name: 10px;
而在MCSS中,變量的聲明是以為`dollar-name`(如`$name`)作為标志
$name = 10px;
__WHY?__
1. __避免沖突__:
LESS由于占用`@`, 達到了在詞法上與css一緻,成就了它看起來最像CSS的美譽,事實上從文法角度講,LESS可以說是最不規範的,因為它占用了`@at-keyword`, 在css中@at-keyword是作為[`@at-rule`](http://dev.w3.org/csswg/css-syntax/#at-rule-diagram)開始的标志, 這就有潛在沖突的可能性,并且也不利于未來功能的擴充(mcss中所有的功能擴充都是通過自定義@atrule)
2. __指派符擴充__:
除了`=`,MCSS中有另外兩種指派符号:
1. `?=`: 指派操作隻在變量不存在時進行,例如:
```
$effect-outport = true;
$effect-outport ?= false;
```
此時第二個指派無效
2. `^=`: 它可以将指派定義在全局作用域,MCSS與LESS一樣有作用域,是以有時候需要跳脫作用域限制時,這個指派符就起作用了
$global = 10px;
p{
$global ^= 20px;
}
```
以上兩個指派符其實都在函數封裝時會常用到。
###3. mixin函數
LESS中的`mixin`跟`ruleset`是一緻的,不過可以帶上操作,例如
```
.size(@width, @height){
width: @width
}
//使用時
p{
.size(20px, 40px);
}
```
而在MCSS中,函數可以達到同樣效果。首先了解下MCSS中函數的書寫方式,與LESS的mixin一樣,一個函數可以有參數,也可以沒有,同時在MCSS中,函數是一種值類型,同樣可以通過指派操作進行定義,例如:
```
// 帶參數
size=(width, $height){
height?=width; // ?= 操作符的作用場景一
height: $height;
width: $width;
}
// 不帶參數
$clearfix = {
*zoom: 1;
&:before, &:after {
display: table;
content: "";
line-height: 0;
}
&:after {
clear: both;
}
}
```
使用時候,你可以用類似的括号來調用,也可以用所謂的`隐式調用`, 比如:
```
body{
$clearfix(); //正常調用
$size: 5px; //設定寬高的隐式調用
}
```
__輸出__
```
body{
*zoom:1;
height:5px;
width:5px;
}
body:before,body:after{
display:table;
content:"";
line-height:0;
}
body:after{
clear:both;
}
``
__需要注意的是,MCSS中的函數是一種真正的值類型,它可以被傳遞進函數,也可以被函數傳回(或用`^=`操作符定義在全局),并保留作用域——所謂閉包__,這不僅僅是個文法糖,使得MCSS擁有其它預處理器沒有封裝能力!。比較近的例子可以檢視MCSS的官方函數庫[mass的effect.mcss](https://github.com/leeluolee/mass#effect),利用它,你可以封裝出類似`$swing`的函數,并且可以傳入參數進行效果調整。
```
@import 'https://rawgithub.com/leeluolee/mass/master/mass/effect.mcss';
$swing(24deg);
```
__Outport__
```css
body{
-webkit-backface-visibility:hidden;
}
.animated{
-webkit-animation-duration:1s;
-moz-animation-duration:1s;
animation-duration:1s;
-webkit-animation-fill-mode:both;
-moz-animation-fill-mode:both;
animation-fill-mode:both;
}
@-webkit-keyframes swing{
20%,40%,60%,80%,100%{
-webkit-transform-origin:top center;
}
20%{
-webkit-transform:rotate(24deg);
}
40%{
-webkit-transform:rotate(-16deg);
}
60%{
-webkit-transform:rotate(8deg);
}
80%{
-webkit-transform:rotate(-8deg);
}
100%{
-webkit-transform:rotate(0deg);
}
}
@-moz-keyframes swing{
20%{
-moz-transform:rotate(24deg);
}
40%{
-moz-transform:rotate(-16deg);
}
60%{
-moz-transform:rotate(8deg);
}
80%{
-moz-transform:rotate(-8deg);
}
100%{
-moz-transform:rotate(0deg);
}
}
@-o-keyframes swing{
20%{
-o-transform:rotate(24deg);
}
-o-transform:rotate(-16deg);
}
60%{
-o-transform:rotate(8deg);
}
80%{
-o-transform:rotate(-8deg);
}
100%{
-o-transform:rotate(0deg);
}
}
@keyframes swing{
20%{
transform:rotate(24deg);
}
40%{
transform:rotate(-16deg);
}
60%{
transform:rotate(8deg);
}
80%{
transform:rotate(-8deg);
}
100%{
transform:rotate(0deg);
}
}
.animated.swing{
-webkit-animation-name:swing;
-moz-animation-name:swing;
animation-name:swing;
-webkit-transform-origin:top center;
-moz-transform-origin:top center;
-ms-transform-origin:top center;
-o-transform-origin:top center;
transform-origin:top center;
}
```
這個不僅僅是LESS,是所有其它預處理器沒有的能力!
4. 顔色函數
mcss支援hsl以及hsla的色值格式,最終會被輸出為rgba或者`#ccc`
與LESS不同的是,MCSS不提供類似`lighten`等動詞的函數,統一為rgb概念中的red、green、 blue 和 hsl概念中 的hue、saturation、lightness 以及alpha 這7個通道的調節,函數名分别為`r-adjust`,`g-adjust`,`b-adjust`,`h-adjust`,`s-adjust`,`l-adjust`,`a-adjust` 全部支援相對和絕對調節
比如LESS中`lighten`、`darken`其實就是lightness的相對調節
```
@color1: lighten(#ccc, 10%);
@color2: darken(#ccc, 10%);
```
在MCSS其實就是
```
$color1 = l-adjust(#ccc, 10%); //往亮調
$color2 = l-adjust(#ccc, -10%); // 往暗調節
```
是以MCSS的色值函數需要你對hsl顔色格式有一定的了解(前端開發應該這是必備的基礎概念吧)
5. 操作符
MCSS支援所有LESS的操作符(或者說其實MCSS支援JS中的二進制以及以下的所有操作符,并且優先級與JS完全一緻)
三、一些LESS所欠缺的能力
1.邏輯控制`@for`、`@if、@elseif、@else`
由于LESS占用了`@at-keyword`,是以很難提供類似的語言功能。LESS提供一個在選擇器上的擴充`when`但是能力仍然有限。
2.`@extend`
mixin函數可以幫助我們實作代碼片的複用,但是有個巨大的問題就是,mixin會讓代碼變得龐大(可以看看基于less的bootstrap的重複樣式),當有明顯的派生關系時,我們可以使用`@extend`,`@extend`是一個源于SASS的概念,它會将派生類的選擇器添加到基礎類之後。
```
.u-ipt {
padding: 5px 10px;
box-shadow: inset 1px 1px 3px rgba(0,0,0,0.3);
}
.m-form{
input[type="text"],
input[type="password"]{
@extend .u-ipt;
}
}
```
__Outport__
```
.u-ipt,
.m-form input[type="text"],
.m-form input[type="password"]
padding:5px 10px;
box-shadow:inset 1px 1px 3px rgba(0,0,0,0.3);
}
```
沒有參數的`mixin`其實都可以用`@extend`來實作(但`@extend`一般用在有明顯派生關系的ruleset),MCSS支援多重`@extend`以及嵌套`@extend`,具體請檢視MCSS首頁
3.`@abstract`
由于元件封裝時,我們無法知道後續是否需要某個ruleset,`@abstract`這個@atrule的作用是,将一個或多個ruleset标記為不輸出,但是仍然可以被派生。
```
//标記一個ruleset
@abstract btn{
left: 10px
}
//标記一整個塊
@abstract {
.btn{
}
.fbtn{
}
}
```
你也可以抽象一整個檔案, 它是`@import` 的抽象版
```
@abstract 'ui.mcss';
```
比如在團隊開發時,`ui.mcss`已經被公有樣式`base.mcss` import了(即會被所有頁面所共用),但是後續的頁面中仍然需要使用ui.mcss的變量、函數或者ruleset,此時`@abstract出現了`;__ui.mcss__
```
// btn的mixin函數
$btn = {
padding: 10px
}
// ui中的ruleset
.u-btn{
}
```
__base.mcss__
使用`@import` 會引入`ui.mcss`中的樣式
```
@import ui.mcss
```
__page1.mcss__
使用`@absctract`,你不會引入任何樣式, __但是你仍然可以使用檔案中的變量、函數和派生`ui.mcss`中的ruleset__
```
@abstract 'ui.mcss';
.u-btn-2{
@extend .u-btn; // 仍然可以@extend
$btn(); // 仍然可以使用變量、函數
}
```
這樣可以解決團隊開發中的問題。一套代碼完全取決于`@import`、`@abstract`和`@media`三者的調用會有不同的表現。
4.更好的出錯資訊以及sourcemap
在出現文法錯誤時,MCSS會給你更精确的資訊

同時sourcemap v3格式開始被chrome的developer tool的支援,MCSS也支援(需開啟MCSS sourcemap選項,并在chrome的開發者工具的實驗特性)

5. MCSS指令行工具
相對于其他預處理器MCSS的指令行工具參數很簡單,并且提供了代碼的多種輸出格式,以及自動編譯的功能,基本上你已經無需其它工具的支援。具體請`npm install -g mcss` 并且`mcss -h` 一下
-----------------------------
四、結尾感言
LESS的成功來源于它的`簡單`,成功的闡述了`82法則`,同時也起到了普及CSS預處理器的作用,事實上接觸并且熟悉了LESS的那些概念之後,接受MCSS或者SCSS都是比較輕松的事情。
如果覺得LESS無法滿足你的需求時
> __npm install -g mcss__ 嘗試一下吧!
_同時MCSS是個易用的CSS Parser哦_
<br/>
免費領取驗證碼、内容安全、短信發送、直播點播體驗包及雲伺服器等套餐
更多網易技術、産品、營運經驗分享請點選。
相關文章:
【推薦】 流式處理架構storm淺析(下篇)
【推薦】 細嚼慢咽 Mongoose 5