此文已由作者郑海波授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验

一、前言

虽然首页没有开始做,昨天仍决定将[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等其它预处理器的嵌套规则完全一致,支持`&`占位符,例如:

```

  1. .m-home{
  2.     display: block;
  3.     div, ul{
  4.         + div{
  5.             margin-top: 20px;
  6.         }
  7.         border: 2px solid #ccc;
  8.         > a{
  9.             color: #fff;
  10.             &:hover{
  11.                text-decoration: none;
  12.             }
  13.             ~ span{
  14.                 display: block;
  15.             }
  16.         }
  17.     }
  18. }
  19. ```

MCSS同时支持另一个占位符`%`,与`&`类似,但它不包含顶级的选择器

比如有时候,我们需要在`.ms-form`的扩展类`.ms-form-stack`中修改某层节点的样式,这时我们不需要重新重复一次书写,例如

  1. ```
  2. .ms-form{
  3.     input[type="text"],
  4.     input[type="password"],
  5.     input[type="email"],
  6.     input[type="url"],
  7.     select{
  8.       display: inline-block;
  9.       .ms-form-stack %{
  10.         display: block;
  11.       }
  12.     }
  13.     // other ruleset
  14. }
  15.  
  16. ```
  17. __outport__
  18.  
  19. ```css
  20. .ms-form input[type="text"],
  21. .ms-form input[type="password"],
  22. .ms-form input[type="email"],
  23. .ms-form input[type="url"],
  24. select{
  25.   display:inline-block;
  26. }
  27. .ms-form-stack  input[type="text"],
  28. .ms-form-stack  input[type="password"],
  29. .ms-form-stack  input[type="email"],
  30. .ms-form-stack  input[type="url"],
  31. select{
  32.   display:block;
  33. }
  34. ```

__另外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. `?=`: 赋值操作只在变量不存在时进行,例如:

```

  1.     $effect-outport = true;
  2.  
  3.     $effect-outport ?= false;
  4.  
  5.     ```

此时第二个赋值无效

2. `^=`: 它可以将赋值定义在全局作用域,MCSS与LESS一样有作用域,所以有时候需要跳脱作用域限制时,这个赋值符就起作用了

```

  1.     $global = 10px;
  2.     p{
  3.       $global ^= 20px;
  4.     }
  5.     ```

以上两个赋值符其实都在函数封装时会常用到。

  1. ###3. mixin函数
  2. LESS中的`mixin``ruleset`是一致的,不过可以带上操作,例如
  3. ```
  4. .size(@width, @height){
  5.   width: @width
  6. }
  7. //使用时
  8. p{
  9. .size(20px, 40px);
  10. }
  11. ```

而在MCSS中,函数可以达到同样效果。首先了解下MCSS中函数的书写方式,与LESS的mixin一样,一个函数可以有参数,也可以没有,同时在MCSS中,函数是一种值类型,同样可以通过赋值操作进行定义,例如:

  1. ```
  2. // 带参数
  3. size=(width, $height){
  4.     height?=width; // ?= 操作符的作用场景一
  5.     height: $height;
  6.     width: $width;
  7. }
  8. // 不带参数
  9. $clearfix = {
  10.     *zoom: 1;
  11.     &:before, &:after {
  12.         display: table;
  13.         content: "";
  14.         line-height: 0;
  15.     }
  16.     &:after {
  17.         clear: both;
  18.     }
  19. }
  20. ```

使用时候,你可以用类似的括号来调用,也可以用所谓的`隐式调用`, 比如:

  1. ```
  2. body{
  3.     $clearfix(); //正常调用
  4.     $size: 5px;  //设置宽高的隐式调用
  5. }
  6. ```

__输出__

  1. ```
  2. body{
  3.   *zoom:1;
  4.   height:5px;
  5.   width:5px;
  6. }
  7. body:before,body:after{
  8.   display:table;
  9.   content:"";
  10.   line-height:0;
  11. }
  12. body:after{
  13.   clear:both;
  14. }
  15.  
  16. ``

__需要注意的是,MCSS中的函数是一种真正的值类型,它可以被传递进函数,也可以被函数返回(或用`^=`操作符定义在全局),并保留作用域——所谓闭包__,这不仅仅是个语法糖,使得MCSS拥有其它预处理器没有封装能力!。比较近的例子可以查看MCSS的官方函数库[mass的effect.mcss](https://github.com/leeluolee/mass#effect),利用它,你可以封装出类似`$swing`的函数,并且可以传入参数进行效果调整。

  1. ```
  2. @import 'https://rawgithub.com/leeluolee/mass/master/mass/effect.mcss';
  3. $swing(24deg);
  4. ```
  5. __Outport__
  6. ```css
  7. body{
  8.   -webkit-backface-visibility:hidden;
  9. }
  10. .animated{
  11.   -webkit-animation-duration:1s;
  12.   -moz-animation-duration:1s;
  13.   animation-duration:1s;
  14.   -webkit-animation-fill-mode:both;
  15.   -moz-animation-fill-mode:both;
  16.   animation-fill-mode:both;
  17. }
  18. @-webkit-keyframes swing{
  19.   20%,40%,60%,80%,100%{
  20.     -webkit-transform-origin:top center;
  21.   }
  22.   20%{
  23.     -webkit-transform:rotate(24deg);
  24.   }
  25.   40%{
  26.     -webkit-transform:rotate(-16deg);
  27.   }
  28.   60%{
  29.     -webkit-transform:rotate(8deg);
  30.   }
  31.   80%{
  32.     -webkit-transform:rotate(-8deg);
  33.   }
  34.   100%{
  35.     -webkit-transform:rotate(0deg);
  36.   }
  37. }
  38. @-moz-keyframes swing{
  39.   20%{
  40.     -moz-transform:rotate(24deg);
  41.   }
  42.   40%{
  43.     -moz-transform:rotate(-16deg);
  44.   }
  45.   60%{
  46.     -moz-transform:rotate(8deg);
  47.   }
  48.   80%{
  49.     -moz-transform:rotate(-8deg);
  50.   }
  51.   100%{
  52.     -moz-transform:rotate(0deg);
  53.   }
  54. }
  55. @-o-keyframes swing{
  56.   20%{
  57.     -o-transform:rotate(24deg);
  58.   }
  59.     -o-transform:rotate(-16deg);
  60.   }
  61.   60%{
  62.     -o-transform:rotate(8deg);
  63.   }
  64.   80%{
  65.     -o-transform:rotate(-8deg);
  66.   }
  67.   100%{
  68.     -o-transform:rotate(0deg);
  69.   }
  70. }
  71. @keyframes swing{
  72.   20%{
  73.     transform:rotate(24deg);
  74.   }
  75.   40%{
  76.     transform:rotate(-16deg);
  77.   }
  78.   60%{
  79.     transform:rotate(8deg);
  80.   }
  81.   80%{
  82.     transform:rotate(-8deg);
  83.   }
  84.   100%{
  85.     transform:rotate(0deg);
  86.   }
  87. }
  88. .animated.swing{
  89.   -webkit-animation-name:swing;
  90.   -moz-animation-name:swing;
  91.   animation-name:swing;
  92.   -webkit-transform-origin:top center;
  93.   -moz-transform-origin:top center;
  94.   -ms-transform-origin:top center;
  95.   -o-transform-origin:top center;
  96.   transform-origin:top center;
  97. }
  98. ```

这个不仅仅是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的相对调节

  1. ```
  2. @color1: lighten(#ccc, 10%);
  3. @color2: darken(#ccc, 10%);
  4. ```

在MCSS其实就是

  1. ```
  2. $color1 = l-adjust(#ccc, 10%); //往亮调
  3. $color2 = l-adjust(#ccc, -10%); // 往暗调节
  4. ```

所以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的概念,它会将派生类的选择器添加到基础类之后。

  1. ```
  2. .u-ipt {
  3.   padding: 5px 10px;
  4.   box-shadow: inset 1px 1px 3px rgba(0,0,0,0.3);
  5. }
  6. .m-form{
  7.     input[type="text"],
  8.     input[type="password"]{
  9.       @extend .u-ipt;
  10.     }
  11. }
  12. ```
  13. __Outport__
  14. ```
  15. .u-ipt,
  16. .m-form input[type="text"],
  17. .m-form input[type="password"]
  18.   padding:5px 10px;
  19.   box-shadow:inset 1px 1px 3px rgba(0,0,0,0.3);
  20. }
  21. ```

没有参数的`mixin`其实都可以用`@extend`来实现(但`@extend`一般用在有明显派生关系的ruleset),MCSS支持多重`@extend`以及嵌套`@extend`,具体请查看MCSS主页

3.`@abstract`

由于组件封装时,我们无法知道后续是否需要某个ruleset,`@abstract`这个@atrule的作用是,将一个或多个ruleset标记为不输出,但是仍然可以被派生。

  1. ```
  2. //标记一个ruleset
  3. @abstract btn{
  4.   left: 10px
  5. }
  6. //标记一整个块
  7. @abstract {
  8.   .btn{
  9.   }
  10.   .fbtn{
  11.   }
  12. }
  13. ```

你也可以抽象一整个文件, 它是`@import` 的抽象版

  1. ```
  2. @abstract 'ui.mcss';
  3. ```

比如在团队开发时,`ui.mcss`已经被公有样式`base.mcss` import了(即会被所有页面所共用),但是后续的页面中仍然需要使用ui.mcss的变量、函数或者ruleset,此时`@abstract出现了`;__ui.mcss__

  1. ```
  2. // btn的mixin函数
  3. $btn = {
  4.   padding: 10px
  5. }
  6. // ui中的ruleset
  7. .u-btn{
  8. }
  9. ```

__base.mcss__

使用`@import` 会引入`ui.mcss`中的样式

  1. ```
  2. @import ui.mcss
  3.  
  4. ```

__page1.mcss__

使用`@absctract`,你不会引入任何样式, __但是你仍然可以使用文件中的变量、函数和派生`ui.mcss`中的ruleset__

  1. ```
  2. @abstract 'ui.mcss';
  3. .u-btn-2{
  4.   @extend .u-btn; // 仍然可以@extend
  5.   $btn();         // 仍然可以使用变量、函数
  6. }
  7. ```

这样可以解决团队开发中的问题。一套代码完全取决于`@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

LESS+to+MCSS的更多相关文章

  1. 解决mac os下mcss命令报错:env: node\r: No such file or directory

    标题无“转载”即原创文章,版权所有.转载请注明来源:http://besteam.im/blogs/article/31/. 我一直对字符界面有抵触感,即使会用vim,我的linux脚本(python ...

  2. es6+react环境搭建

    工具说明 Node Koa React Webpack 项目结构 - build 客户端代码的构建文件目录 - config 项目的配置文件 - docs 项目相关的文档目录 - lib 服务端库文件 ...

  3. LTE Module User Documentation(翻译7)——无线环境地图(REM)、AMC 模型 和 CQI 计算

    LTE用户文档 (如有不当的地方,欢迎指正!) 12 Radio Environment Maps   通过使用类 RadioEnvironmentMapHelper  是可能输出文件 Radio E ...

  4. Unieap3.5Java端通过SQL语句直接查询DataStore

    通过sql查询dataStore 例子见 /mcss/src/com/neusoft/mcss/base/todo/dao/WorkTodoDaoImpl.java getWorksTodo() ID ...

  5. Unieap3.5-前台js用SQL语句执行数据请求

    执行UPDATE var sql=" update T_SS_SETTLEMENT_RECORD "+ " set CINVOICE_INFO_FLAG='Y',&quo ...

  6. 构建前端Mock Server

    写在前面 最开始只是在做活动页面时苦于效率太低制定了这样一个自动化的工作环境, 所以Github上项目名是Rapid-Dev-Activity-Page(快速开发活动页...). 活动页这类比较简单的 ...

  7. 移动web屏幕适配方案

    刚进部门就被拉去趟移动端Web的浑水,视觉稿是按照640px设计的.那如何做屏幕适配呢?当然想到的第一方法就是问前辈了,问他们之前怎么做的,前辈说直接按视觉稿来,我说640太大了,他说除以2啊,按32 ...

  8. grunt -- javascript自动化工具

    grunt 是一个基于npm,node.js 用js编写的工具框架,可以自动完成一些重复性的任务(如合并文件,语法检查,压缩代码), grunt拥有庞大的插件库,可以满足各种自动化批处理需求,常用的插 ...

  9. JavaEE学习之Spring声明式事务

    一.引言 上一篇文章,学习了AOP相关知识,并做了一个简单的Hello world.本文在上篇文章的基础上,进一步学习下Spring的声明式事务. 二.相关概念 1. 事务(Transaction)— ...

随机推荐

  1. MyEclipse8.6启动后提示内存不足的解决方案(亲测,完美解决)

    转自:http://www.bubuko.com/infodetail-1625857.html 最近可能由于公司项目大了,启动MyEclipse后经常提示内存不足的警告框,如下: 其实点击close ...

  2. C++Builder 内存泄露检测

    C++Builder 内存泄露检测 CodeGuard http://bbs.2cto.com/read.php?tid=179933 XE新版里 ReportMemoryLeaksOnShutdow ...

  3. 在WebBrowser中发送POST请求

    我们要用到的也是WebBrowser的“Navigate”方法,其函数原型如下所示: Sub Navigate(URL As String, [Flags], [TargetFrameName], [ ...

  4. C++全总结

    // CPPTEST.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include & ...

  5. 【330】word - VBA 相关实现

    参考:Object model (Word VBA reference) 序号 类名称   功能说明   语法 & 举例 01 Selection   ====<<<< ...

  6. kafka启动报java.net.UnknownHostException

    kafka启动报java.net.UnknownHostException 参考资料: 1.https://blog.csdn.net/zdxiq000/article/details/6258765 ...

  7. Docker简介及基本应用

    Docker 前言 1.虚拟化 在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器.网络.内存及存储等,予以抽象.转换后呈现出来,打破实体结 ...

  8. 录制手机的视频,转换成gif

    Android: 通过adb命令去进行录屏,然后将录制的视频转换成gif图片: 前提:确保电脑上安装了adb,且Android的level高于19. 1.adb shell screenrecord ...

  9. docker 容器创建参数错误记录

    sudo docker ps -a -q sudo docker ps -a|cutawk '{print $1}' #删除前八条 sudo docker ps -a -q|head -n |xarg ...

  10. archiver error. Connect internal only, until freed. 之解决办法

    这个报错说的是数据库的日志备份不足空间.解决办法: DELETE backup COMPLETED BEFORE 'SYSDATE-7';DELETE ARCHIVELOG ALL COMPLETED ...