运算符
运算符优先级
以下是运算符优先级表,从最高到最低
.
[]
! ~ + -
is defined
** * / %
+ -
... ..
<= >= < >
in
== is != is not isnt
is a
&& and || or
?:
= := ?= += -= *= /= %=
not
if unless
.
[]
! ~ + -
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
!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)
a = 0
b = 1
!a and !b
// => false
// parsed as: (!a) and (!b)
使用
not a or b
// => false
// parsed as: not (a or b)
not a or b
// => false
// parsed as: not (a or b)
二元运算符
下标 []
下标运算符允许我们通过索引(从 0 开始)获取表达式中的值。负索引值从表达式中的最后一个元素开始。
list = 1 2 3
list[0]
// => 1
list[-1]
// => 3
list = 1 2 3
list[0]
// => 1
list[-1]
// => 3
带括号的表达式可以作为元组(例如 (15px 5px)
、(1 2 3)
)。
下面是一个使用元组进行错误处理(并展示此结构的多功能性)的示例
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";
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";
这是一个更复杂的示例。现在,每当 ident(第一个值)等于 error
时,我们都会调用内置 error()
函数并返回错误消息。
if (val = add(1,'5'))[0] == error
error(val[1])
if (val = add(1,'5'))[0] == error
error(val[1])
范围 .. ...
提供了包含(..
)和不包含(...
)范围运算符,扩展为表达式
1..5
// => 1 2 3 4 5
1...5
// => 1 2 3 4
5..1
// => 5 4 3 2 1
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"
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
2000ms + (1s * 2)
// => 4000ms
5s / 2
// => 2.5s
4 % 2
// => 0
在属性值中使用 /
时,必须用括号括起来。否则,/
将按字面意思理解(以支持 CSS line-height
)
font: 14px/1.5;
font: 14px/1.5;
但以下内容将计算为 14px
÷ 1.5
font: (14px/1.5);
font: (14px/1.5);
仅对 /
运算符需要这样做。
简写运算符:+= -= *= /= %=
简写运算符的工作方式与其他常用语言类似。对于列表变量,第一个值将用于执行运算符并将列表覆盖为单值变量。对于字符串,节点值只有 += 作为追加函数。对于数字类型值,所有运算符的工作方式与普通数学运算完全相同。颜色值类似。
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
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
2 ** 8
// => 256
相等和关系:== != >= <= > <
相等运算符可用于比较单位、颜色、字符串,甚至标识符。这是一个强大的概念,因为即使是任意标识符(例如 wahoo
)也可以用作原子。函数可以返回 yes
或 no
,而不是 true
或 false
(虽然不建议这样做)。
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
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
只有精确的值才匹配。例如,0 == false
和 null == false
都是 false
。
别名
== is
!= is not
!= isnt
== is
!= is not
!= isnt
真值
Stylus 中几乎所有内容都解析为 true
,包括带后缀的单位。即使是 0%
、0px
等也会解析为 true
(因为在 Stylus 中,混入或函数接受单位作为有效值很常见)。
但是,就算术而言,0
本身是 false
。
长度大于 1 的表达式(或“列表”)被认为是真值。
true
示例
0%
0px
1px
-1
-1px
hey
'hey'
(0 0 0)
('' '')
0%
0px
1px
-1
-1px
hey
'hey'
(0 0 0)
('' '')
false
示例
0
null
false
''
0
null
false
''
逻辑运算符:&& || 和 or
逻辑运算符 &&
和 ||
是别名 and
/ or
,它们应用相同的优先级。
5 && 3
// => 3
0 || 5
// => 5
0 && 5
// => 0
#fff is a 'rgba' and 15 is a 'unit'
// => true
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
nums = 1 2 3
1 in nums
// => true
5 in nums
// => false
一些未定义的标识符
words = foo bar baz
bar in words
// => true
HEY in words
// => 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
vals = (error 'one') (error 'two')
error in vals
// => false
(error 'one') in vals
// => true
(error 'two') in vals
// => true
(error 'something') in vals
// => false
在混入中的示例用法
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)
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;
}
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 ?= white
color = color is defined ? color : white
当使用纯 =
时,我们只需重新赋值
color = white
color = black
color
// => black
color = white
color = black
color
// => black
但当使用 ?=
时,我们的第二次尝试失败(因为变量已经定义)
color = white
color ?= black
color
// => white
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
15 is a 'unit'
// => true
#fff is a 'rgba'
// => true
15 is a 'rgba'
// => false
或者,我们可以使用 type()
BIF
type(#fff) == 'rgba'
// => true
type(#fff) == 'rgba'
// => true
注意: color
是唯一的特殊情况,当左手操作数是 RGBA
或 HSLA
节点时,它会计算为 true
。
变量定义:is defined
此伪二进制运算符不接受右手运算符,并且不计算左手。这允许我们检查变量是否已分配值。
foo is defined
// => false
foo = 15px
foo is defined
// => true
#fff is defined
// => 'invalid "is defined" check on non-variable #fff'
foo is defined
// => false
foo = 15px
foo is defined
// => true
#fff is defined
// => 'invalid "is defined" check on non-variable #fff'
或者,可以使用 lookup(name)
内置函数来执行此操作,或执行动态查找
name = 'blue'
lookup('light-' + name)
// => null
light-blue = #80e2e9
lookup('light-' + name)
// => #80e2e9
name = 'blue'
lookup('light-' + name)
// => null
light-blue = #80e2e9
lookup('light-' + name)
// => #80e2e9
此运算符至关重要,因为未定义的标识符仍然是真值。例如
body
if ohnoes
padding 5px
body
if ohnoes
padding 5px
当未定义时将生成以下 CSS
body {
padding: 5px;
}
body {
padding: 5px;
}
但是这将是安全的
body
if ohnoes is defined
padding 5px
body
if ohnoes is defined
padding 5px
三元
三元运算符在大多数语言中按我们预期的那样工作。它是唯一具有三个操作数(条件表达式、真表达式和假表达式)的运算符。
num = 15
num ? unit(num, 'px') : 20px
// => 15px
num = 15
num ? unit(num, 'px') : 20px
// => 15px
强制类型转换
作为对unit()
内置函数的简洁替代,可以使用语法(expr) unit
来强制后缀。
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)
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)
颜色操作
对颜色的操作提供了一种简洁、富有表现力的方式来更改组件。例如,我们可以对每个 RGB 进行操作
#0e0 + #0e0
// => #0f0
#0e0 + #0e0
// => #0f0
另一个示例是通过添加或减去百分比来调整亮度值。要使颜色变亮,请添加;要变暗,请减去。
#888 + 50%
// => #c3c3c3
#888 - 50%
// => #444
#888 + 50%
// => #c3c3c3
#888 - 50%
// => #444
还可以通过添加或减去度数来调整色相。例如,向此红色值添加50deg
会产生黄色
#f00 + 50deg
// => #ffd500
#f00 + 50deg
// => #ffd500
值适当地钳位。例如,我们可以将色相“旋转”180度,如果当前值为320deg
,它将解析为140deg
。
我们还可以通过使用rgb()
、rgba()
、hsl()
或hsla()
一次调整多个值(包括 alpha)。
#f00 - rgba(100,0,0,0.5)
// => rgba(155,0,0,0.5)
#f00 - rgba(100,0,0,0.5)
// => rgba(155,0,0,0.5)
Sprintf
字符串 sprintf 类似运算符%
可用于生成一个字面值,在内部通过s()
内置函数传递参数
'X::Microsoft::Crap(%s)' % #fc0
// => X::Microsoft::Crap(#fc0)
'X::Microsoft::Crap(%s)' % #fc0
// => X::Microsoft::Crap(#fc0)
多个值应该用括号括起来
'-webkit-gradient(%s, %s, %s)' % (linear (0 0) (0 100%))
// => -webkit-gradient(linear, 0 0, 0 100%)
'-webkit-gradient(%s, %s, %s)' % (linear (0 0) (0 100%))
// => -webkit-gradient(linear, 0 0, 0 100%)