运算符

运算符的优先级

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

 .
 []
 ! ~ + -
 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
// parsed as: (!a) and (!b)

可以被替换为:

not a or b
// => false
// parsed as: not (a or b)

二元运算符

下标运算符 []

The subscript operator allows us to grab a value inside an expression via index (zero-based). Negative index values starts with the last element in the expression.

 list = 1 2 3
 list[0]
 // => 1

 list[-1]
 // => 3

Parenthesized expressions may act as tuples (e.g. (15px 5px), (1 2 3)).

Below is an example that uses tuples for error handling (and showcasing the versatility of this construct):

 add(a, b)
   if a is a 'unit' and b is a 'unit'
     a + b
   else
     (error 'a and b must be units!')

 body
   padding add(1,'5')
   // => padding: error "a and b must be units";
   
   padding add(1,'5')[0]
   // => padding: error;
   
   padding add(1,'5')[0] == error
   // => padding: true;

   padding add(1,'5')[1]
   // => padding: "a and b must be units";

Here’s a more complex example. Now we’re invoking the built-in error() function with the return error message, whenever the ident (the first value) equals error.

 if (val = add(1,'5'))[0] == error
   error(val[1])

Range .. …

Both the inclusive (..) and exclusive (...) range operators are provided, expanding to expressions:

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

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

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

加减运算符:+ -

乘法和加法二元运算符和一般认知一致。单位类型属于同一类的会做类型转换,否则默认转换为字面值,例如 5s - 2px 结果是 3s

15px - 5px
// => 10px

5 - 2
// => 3

5in - 50mm
// => 3.031in

5s - 1000ms
// => 4s

20mm + 4in
// => 121.6mm

"foo " + "bar"
// => "foo bar"

"num " + 15
// => "num 15"

乘除运算符:/ * %

2000ms + (1s * 2)
// => 4000ms

5s / 2
// => 2.5s

4 % 2
// => 0

在属性值中使用 / 运算符时,必须 用括号括起来,否则 / 运算符将被作为字面意思(即“斜线”)解释(以支持 CSS 的 line-height 属性):

font: 14px/1.5;

但是,以下属性值等价于 14px ÷ 1.5

font: (14px/1.5);

只有 / 操作符需要特殊对待。

Shorthand operators: += -= *= /= %=

Shorthand operators works like other common language. With list variable, the first value will be use to execute the operators and overwrite the list to turn it to a single-value variable. With string, node values only += works as an appending function. With number type value, all operators work exactly like a normal math. Similar for color value.

n = 12
n += 8
// => n = 20

int-list = 12 23 0 32
int-list %= 2
// => 12 % 2 = 0 (mod operator)
// => int-list = 0

mixed-list = node 23 'str'
mixed-list %= 2
// => error

mixed-list = node 23 'str' #2e7
mixed-list += 2
// => mixed-list = node2

s = 'str'
s += 2
// => s = 'str2'

c = #0e0
c -= #0e0
// => c = #000    

指数运算符:**

指数运算符示例:

2 ** 8
// => 256

相等与关系运算:== != >= <= > <

Equality operators can be used to equate units, colors, strings, and even identifiers. This is a powerful concept, as even arbitrary identifiers (such as as wahoo) can be utilized as atoms. A function could return yes or no instead of true or false (although not advised).

5 == 5
// => true

10 > 5
// => true

#fff == #fff
// => true

true == false
// => false

wahoo == yay
// => false

wahoo == wahoo
// => true

"test" == "test"
// => true

true is true
// => true

'hey' is not 'bye'
// => true

'hey' isnt 'bye'
// => true

(foo bar) == (foo bar)
// => true

(1 2 3) == (1 2 3)
// => true

(1 2 3) == (1 1 3)
// => false

Only exact values match. For example, 0 == false and null == false are both false.

Aliases:

==    is
!=    is not
!=    isnt

Truthfulness

Nearly everything within Stylus resolves to true, including units with a suffix. Even 0%, 0px, etc. will resolve to true (because it’s common in Stylus for mixins or functions to accept units as valid).

However, 0 itself is false in terms of arithmetic.

Expressions (or “lists”) with a length greater than 1 are considered truthy.

true examples:

  0% 
  0px
  1px 
  -1
  -1px
  hey
  'hey'
  (0 0 0)
  ('' '')

false examples:

 0 
 null
 false
 ''

逻辑运算符:&& || and or

逻辑运算符 &&|| 分别是 and / or 的别名,具有相同的优先级。

5 && 3
// => 3

0 || 5
// => 5

0 && 5
// => 0

#fff is a 'rgba' and 15 is a 'unit'
// => true

存在运算符:in

此运算符用于检查 左侧 操作数是否存在于 右侧 表达式中。

简单示例:

  nums = 1 2 3
  1 in nums
  // => true

  5 in nums
  // => false

一些未定义标识符:

  words = foo bar baz
  bar in words
  // => true

  HEY in words
  // => false

元组同样适用:

  vals = (error 'one') (error 'two')
  error in vals
  // => false
  
  (error 'one') in vals
  // => true

  (error 'two') in vals
  // => true

  (error 'something') in vals
  // => false

在混合(mixin)中的使用示例:

  pad(types = padding, n = 5px)
    if padding in types
      padding n
    if margin in types
      margin n

  body
    pad()

  body
    pad(margin)

  body
    pad(padding margin, 10px)

输出结果:

  body {
    padding: 5px;
  }
  body {
    margin: 5px;
  }
  body {
    padding: 10px;
    margin: 10px;
  }

条件赋值运算符:?= :=

条件赋值运算符 ?= (别名 :=)允许我们定义变量而不删除旧值(如果存在的话)。此运算符可以通过一个三元运算符和一个 is defined 二元运算来表达其等效的逻辑。

例如,以下内容是等效的:

color := white
color ?= white
color = color is defined ? color : white

当使用普通的 = 时,只是简单地重新赋值:

color = white
color = black

color
// => black

但是使用 ?= 时,第二次的赋值就会失败(因为变量已经被定义过了):

color = white
color ?= black

color
// => white

类型检查运算符:is a

Stylus 提供了一个名为 is a 的二元运算符,用于类型检查。

15 is a 'unit'
// => true

#fff is a 'rgba'
// => true

15 is a 'rgba'
// => false

或者,我们也可以使用 type() BIF:

type(#fff) == 'rgba'
// => true                                                                            

注意: color 是唯一的特例,当左侧操作数 是 RGBAHSLA 时,计算结果都是 true

变量定义检查运算符:is defined

This pseudo binary operator does not accept a right-hand operator, and does not evaluate the left. This allows us to check if a variable has a value assigned to it.

foo is defined
// => false

foo = 15px
foo is defined
// => true

#fff is defined
// => 'invalid "is defined" check on non-variable #fff'

Alternatively, one can use the lookup(name) built-in function to do this—or to perform dynamic lookups:

name = 'blue'
lookup('light-' + name)
// => null

light-blue = #80e2e9
lookup('light-' + name)
// => #80e2e9

This operator is essential, as an undefined identifier is still a truthy value. For example:

body
  if ohnoes
    padding 5px

Will yield the following CSS when undefined:

body {
  padding: 5px;
}

However this will be safe:

body
  if ohnoes is defined
    padding 5px

三元运算符

The ternary operator works as we would expect in most languages. It’s the only operator with three operands (the condition expression, the truth expression, and the false expression).

num = 15
num ? unit(num, 'px') : 20px
// => 15px

Casting

As a terse alternative to the unit() built-in function, the syntax (expr) unit may be used to force the suffix.

body
  n = 5
  foo: (n)em
  foo: (n)%
  foo: (n + 5)%
  foo: (n * 5)px
  foo: unit(n + 5, '%')
  foo: unit(5 + 180 / 2, deg)

颜色运算符

Operations on colors provide a terse, expressive way to alter components. For example, we can operate on each RGB:

#0e0 + #0e0
// => #0f0

Another example is adjust the lightness value by adding or subtracting a percentage. To lighten a color, add; to darken, subtract.

#888 + 50%
// => #c3c3c3

#888 - 50%
// => #444

Adjust the hue is also possible by adding or subtracting with degrees. For example, adding 50deg to this red value results in a yellow:

 #f00 + 50deg
 // => #ffd500

Values clamp appropriately. For example, we can “spin” the hue 180 degrees, and if the current value is 320deg, it will resolve to 140deg.

We may also tweak several values at once (including the alpha) by using rgb(), rgba(), hsl(), or hsla():

  #f00 - rgba(100,0,0,0.5)
  // => rgba(155,0,0,0.5)

Sprintf

The string sprintf-like operator % can be used to generate a literal value, internally passing arguments through the s() built-in:

   'X::Microsoft::Crap(%s)' % #fc0
   // => X::Microsoft::Crap(#fc0)

Multiple values should be parenthesized:

  '-webkit-gradient(%s, %s, %s)' % (linear (0 0) (0 100%))
  // => -webkit-gradient(linear, 0 0, 0 100%)
Stylus on GitHub