选择器(Selectors)

缩进(Indentation)

Stylus 类似于 Python,通过缩进对齐表达代码逻辑,如下所示:

body
  color white

编译 CSS 为:

body {
  color: #fff;
}

如果你喜欢,你可以把冒号加上,用做分隔,便于阅读:

body
  color: white

规则集

Stylus 就跟 CSS 一样,允许你使用逗号为多个选择器同时定义属性。

textarea, input
  border 1px solid #eee

同样可以用换行达到一样效果:

textarea
input
  border 1px solid #eee

编译 CSS 为:

textarea,
input {
  border: 1px solid #eee;
}

该规则唯一的例外就是长得像属性的选择器。

例如,下面的foo bar baz可能是个属性或者是选择器。

foo bar baz
> input
  border 1px solid

为解决这个原因,我们可以在尾部加个逗号:

foo bar baz,
form input,
> a
  border 1px solid

父级引用

字符&指向父选择器。下面这个例子,我们两个选择器(textareainput)在:hover伪类选择器上都改变了color

textarea
input
  color #A7A7A7
  &:hover
    color #000

编译 CSS 为:

textarea,
input {
  color: #a7a7a7;
}
textarea:hover,
input:hover {
  color: #000;
}

消除歧义

padding - n这样的表达式,既可以被解释成减法运算,也可以被解释成一元减号。为了避免这种歧义,用括号包裹表达式:

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

编译 CSS 为:

body {
  padding: -5px;
}

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

下面这个例子就没有问题(产生与上面相同的结果):

body
  padding -5px

是否有 Stylus 无法处理的属性值?unquote()可以帮助你:

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

编译 CSS 为:

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

变量(Variables)

变量

我们可以声明变量,并在整个样式表中使用:

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

编译 CSS 为:

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

变量甚至可以包含在表达式中:

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

编译 CSS 为:

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

标识符(变量名、函数等)也可以是$开始。例如:

$font-size = 14px
 
body {
  font: $font-size 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)

我们可以不使用变量wh,而是简单地通过@字符获取属性对应的值:

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

另外一种使用情况就是在混合中根据其他属性来定义属性值。

在下面这个例子中,我们定义在z-index未被指定情况下默认值为1

position()
  position: arguments
  z-index: 1 unless @z-index
  
#logo
  z-index: 20
  position: absolute
#logo2
  position: absolute

属性查找通过“冒泡”方式直到找到相应的值,或该属性不存在则返回null。在以下示例中,@color被解析为blue:

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

插值(Interpolation)

插值

Stylus 支持通过使用{}字符包围表达式来插入值,其会变成标识符的一部分。

例如,-webkit-{'border' + '-radius'}等同于-webkit-border-radius

比较好的例子就是私有前缀属性扩展:

vendor(prop, args)
  -webkit-{prop} args
  -moz-{prop} args
  {prop} args
 
border-radius()
  vendor('border-radius', arguments)
 
box-shadow()
  vendor('box-shadow', arguments)
 
button
  border-radius 1px 2px / 3px 4px

编译 CSS 为:

button {
  -webkit-border-radius: 1px 2px / 3px 4px;
  -moz-border-radius: 1px 2px / 3px 4px;
  border-radius: 1px 2px / 3px 4px;
}

选择器插值

插值也可以在选择器上起作用。例如,我们可以指定表格前 5 行的高度,如下:

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

编译 CSS 为:

table tr:nth-child(1) {
  height: 10px;
}
table tr:nth-child(2) {
  height: 20px;
}
table tr:nth-child(3) {
  height: 30px;
}
table tr:nth-child(4) {
  height: 40px;
}
table tr:nth-child(5) {
  height: 50px;
}

运算符(Operators)

运算符优先级

下表运算符优先级,从最高到最低:

[]
! ~ + -
is defined
** * / %
+ -
... ..
<= >= < >
in
== is != is not isnt
is a
&& and || or
?:
= := ?= += -= *= /= %=
not
if unless

一元运算符

以下一元运算符可用,!, not, -, +, 以及~

!0
// => true

!!0
// => false

!1
// => false

5px
// => true

-5px
// => -5px

--5px
// => 5px

not true
// => false

not not true
// => true

逻辑运算符not的优先级较低,因此,下面这个例子可以替换:

a = 0
b = 1

!a and !b
// => false
// 解析为: (!a) and (!b)

用:

not a or b
// => false
// 解析为: not (a or b)

混合书写(Mixins)

混入

混入和函数定义方法一致,但是应用却大相径庭。

例如,下面有定义的border-radius(n)方法,其却作为一个mixin(如,作为状态调用,而非表达式)调用。

border-radius()选择器中调用时候,属性会被扩展并复制在选择器中。

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;
}

使用混入书写,你可以完全忽略括号,提供梦幻般私有属性的支持。

border-radius(n)
  -webkit-border-radius n
  -moz-border-radius n
  border-radius n
 
form input[type=button]
  border-radius 5px

注意到我们混合书写中的border-radius当作了属性,而不是一个递归函数调用。

更进一步,我们可以利用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);
}

父级引用

混合书写可以利用父级引用字符&, 继承父业而不是自己筑巢。

例如,我们要用stripe(even, odd)创建一个条纹表格。evenodd均提供了默认颜色值,每行也指定了background-color属性。我们可以在tr嵌套中使用&来引用tr,以提供even颜色。

stripe(even = #fff, odd = #eee)
 tr
   background-color odd
   &.even
   &:nth-child(even)
       background-color even

然后,利用混合书写,如下:

table
  stripe()
  td
    padding 4px 10px
 
table#users
  stripe(#303030, #494848)
  td
    color white

另外,stripe()的定义无需父引用:

stripe(even = #fff, odd = #eee)
  tr
    background-color odd
  tr.even
  tr:nth-child(even)
    background-color even

如果你愿意,你可以把stripe()当作属性调用。

stripe #fff #000

混合书写中的混合书写

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

例如,下面我们创建内联comma-list()(通过inline-list())以及逗号分隔的无序列表。

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

渲染:

ul li:after {
  content: ", ";
}
ul li:last-child:after {
  content: "";
}
ul li {
  display: inline;
}

方法(Functions)

函数

Stylus 强大之处就在于其内置的语言函数定义。其定义与混入(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

注意:因为参数默认是赋值,我们可可以使用函数调用作为默认值。

add(a, b = unit(a, px))
  a + b

函数体

我们可以把简单的add()方法更进一步。通过内置unit()把单位都变成px, 因为赋值在每个参数上,因此,我们可以无视单位换算。

add(a, b = a)
  a = unit(a, px)
  b = unit(b, px)
  a + b
 
add(15%, 10deg)
// => 25

多个返回值

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

例如,下面就是一个有效赋值:

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

类似的,我们可以在函数中返回多个值:

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

有个小小的例外就是返回值是标识符。例如,下面看上去像一个属性赋值给 Stylus(因为没有操作符)。

swap(a, b)
  b a

为避免歧义,我们可以使用括号,或是return关键字。

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

条件

比方说,我们想要创建一个名为stringish()的函数,用来决定参数是否是字符串。我们检查val是否是字符串或缩进(类似字符)。如下,使用yesno代替truefalse

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

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

另外一个例子:

compare(a, b)
  if a > b
    higher
  else if a < b
    lower
  else
    equal

使用:

compare(5, 2)
// => higher
 
compare(1, 5)
// => lower
 
compare(10, 10)
// => equal

别名

给函数起个别名,和简单,直接等于就可以了。例如上面的add()弄个别名plus(), 如下:

plus = add
 
plus(1, 2)
// => 3

变量函数

我们可以把函数当作变量传递到新的函数中。例如,invoke()接受函数作为参数,因此,我们可以传递add()以及sub()

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是所有函数体都有的局部变量,包含传递的所有参数。

例如:

sum()
  n = 0
  for num in arguments
    n = n + num
 
sum(1,2,3,4,5)
// => 15

哈希示例

下面,我们定义get(hash, key)方法,用来返回key值或null 我们遍历每个键值对,如果键值匹配,返回对应的值。

get(hash, key)
  return pair[1] if pair[0] == key for pair in hash

下面例子可以证明,语言函数模样的Stylus表达式具有更大的灵活性。

hash = (one 1) (two 2) (three 3)
 
get(hash, two)
// => 2
 
get(hash, three)
// => 3
 
get(hash, something)
// => null

关键字参数(Keyword Arguments)

关键字参数

Stylus 支持关键字参数,或”kwargs”. 允许你根据相关参数名引用参数。

下面这些例子功能上都是一样的。但是,我们可以在列表中的任何地方放置关键字参数。其余不键入参数将适用于尚未得到满足的参数。

body {
  color: rgba(255, 200, 100, 0.5);
  color: rgba(red: 255, green: 200, blue: 100, alpha: 0.5);
  color: rgba(alpha: 0.5, blue: 100, red: 255, 200);
  color: rgba(alpha: 0.5, blue: 100, 255, 200);
}

等同于:

body {
   color: rgba(255,200,100,0.5);
   color: rgba(255,200,100,0.5);
   color: rgba(255,200,100,0.5);
   color: rgba(255,200,100,0.5);
}

查看函数或混合书写中接受的参数,可以使用p()方法。

p(rgba)

生成:

inspect: rgba(red, green, blue, alpha)

内置方法(Built-in Functions)

red(color)

返回color中的红色比重。

red(#c00)
// => 204

green(color)

返回color中的绿色比重。

green(#0c0)
// => 204

blue(color)

返回color中的蓝色比重。

red(#00c)
// => 204

alpha(color)

返回color中的透明度比重。

alpha(#fff)
// => 1

alpha(rgba(0,0,0,0.3))
// => 0.3

dark(color)

检查color是否是暗色。

dark(black)
// => true

dark(#005716)
// => true

dark(white)
// => false

light(color)

检查color是否是亮色。

light(black)
// => false

light(white)
// => true

light(#00FF40)
// => true

hue(color)

返回给定color的色调。

hue(hsla(50deg, 100%, 80%))
// => 50deg

saturation(color)

返回给定color的饱和度。

saturation(hsla(50deg, 100%, 80%))
// => 100%

lightness(color)

返回给定color的亮度。

lightness(hsla(50deg, 100%, 80%))
// => 80%