Stylus 学习笔记

由于一些不可描述的原因,需要接触 stylus 这个工具。作为一个爱学习的宝宝,应该要做好笔记。

stylus 呢,是一个 CSS 预处理器,让 CSS 变得像 JavaScript 般进行动态开发,可以使用变量、简单逻辑、函数等编程语言的基本语法。

但不同于 sass,stylus 是基于 Node.js 的,而且比 less 强大。
具体查阅:[译]为什么使用Stylus

Stylus 默认使用 “styl“ 作为文件拓展名。

配置环境

  1. Node.js
    既然说 stylus 是基于 Node.js,那么首先就要先要准备好 Node.js 的环境。

  2. Stylus 模块
    用 npm 等安装 stylus 模块

    $ npm install stylus -g
  3. Sublime Text 3 的 stylus 插件
    使用 Package Control 安装

完成这三步之后,就可以在 ST3 里进行 styl 文件的编译了。当然,如果不想借助 ST 的话,只需完成前两步即可。


下来就是 stylus 的语法了

选择器

1. 缩进

stylus 使用缩进(Indentation)来表示花括号{}。
对于缩进可以使用空格或者 tab,只不过必须整个文件要统一(要么只用 spaces,要么只用 tab),否则会报错。

body
color: blue

P.s. 属性名后面的冒号可加可不加

另外,缩进也可以表示嵌套

.outer
.inner
color: blue
/* 表示 */
.outer .inner{
color: blue
}

2. 规则

stylus 的语法和 CSS 还是有很多相似之处。
如想要为多个不同选择器设置相同的样式,可以用逗号隔开,或者是直接换行。如:

button, a
display: inline-block
button
a
display: inline-block
/* 编译后都是如下 ==> */
button,
a {
display: inline-block
}

文档中有个地方,我还不太明白怎么使用

The only exception to this rule are selectors that look like properties. For example, the following foo bar baz might be a property or a selector

“有一个例外,选择器看起来会和属性名相似。比如 foo bar baz 就可能是一个属性或者选择器”

So for this reason (or simply if preferred), we may trail with a comma

“因此(最好平时也如此),可以在后面添上一个逗号”

父级引用

使用 & 字符引用父选择器,可以让伪类选择器指向父选择器,如:

#p1
span
button
color: blue
&:hover
color: yellow

在上面的代码中,等同于:

#p1 span,
#p1 button{
color: blue
}
#p1 span:hover,
#p1 button:hover{
color: yellow
}

文档还有个比较特别的栗子,在 IE 浏览器中,利用父级引用以及混合书写来实现 2px 的边框:

// styl
box-shadow()
-webkit-box-shadow arguments
-moz-box-shadow arguments
box-shadow arguments
html.ie8 &,
html.ie7 &,
html.ie6 &
border 2px solid arguments[length(arguments) - 1]
body
#login
box-shadow 1px 1px 3px #eee

变身(此处应有奥特曼!)

/* css */
body #login {
-webkit-box-shadow: 1px 1px 3px #eee;
-moz-box-shadow: 1px 1px 3px #eee;
box-shadow: 1px 1px 3px #eee;
}
html.ie8 body #login,
html.ie7 body #login,
html.ie6 body #login {
border: 2px solid #eee;
}

针对 styl 部分解释一下:

  • 可以把 box-shadow() 近似看成是一个函数,参数可以用 arguments 数组来获取,而参数在传入的时候,根据空格来分隔出若干个参数。在栗子中,传入的是”1px 1px 3px #eee”,因此 arguments 就有四个元素了。
  • 将 box-shadow(函数)作为属性赋给 body #login,可以将函数内的属性设置在 body #login 中。并且可以通过传参动态改变属性值。
  • 在 html.ieX 后,带有一个字符 &。而这个 & 就引用了父级,即:当前被赋予 box-shadow() 的选择器,这里也就是 body #login

消除歧义

函数中,类似 padding -n 的表达式时,要注意消除歧义,因为它即可被解释为减法运算,也可以是一元负号属性。所以,用括号来包裹表达式以避免歧义。

marg(n)
margin (- n)
body
marg(5px)

注意,- 号和变量中间要有一个空格

无法处理的属性值,用 unquote():

filter unquote('progid:DXImageTransform.Microsoft.BasicImage(rotation=1)')

变量

设置变量

变量可以这么玩:

font-size = 14px
body
font: font-size Arial, sans-serif

===>

body {
font: 14px Arial sans-serif;
}

或者这么玩:

$font-size = 14px
font = $font-size "Lucida Grande", Arial
body
font: font sans-serif

===>

body {
font: 14px "Lucida Grande", Arial sans-serif;
}

属性引用

Core —— 使用字符 @ 来实现:

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

还可以给属性设置默认值:

position()
position: arguments
z-index: 1 unless @z-index

此外,这个引用功能,还会向上冒泡,查找堆栈直到发现,或者最后返回 null。栗子:

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

最后 background-color 为 blue。

插值

插值

stylus 中,{} 有了新的用法。用它包裹表达式来插入一些值或者内容(有点类似 Vue 中的插值绑定 )
e.g. -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(50%)

===>

button {
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
}

选择器插值

直接举栗吧:

table
for row in 1 2 3 4 5
tr:nth-child( {row} )
height: 10px * row

运算符

优先级(最高到最低)

[] // 下标运算符(跟数组的用法一致)
! ~ + -
is defined
** * / %
+ -
... .. // 范围。分别是 范围操作符 和 界线操作符
<= >= < >
in
== is != is not isnt
&& and || or
?:
= := ?= += -= *= /= %=
not
if unless

范围操作符(…)和界线操作符(..)

1..5
// => 1 2 3 4 5
1...5
// => 1 2 3 4

乘除运算符

如果使用 “/“ 运算符的话,必须要给它加一个括号,否则会直接根据其字面意思来处理,如 CSS 的 line-height:

font: 14px/1.5 // 这里表示文字大小和行高
font: (14px/1.5) // 这里表示文字大小为 14÷1.5

指数操作符(**)

2 ** 8
// => 256

条件赋值( ?= := )

条件赋值,可以在不改变旧值的情况下,定义一个变量。
(其实也就是在定义一个变量时,检查它是否有值,如果没有,就给它赋予一个指定的新值。)
e.g.

color = black
color := white
borderColor ?: white
backgroundColor = backgroundColor is defined ? backgroundColor : white
// color => black
// borderColor => white
// backgroundColor => white

混入和函数(Mixin & Function)

混入和函数,是 stylus 里两种特性。两者都是通过相同的方式来定义,只不过它们的使用方式不同。

混入

混入,按我自己的理解,就是我们先针对某个属性及其前缀,自行定义一个方法(方法内是针对某个属性的模版),在选择器中调用,该方法会将内部设置的属性模版直接套用在当前选择器的属性中。
如:

// 定义
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]{
-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

父级引用

其实和之前选择器的父级引用用法一样。可以用来设置伪类的属性。

// 设置一个条纹表格样式
// 这里可以给其赋予一个默认值
stripe( even=#fff, odd=#eee )
tr
background-color odd
&.even
&:nth-child(even)
background-color even
table
stripe()
table
stripe pink, blue

混入的嵌套和组合

inline-list()
li
display inline
comma-list()
inline-list()
li
&:after
content ', '
&:last-child:after
content ''

函数

函数的定义和混入一致,但不同的是,函数可以返回值。
(我觉得基本就是用来返回值的。就是说,stylus 的函数的用途就用来返回处理后的数据,当然啦,不用手动返回啦)

返回值

// 定义
add(a, b)
a + b
// 调用
body
padding add(10px, 5)
// 渲染结果
body{
padding: 15px;
}

默认值

和混入一样,可以给参数设置默认值。

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