天天看點

LESS+to+MCSS

此文已由作者鄭海波授權網易雲社群釋出。

歡迎通路網易雲社群,了解更多網易技術産品營運經驗

一、前言

雖然首頁沒有開始做,昨天仍決定将[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會給你更精确的資訊

![error圖](https://github-camo.global.ssl.fastly.net/9b3c4a1accf639b9dffbc877275e3e6cca9360c7/687474703a2f2f6c65656c756f6c65652e6769746875622e696f2f6d6373732f696d672f6572726f722e706e67)

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

![sourcemap](https://github-camo.global.ssl.fastly.net/8933d6c727f1461fbab5592eb48e0e3d778d324c/687474703a2f2f6c65656c756f6c65652e6769746875622e696f2f6d6373732f696d672f736d2e706e67)

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