Mcss
writing modular css witch mcss
Install / Use
/learn @leeluolee/McssREADME
Writing abstract and modular CSS with MCSS
MCSS是一个CSS Preprocessor, 语法上基于CSS3 Syntax的超集, 提供 Nested Ruleset, Variable, first-class function(or mixin), custom atrule(@extend、@import、@abstract...)等等特性来填补原生CSS的抽象能力弱的缺陷, 帮助我们书写抽象化的CSS
MCSS是有丰富的语言特性的一个DSL, 它甚至允许扩展@atrule自定义解释策略; 与此同时MCSS是一个易用使用的CSS Parser, 并提供便利化的方式去操作树形结构, 以实现csscomb、prefixr等CSS工具.
MCSS完全使用javascript构建, 你可以分别在browser(ES5 support needed)和nodejs中使用它
目前主页正在建设中,这是临时性介绍页, 你可以先 动手试试
有兴趣可以查看下mcss的实例函数库(类似compass),你会发现几乎所有在mcss中都可以封装成函数的形势,如果你愿意
安装
Nodejs
npm install -g mcss
Browser
<script src="https://github.com/leeluolee/mcss/blob/master/dist/mcss-latest.js"></script>
需要支持ES5的浏览器,绝对只建议在线上环境使用compile后的css文件,而不是即时compile;
使用
API请参考(API使用指南)
命令行
一般就输入 mcss 输入目录或文件 -o 输出目录或文件 -w即可开启监听并编译了, 其他参数请参考mcss -h
ubuntu-10:12 ~ $ mcss -h
Usage: mcss [options] <file>
Options:
-h, --help print usage information
-v, --version print the version number
-f, --format <n> the outport format, 1: common | 2: compress | 3:online
-c, --config <file> the config filepath. [optional]
..........省略请输入 mcss -h 查看详情............
注意: 当file参数为文件夹时, 会compile目录下的所有.mcss文件, 此时outport参数会视为是一个文件夹, 并将所有css输入到此文件夹
####配置文件
当参数略多时,你会感觉筋疲力竭, 这时你可以建立一个配置的JSON文件, 其中JSON中的input参数代表输入文件 file, 其它与命令行打印的__参数全名__(比如format)一致 并使用-c 参数指定这个配置文件,默认情况下mcss会寻找 当前路径下的mcss.json 作为配置文件, 配置文件与命令的参数会进行合并(命令行优先)
{
"input": "./", //代表输入文件或目录
"outport": "../css", //输出目录(如果输入为单文件可以是一个具体的文件名)
"format": 1,
"watch": 2, //检测文件变化并build,并有报警声(1监听但无报警), 0为不watch
"exclude": "(\/|\\\\)_|^_|include"
}
注意: 使用config文件之后,程序的current word dir 切换到config文件的所在目录!!!
浏览器端
Browser环境时, 除了可以使用对应的API, mcss还会自动解释在mcss.js所在script标签前的所有style[type='text/mcss']与link[rel='stylesheet/mcss']的标签, 而其后的mcss文件不会生效. 如:
<link rel="stylesheet/mcss" href="test.mcss"/>
<style type = 'text/mcss'>
$color = #fff;
$border-radius = ($radius = 5px){
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
p{
border: 2px solid hsla(10, 90%, 21%, 0.1);
$border-radius: 5px;
}
</style>
<script src="../../dist/mcss-0.0.1.js"></script>
<link rel="stylesheet/mcss" href="test2.mcss"/>
其中test2.mcss不会生效
语言特性描述
了解特性之前,需要了解下mcss的基本数据类型(与css syntax对应) MCSS的数据类型
有时也需要了解下选择器的基本概念, 可以去nes的选择器科普页了解下
需要注意的是,由于mcss是css的超集, __ 标准css即标准mcss__
nested ruleset
mcss支持层级嵌套的ruleset以及 & (父引用符号)
<!-- {{nested_ruleset.mcss}} -->.m-home{
display: block;
div, ul{
+ div{
margin-top: 20px;
}
border: 2px solid #ccc;
> a{
color: #fff;
&:hover{
text-decoration: none;
}
~ span{
display: block;
}
}
}
}
输出
.m-home{
display:block;
}
.m-home div,.m-home ul{
border:2px solid #cccccc;
}
.m-home div + div,.m-home ul + div{
margin-top:20px;
}
.m-home div >a,.m-home ul >a{
color:#ffffff;
}
.m-home div >a:hover,.m-home ul >a:hover{
text-decoration:none;
}
.m-home div >a ~ span,.m-home ul >a ~ span{
display:block;
}
mcss支持另外一种预置符%, 代表除最外层选择器之外的选择器序列 如:
.ms-form{
// 真不想重复写这么多啊
input[type="text"],
input[type="password"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="range"],
select{
display: inline-block;
.ms-form-stack %{
display: block;
}
}
// other ruleset
}
输出
.ms-form input[type="text"],.ms-form input[type="password"],.ms-form input[type="email"],.ms-form input[type="url"],.ms-form input[type="date"],.ms-form input[type="month"],.ms-form input[type="time"],.ms-form input[type="range"],.ms-form 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"],.ms-form-stack input[type="date"],.ms-form-stack input[type="month"],.ms-form-stack input[type="time"],.ms-form-stack input[type="range"],.ms-form-stack select{
display:block;
}
和类似NEC的解决方案相契合
赋值操作
mcss中的variable与以 $ 开头(与SCSS一致如$length), 这也是mcss引入的唯一一个非css规范的词法类型, 目的是 防止潜在冲突 和 视觉上更易识别
mcss支持三种赋值操作^=, = 与 ?=, 其中?= 只在变量未赋值或null时生效, 所有的值类型都可以被赋值,包括函数, ^= 表示将赋值操作提升到全局作用域,
// $variable has scope
$a = 10px;
$a ?= 20px;
body{
left: $a; // exports left: 10px;
}
// override before
$a = 30px;
body{
left: $a; // exports left: 30px;
}
// function is also a value can be assigned
$fn ?= ($name) {
left: $name;
}
输出
body{
left:10px;
}
body{
left:30px;
}
由于mcss有严格作用域划分,所以有时候你想跳脱作用域限制时'^='这个赋值符可以解决一些封装的问题, 让几乎所有形式的组件都可以封装成函数的形式,比如
$import-raw = false;
$reset-var = (){
$import-raw ^= true; //这个会影响到外层
}
$reset-var();//调用
body{
left: $import-raw;
}
输出:
body{
left:true;
}
强大的function (mixin)
函数是mcss中除了css syntax中定义的值类型之外, 引入的唯一一种数据类型, 与js一样 mcss中的函数, 可以传递给函数,也可以在函数中被返回, 并保留定义时的作用域链(所谓的闭包)。
mcss中函数可以是一个block, 它可以有参数列表也可以没有
1. 作为mixin混入使用
当function没有返回值时,函数成为一个mixin, 会将解释后的 function block输出,实现SCSS中的@include, 这也是最常用的方式
// 带参数
$size = ($width, $height){
$height ?= $width;
height: $height;
width: $width;
}
// 不带参数, 可视为一个block模版
$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;
}
2. 作为函数使用
在解释function block时, 遇到了 @return 语句, 则中断返回. 注意返回值可以是另外一个函数. mcss 函数本质上与mcss的javascript实现的内建函数是一致的,优势是 不需要树节点操作 。并且维护在mcss file中更易模块化。
$abs = ($value){
@if $value < 0 {
@return -$value; }
@return $value;
}
$min = (){
$res = index($arguments, 0);
@for $item of $arguments{
@if $item < $res {
$res = $item; }}
@return $res;
}
@debug $min(1, 2, 3, 4, 0); // -> 0
@debug $abs(-100px); // 100px
3. transparent call
mcss支持类似 stylus 的transparent call (只适用于作为mixin使用的function)的调用方式
$border-radius = ($args...){
@if !len($args) {
error('$border-radius Requires at least one paramete')}
$value = join($args, ' / ');
-webkit-border-radius: $value;
-moz-border-radius: $value;
border-radius: $value;
}
body{
$border-radius: 10px 20px;
$border-radius: 10px 20px 100% , 20px;
}
输出为
body{
-webkit-border-radius:10px 20px;
-moz-border-radius:10px 20px;
border-radius:10px 20px;
-webkit-border-radius:10px 20px 100% / 20px;
-moz-border-radius:10px 20px 100% / 20px;
border-radius:10px 20px 100% / 20px;
}
4. 参数
mcss支持丰富的参数类型: rest param 以及 default param 、named param;
// 缺省值
$default-param = ($left, $right = 30px ){
default-param: $right;
}
// named param 一般用在大量default 只需要传入部分参数的情况下
$named-param = ($color = 30px, $named){
named: $named;
}
$rest-at-middle = ($left, $middle... , $right){
rest-at-middle: $middle;
}
$rest-at-left = ($left... , $right){
rest-at-left: $left;
}
$rest-at-right = ($left,$right...){
rest-at-right: $right;
}
body{
$named-param($named = 30px);
$default-param(10px);
$rest-at-middle(1, 2, 3, 4);
$rest-at-left(1, 2, 3, 4);
$rest-at-right(1, 2, 3, 4);
}
输出 :
body{
named: 30px;
default-param:30px;
rest-at-middle:2,3;
rest-at-left:1,2,3;
rest-at-right:2,3,4;
}
注意rest param 不能有默认值, 在参数有named param时 这个参数会被从参数列表中剔除,剩余的参数再进行赋值
5. 作为一种数据类型的函数
函数可以被传入函数, 也可以被函数返回. 并且保留当前完整作用域链
函数可以被返回:
$pos = ($position, $top, $left){
@if len($arguments) == 1{
// 返回函数
@return ($top, $left){
$pos($position, $top, $left);
}
}
position: $position;
left: $left;
top: $top;
}
$relative = $pos(relative);
$fixed = $pos(fixed);
$absolute = $pos(absolute);
body{
$absolute(10px, 20px);
// == $pos(relative, 10px, 20px);
}
输出:
body{
position:absolute;
left:20px;
top:10px;
}
6. $arguments以及其他
在进入function block时, mcss会在当前作用域定义一个变量叫$arguments(Type: valueslist), 代表传入的所有参数
mcss不支持类似arguments[0]下标操作, 不过你可以通过内建函数 args(0)来得到同样的效果
$foo = {
first: args(0);
seconed: args(1);
arguments: $arguments
}
body{
$foo: 10px, 20px
}
输出
body{
first:10px;
seconed:20px;
arguments:10px,20px;
}
注释
支持行注释// 和块注释/**/
Atrule
除了变量之外,所有的功能扩展,mcss都采用扩展@atkeyword的方式, 对于规范外的atrule(SCSS称之为directive)并且mcss也未定义, 开发者如果传入了对应的函数则根据传入函数的策略解释这个片段(), 否则按css基本规则输出(比如mcss中的-moz-document、charset等都没有进行定义 但是仍可以正确输出)
以下介绍: mcss中定义了的atruleset
@extend
继承由输入的complexselector指定的base ruleset, 表现为在在另一个base ruleset中组合进的selector.
@extend是css preprocessor中另一个较重要的特性,可以帮助我们缓解在html写入过多类名的泥潭
mcss中的@extend 有以下特性:
1. 需完整描述complex selector
这样做首先是为了避免歧义, 如:
.class-1 span{
name: class-1;
}
.body-1{
// need specify the full complex selector
// if only `span` will not work( but work in scss)
@extend .class-1 span;
}
输出:
.class-1 span,.body-1{
name:class-1;
}
2. 有作用域
与参数一样, 会优先获取内层作用域的的base ruleset, 并且只能使用定义过的base ruleset(也就是说无法后向引用), 这个是为了规避循环@extend;
class-1{
name: class-1 in global;
}
div.body-4, .other-body{
cl
