stylus的安装与使用

stylus介绍就不需要了,直接进入主题吧。

stylus的安装

此处只介绍sublime中使用stylus编译的安装方法,因个人比较喜欢使用sublime。

  1. node肯定是要有的;
  2. 全局安装stylus: npm install stylus -g;
  3. sublime中搜索stylus插件,下载安装,设置stylus的个人配置;
  4. 重启sublime,创建 .styl 文件保存就会自动编译了。
  5. 以上的stylus插件只提供了编译与高亮,并不会有语法补与提示,所以还要安装一个stylus-clean-completions插件就ok了!
  6. 如果需要自动前置添加的话,最好还是工程化后结合gulp对编译后的css进行处理,此点less也是如此。

    基本配置如下:

    {
        "envPATH": "",  //环境的路径 
        "binDir": "",   //项目路径
        "compileOnSave": true,  //是否编辑保存
        "compileDir": true,   //编译到指定目录
        "compress": true,  //是否压缩
        "compilePaths": {"": ""}  //输出路径,此项不要默认在styl相同路径生成css
    }
    

stylus语法简介

语法的话参考 张鑫旭翻译的stylus文档 就行了,本文只挑选一些常用的语法出来,便于及时查看。感谢张大大的无私奉献!

  1. 选择器

    stylus的冒号、花括号、分号均可以省略替代;
    stylus通过空格,缩排来代替花括号,故缩进很重要;

    body
      color #fff
    

    Stylus就跟CSS一样,允许你使用逗号为多个选择器同时定义属性,使用新行是一样的效果:

    textarea
    input
      border 1px solid #eee
    //等同于:
    textarea,
    input
      border 1px solid #eee
    

    父级引用,同less一样,用 & 代表;
    消除歧义,类似padding - n的表达式可能既被解释成减法运算,也可能被释义成一元负号属性。为了避免这种歧义,用括号包裹表达式:

    pad(n)
      padding (- n)
    
    body
      pad(5px)
    

    然而,只有在函数中才会这样(因为函数同时用返回值扮演混合或回调)。

  2. 变量

    stylus以等式的方式定义变量,变量替换时,会将变量值全部替换到使用的变量名位置,变量值中还可以包含变量;标识符(变量名,函数等),也可能包括$字符。变量冒失只能在冒号右边有效,左边属性名内会被当成属性名而无效。

    font-size = 14px
    font = font-size "Lucida Grande", Arial
    body
      font font sans-serif
    //会被编译为:
    body {
      font: 14px "Lucida Grande", Arial sans-serif;
    }

属性查找,Stylus有另外一个很酷的独特功能,不需要分配值给变量就可以定义引用属性。下面是个很好的例子,元素水平垂直居中对齐(典型的方法是使用百分比和margin负值),如下:

    #logo
      position: absolute
      top: 50%
      left: 50%
      width: w = 150px
      height: h = 80px
      margin-left: -(w / 2)
      margin-top: -(h / 2)

我们不使用这里的变量w和h, 而是简单地前置 `@` 字符在属性名前来访问该属性名对应的值:

    #logo
      position: absolute
      top: 50%
      left: 50%
      width: 150px
      height: 80px
      margin-left: -(@width / 2)
      margin-top: -(@height / 2)

若 `@` 的属性没有被定义,则属性会“向上冒泡”查找堆栈直到被发现,或者返回null(如果属性搞不定)。下面这个例子,@color被弄成了blue。

    body
      color: red
      ul
        li
          color: blue
          a
            background-color: @color

变量赋值时,若后面的值内容有空格分隔,则变量可以当做数组来看待:

    size = 10px 15px
    body
        font-size size[0]
        padding size
    //编译为:
    body {
      font-size:10px;
      padding:10px 15px
    }
  1. 插值

    Stylus支持通过使用{}字符包围 表达式 来插入值,其会变成标识符的一部分。例如,-webkit-{‘border’ + ‘-radius’}等同于-webkit-border-radius。感觉就是变量名的字符串链接,若用变量直接放在属性中的话,会被当成属性名处理的。

    vendor(prop, args)
      -webkit-{prop} args
      -moz-{prop} args
      {prop} args
    border-radius()
      vendor('border-radius', arguments)
    button
       border-radius 1px 2px / 3px 4px
    // 编译为
    button {
      -webkit-border-radius: 1px 2px / 3px 4px;
      -moz-border-radius: 1px 2px / 3px 4px;
      border-radius: 1px 2px / 3px 4px;
    }
    
    table
      for row in 1 2
        tr:nth-child({row})
          height: 10px * row
    // 编译为
    table tr:nth-child(1) {
      height: 10px;
    }
    table tr:nth-child(2) {
      height: 20px;
    }
    
  2. 运算符

    这一部分比较杂乱,复杂的运用一般不多,若遇到了可以参考 此文档

  3. 混合书写

    混入和函数定义方法一致,但是应用却大相径庭。mixins作为状态调用,而非表达式调用,仅仅是一些模块化的状态封装而已;minxins使用的时候,其内部属性会被复制到对应的选择器中。

    border-radius(n)
      -webkit-border-radius n
      -moz-border-radius n
      border-radius n    
    form input[type=button]
      border-radius(5px)
    form input[type=button]
      border-radius 5px
    // 编译为如下,mix调用时,甚至不需要编写括号。
    form input[type=button] {
      -webkit-border-radius: 5px;
      -moz-border-radius: 5px;
      border-radius: 5px;
    }
    

    更进一步,我们可以利用arguments这个局部变量,传递可以包含多值的表达式。

    border-radius()
      -webkit-border-radius arguments
      -moz-border-radius arguments
      border-radius arguments
    border-radius 1px 2px / 3px 4px
    

    另外一个很赞的应用是特定的私有前缀支持——例如IE浏览器的透明度:

    support-for-ie ?= true
    opacity(n)
      opacity n
      if support-for-ie
        filter unquote('progid:DXImageTransform.Microsoft.Alpha(Opacity=' + round(n * 100) + ')')
    #logo
      &:hover
        opacity 0.5
    // 编译为
    #logo:hover {
      opacity: 0.5;
      filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
    }
    

    混合书写可以利用父级引用字符 &, 继承父业而不是自己筑巢,也就是mixins最外层的 & 引用引的是mixins调用的环境父级。

    自然,混合书写可以利用其它混合书写,建立在它们自己的属性和选择器上。

  4. 方法

    语言函数定义,其定义与混入(mixins)一致,却可以返回值。

    add(a, b)
      a + b
    body 
      padding add(10px, 5)
    // 渲染为:
    body {
      padding: 15px;
    }
    

    注意到方法和混入的区别了吗?简介片面的来说,方法可以看做一个定义的变量,而混入是一个相较独立的属性包。

    默认参数:可选参数往往有个默认的给定表达。在Stylus中,我们甚至可以超越默认参数。

    add(a, b = a)
      a + b
    
    add(10, 5)
    // => 15    
    add(10)
    // => 20
    

    返回多值:Stylus的函数可以返回多个值,就像你给变量赋多个值一样。

    sizes()
     15px 10px
    
    sizes()[0]
    // => 15px
    

    有个小小的例外就是返回值是标识符。例如,下面看上去像一个属性赋值给Stylus(因为没有操作符)。为避免歧义,我们可以使用括号,或是return关键字。

    swap(a, b)
      b a
    
    swap(a, b)
      (b a)
    
    swap(a, b)
      return b a
    

    条件:简单的 if…else… 应用。

    stringish(val)
      if val is a 'string' or val is a 'ident'
        yes
      else
        no
    
    stringish('yay') == yes
    // => true        
    stringish(yay) == yes
    // => true        
    stringish(0) == no
    // => true
    

    注意:yes和no并不是布尔值。本例中,它们只是简单的未定义标识符。

    别名:给函数起别名类似于定义变量。

    add(a, b)
      a + b
    plus = add
    plus(1, 2)
    // => 3
    

    变量函数:把函数当作变量传递到新的函数中。

    invoke(a, b, fn)
      fn(a, b)        
    add(a, b)
      a + b        
    body
      padding invoke(5, 10, add)
      padding invoke(5, 10, sub)
    
    body {
      padding: 15;
      padding: -5;
    }
    

    参数:arguments是所有函数体都有的局部变量,包含传递的所有参数。mixins中也有arguments变量,同函数一致。

    sum()
      n = 0
      for num in arguments
        n = n + num
    
    sum(1,2,3,4,5)
    // => 15
    
  5. 关键字参数

    Stylus支持关键字参数,或”kwargs”. 允许你根据相关参数名引用参数,参数的顺序可以打乱,因为有的关键字,但这种情况一般使用的很少,个人感觉其实是加大了开发的复杂度,故此处就不再讨论。

  6. 内置方法

    red(color):返回color中的红色比重。

    green(color):返回color中的绿色比重。

    blue(color):返回color中的蓝色比重。

    alpha(color):返回color中的透明度比重。

    dark(color):检查color是否是暗色。

    light(color):检查color是否是亮色。

    hue(color):返回给定color的色调。

    push(expr, args…):后面推送给定的args给expr,别名为append()。

    nums = 1 2
    push(nums, 3, 4, 5)
    
    nums
    // => 1 2 3 4 5
    

    unshift(expr, args…):起始位置插入给定的args给expr,别名为prepend(),单个单个数据的操作,不是一次将所有args按给定顺序插入。

    nums = 4 5
    unshift(nums, 3, 2, 1)
    
    nums
    // => 1 2 3 4 5
    

    keys(pairs):返回给定pairs中的键。

    pairs = (one 1) (two 2) (three 3)
    keys(pairs)
    // => one two three
    

    values(pairs):返回给定pairs中的值。

    pairs = (one 1) (two 2) (three 3)
    values(pairs)
    // => 1 2 3
    

    typeof(node):字符串形式返回node类型,别名有type-of和type。

    type(12)
    // => 'unit'        
    typeof(12)
    // => 'unit'        
    typeof(#fff)
    // => 'rgba'        
    type-of(#fff)
    // => 'rgba'
    

    unit(unit[, type]):返回unit类型的字符串或空字符串,或者赋予type值而无需单位转换。

    unit(10)
    // => ''
    unit(15in)
    // => 'in'
    unit(15%, 'px')
    // => 15px
    unit(15%, px)
    // => 15px
    

    match(pattern, string):检测string是否匹配给定的pattern。

    abs(unit):绝对值。

    abs(-5px) // => 5px
    

    ceil(unit):向上取整。

    floor(unit):向下取整。

    round(unit):四舍五入取整。

    min(a, b):取较小值。

    max(a, b):取较大值。

    even(unit):是否为偶数。

    even(6px) // => true
    

    odd(unit):是否为奇数。

    sum(nums):求和。

    avg(nums):求平均数。

    join(delim, vals…):给定vals使用delim连接。

    join(' ', 1 2 3) // => "1 2 3"        
    join(',', 1 2 3) // => "1,2,3"        
    join(', ', foo bar baz) // => "foo, bar, baz"        
    join(', ', foo, bar, baz) // => "foo, bar, baz"        
    join(', ', 1 2, 3 4, 5 6) // => "1 2, 3 4, 5 6"
    

    s(fmt, …):s()方法类似于unquote(),不过后者返回的是Literal节点,而这里起接受一个格式化的字符串,非常像C语言的sprintf(). 目前,唯一标识符是%s。

    s('bar()'); // => bar()
    s('bar(%s)', 'baz'); // => bar("baz")
    s('bar(%s)', baz); // => bar(baz)
    s('bar(%s)', 15px); // => bar(15px)
    s('rgba(%s, %s, %s, 0.5)', 255, 100, 50); // => rgba(255, 100, 50, 0.5)
    s('bar(%Z)', 15px); // => bar(%Z)
    s('bar(%s, %s)', 15px); // => bar(15px, null)
    

    length([expr]):括号表达式扮演元组,length()方法返回该表达式的长度。

    length((1 2 3 4)) // => 4
    length((1 2)) // => 2
    length((1)) // => 1
    length(()) // => 0
    length(1 2 3) // => 3
    length(1) // => 1
    length() // => 0
    

    warn(msg):使用给定的error警告,并不退出。

    error(msg):伴随着给定的错误msg退出。

    last(expr):返回给定expr的最后一个值。

    opposite-position(positions):返回给定positions相反内容。

    opposite-position(right) // => left
    opposite-position(top left) // => bottom right
    
  7. 其余参数

    Stylus支持 name... 形式的其余参数。这些参数可以消化传递给混写或函数的参数们。

    box-shadow(offset-x, args...)
      got-offset-x offset-x
      -webkit-box-shadow offset-x args
      -moz-box-shadow offset-x args
      box-shadow offset-x args        
    #login
      box-shadow 1px 2px 5px #eee
    // 编译为
    #login {
      got-offset-x: 1px;
      -webkit-box-shadow: 1px 2px 5px #eee;
      -moz-box-shadow: 1px 2px 5px #eee;
      box-shadow: 1px 2px 5px #eee;
    }
    

    offset-x设定一个专门的变量接收第一个传入的参数,剩余的参数统统传到args类数组中,不过传入的数据好像不能实现表达式的精确传递,比如逗号就有问题,故推荐直接使用 arguments 参数处理。

  8. 注释

    Stylus支持三种注释,单行注释,多行注释,以及多行缓冲注释。

    // 我是注释!
    body
      padding 5px // 蛋疼的padding
    
    /*
     * 给定数值合体
     */        
    add(a, b)
      a + b
    
    /*!
     * 给定数值合体
     */        
    add(a, b)
      a + b
    

    单行注释跟JavaScript一样,双斜杠,CSS中不输出;多行注释看起来有点像CSS的常规注释。然而,它们只有在compress选项未启用的时候才会被输出;多行缓冲注释跟多行注释类似,不同之处在于开始的时候,这里是/*!. 这个相当于告诉Stylus压缩的时候这段无视直接输出。

  9. 条件

    if / else if / else:跟一般的语言一致,if表达式满足(true)的时候执行后面语句块,否则,继续后面的else if或else。

    box(x, y, margin-only = false)
      if margin-only
        margin y x
      else
        padding y x
    

    unless:除非,基本上与if相反,本质上是(!(expr))。

    后缀条件:Stylus支持后缀条件,这就意味着if和unless可以当作操作符;当右边表达式为真的时候执行左边的操作对象,有点类似于三目运算;

    negative(n)
      error('无效数值') unless n is a 'unit'
      return yes if n < 0
      no
    
  10. 迭代

    Stylus允许你通过for/in对表达式进行迭代形式如下:

    for <val-name> [, <key-name>] in <expression>
    

    例如:

    body
      for num in 1 2 3
        foo num
    // 编译为:
    body {
      foo: 1;
      foo: 2;
      foo: 3;
    }
    

    加上key-name的情况:

    body
      fonts = Impact Arial sans-serif
      for font, i in fonts
        foo i font
    // 编译为
    body {
      foo: 0 Impact;
      foo: 1 Arial;
      foo: 2 sans-serif;
    }
    

    后缀:就跟if/unless可以利用后面语句一样,for也可以。如下后缀解析的例子:

    sum(nums)
      sum = 0
      sum += n for n in nums
    

    不过为了方便理解,个人不建议使用这种方式。

  11. 导入

    Stylus支持字面@import CSS, 也支持其他Stylus样式的动态导入。

    @import "reset.css"
    

    当使用@import没有 .css 扩展,会被认为是Stylus片段(如:@import "mixins/border-radius")。

  12. 媒体

    @media 工作原理和在常规CSS中一样,但是,要使用Stylus的块状符号。

    @media print
      #header
      #footer
        display none
    
  13. 自定义字体

    @font-face 跟其在CSS中作用表现一样,在后面简单地添加个块状属性即可,类似下面:

    @font-face
      font-family Geo
      font-style normal
      src url(fonts/geo_sans_light/GensansLight.ttf)
    
    .ingeo
      font-family Geo
    
  14. 动画定义

    Stylus支持@keyframes规则,当编译的时候转换成@-webkit-keyframes,使用@keyframes,通过vendors变量,会自动添加私有前缀(webkit moz official),official 为标准解析。

  15. 继承

    Stylus的 @extend 指令受SASS实现的启发,基本一致,除了些轻微差异。此功能大大简化了继承其他语义规则集的语义规则集的维护;把对应的选择器传给 @extend 即可继承已存在的选择器规则;此方式用 mixins 也可以实现,两种方式均比较简便,对于已有的规则集,一般使用 extend,若公共的规则比较多,建议使用 mixins 。

    .message {
      padding: 10px;
      border: 1px solid #eee;
    }    
    .warning {
      @extend .message;
      color: #E2E21E;
    }
    

    目前Stylus与SASS不同之处在于SASS不允许@extend嵌套选择器,Stylus中,只要选择器匹配,就可以生效。

  16. CSS字面量

    不管什么原因,如果遇到Stylus搞不定的特殊需求,你可以使用@css使其作为CSS字面量解决之。

    @css {
      body {
        font: 14px;
      }
    }
    // 编译为
    body {
      font: 14px;
    }
    
  17. 字符转码

    Stylus可以字符转码。这可以让字符变成标识符,或是渲染成字面量。注意Stylus中 / 当作为属性使用的时候需要用括号括起来:

    body
      padding 1 \+ 2
    body
      font 14px/1.4
      font (14px/1.4)
    // 编译为
    body {
      padding: 1 + 2;
    }
    body {
      font: 14px/1.4;
      font: 10px;
    }
    

慢慢回味学习吧~