小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文承接《Stylus 学习使用整理总结(上)》,整理归纳了 Stylus 的进阶用法,包括剩余参数、条件、内置方法等。
Stylus进阶用法
剩余参数
剩余参数
Stylus 支持 name... 形式的其余参数。这些参数可以消化传递给混写或函数的参数们。这在处理浏览器私有属性,如 -moz 或 -webkit 的时候很管用。下面这个例子中,所有的参数 (1px, 2px, ...) 都被一个 args 参数给简单处理了:
box-shadow(args...)
-webkit-box-shadow args
-moz-box-shadow args
box-shadow args
#login
box-shadow 1px 2px 5px #eee
生成为:
#login {
-webkit-box-shadow: 1px 2px 5px #eee;
-moz-box-shadow: 1px 2px 5px #eee;
box-shadow: 1px 2px 5px #eee;
}
想指定特定的参数,如 x-offset,可以使用 args[0], 或者,可能希望重新定义混入。
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;
}
参数
arguments 变量可以实现表达式的精确传递,包括逗号等等。这可以弥补 args... 参数的一些不足,例子:
box-shadow(args...)
-webkit-box-shadow args
-moz-box-shadow args
box-shadow args
#login
box-shadow #ddd 1px 1px, #eee 2px 2px
结果并非想要得到的:
#login {
-webkit-box-shadow: #ddd 1px 1px #eee 2px 2px;
-moz-box-shadow: #ddd 1px 1px #eee 2px 2px;
box-shadow: #ddd 1px 1px #eee 2px 2px;
}
逗号被忽略了。现在使用 arguments 重新定义这个混合书写。
box-shadow()
-webkit-box-shadow arguments
-moz-box-shadow arguments
box-shadow arguments
body
box-shadow #ddd 1px 1px, #eee 2px 2px
得到想要的结果:
body {
-webkit-box-shadow: #ddd 1px 1px, #eee 2px 2px;
-moz-box-shadow: #ddd 1px 1px, #eee 2px 2px;
box-shadow: #ddd 1px 1px, #eee 2px 2px;
}
条件
条件
条件提供了语言的流控制,否则就是纯粹的静态语言。提供的条件有导入、混入、函数以及更多。
if / else if / else
跟一般的语言一致, if 表达式满足 (true) 的时候执行后面语句块,否则,继续后面的 else if 或 else.
下面这个例子,根据 overload 的条件,决定是使用 padding 还是 margin.
overload-padding = true
if overload-padding
padding(y, x)
margin y x
body
padding 5px 10px
另外的例子:
box(x, y, margin = false)
padding y x
if margin
margin y x
body
box(5px, 10px, true)
另外的box()帮手:
box(x, y, margin-only = false)
if margin-only
margin y x
else
padding y x
除非(unless)
熟悉 Ruby 程序语言的用户应该都知道 unless 条件,其基本上与 if 相反,本质上是 (!(expr)).
下面这个例子中,如果 disable-padding-override 是 undefined 或 false, padding 将被干掉,显示 margin 代替之。但是,如果是 true, padding 将会如期继续输出 padding 5px 10px.
disable-padding-override = true
unless disable-padding-override is defined and disable-padding-override
padding(x, y)
margin y x
body
padding 5px 10px
后缀条件
Stylus 支持后缀条件,这就意味着 if 和 unless 可以当作操作符;当右边表达式为真的时候执行左边的操作对象。例如,我们定义 negative() 来执行一些基本的检查。下面我们使用块式条件:
negative(n)
unless n is a 'unit'
error('无效数值')
if n < 0
yes
else
no
接下来,利用后缀条件让我们的方法简洁。
negative(n)
error('无效数值') unless n is a 'unit'
return yes if n < 0
no
当然,我们可以更进一步。如这个 n < 0 ? yes : no 可以用布尔代替:n < 0。后缀条件适用于大多数的单行语句。如,@import, @charset, 混合书写等。当然,下面所示的属性也是可以的:
pad(types = margin padding, n = 5px)
padding unit(n, px) if padding in types
margin unit(n, px) if margin in types
body
pad()
body
pad(margin)
body
apply-mixins = true
pad(padding, 10) if apply-mixins
结果为:
body {
padding: 5px;
margin: 5px;
}
body {
margin: 5px;
}
body {
padding: 10px;
}
迭代
迭代
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;
}
混合书写(Mixins)
我们可以在混写中使用循环实现更强大的功能,例如,我们可以把表达式对作为使用插值和循环的属性。下面,我们定义 apply(), 利用所有的 arguments,这样逗号分隔以及表达式列表都会支持。
apply(props)
props = arguments if length(arguments) > 1
for prop in props
{prop[0]} prop[1]
body
apply(one 1, two 2, three 3)
body
list = (one 1) (two 2) (three 3)
apply(list)
函数(Functions)
Stylus 函数同样可以包含 for 循环。下面就是简单使用示例:
求和:
sum(nums)
sum = 0
for n in nums
sum += n
sum(1 2 3) // => 6
连接:
join(delim, args)
buf = ''
for arg, index in args
if index
buf += delim + arg
else
buf += arg
join(', ', foo bar baz) // => "foo, bar, baz"
后缀(Postfix)
和 if/unless 可以利用后面语句一样,for 也可以。如下后缀解析的例子:
sum(nums)
sum = 0
sum += n for n in nums
join(delim, args)
buf = ''
buf += i ? delim + arg : arg for arg, i in args
我们也可以从循环返回,下例子就是 n % 2 == 0 为 true 的时候返回数值。
first-even(nums)
return n if n % 2 == 0 for n in nums
first-even(1 3 5 5 6 3 2) // => 6
@IMPORT
导入
Stylus 支持字面 @import CSS, 也支持其他 Stylus 样式的动态导入。
字面CSS
任何 .css 扩展的文件名将作为字面量。例如:
@import "reset.css"
渲染如下:
@import "reset.css"
Stylus导入
- 当使用
@import没有.css扩展,会被认为是Stylus片段(如:@import "mixins/border-radius")。 @import工作原理为:遍历目录队列,并检查任意目录中是否有该文件(类似node的require.paths)。该队列默认为单一路径,从filename选项的dirname衍生而来。 因此,如果你的文件名是/tmp/testing/stylus/main.styl,导入将显现为/tmp/testing/stylus/。@import也支持索引形式。这意味着当你@import blueprint, 则会理解成blueprint.styl或blueprint/index.styl. 下面语句:
@import 'mixins/vendor'
等同于:
.import('mixins/vendor')
@MEDIA
@media 工作原理和在常规 CSS 中一样,但是要使用 Stylus 的块状符号。
@media print
#header
#footer
display none
生成为:
@media print {
#header,
#footer {
display: none;
}
}
@FONT-FACE
@font-face 跟其在 CSS 中作用表现一样,在后面简单地添加个块状属性即可,例如:
@font-face
font-family Geo
font-style normal
src url(fonts/geo_sans_light/GensansLight.ttf)
.ingeo
font-family Geo
生成为:
@font-face {
font-family: Geo;
font-style: normal;
src: url("fonts/geo_sans_light/GensansLight.ttf");
}
.ingeo {
font-family: Geo;
}
@KEYFRAMES
@keyframes
Stylus 支持 @keyframes 规则,当编译的时候转换成@-webkit-keyframes:
@keyframes pulse
0%
background-color red
opacity 1.0
-webkit-transform scale(1.0) rotate(0deg)
100%
background-color red
opacity 1.0
-webkit-transform scale(1.0) rotate(0deg)
生成为:
@-webkit-keyframes pulse {
0% {
background-color: red;
opacity: 1;
-webkit-transform: scale(1) rotate(0deg);
}
100% {
background-color: red;
opacity: 1;
-webkit-transform: scale(1) rotate(0deg);
}
}
扩展
使用 @keyframes,通过 vendors变量,会自动添加私有前缀(webkit moz official)。这意味着可以在任意时候立即高效地做修改。考虑下面的例子:
@keyframes foo {
from {
color: black
}
to {
color: white
}
}
扩增两个默认前缀,官方解析:
@-moz-keyframes foo {
0% {
color: #000;
}
100% {
color: #fff;
}
}
@-webkit-keyframes foo {
0% {
color: #000;
}
100% {
color: #fff;
}
}
@keyframes foo {
0% {
color: #000;
}
100% {
color: #fff;
}
}
如果我们只想有标准解析,很简单,修改 vendors:
vendors = official
@keyframes foo {
from {
color: black
}
to {
color: white
}
}
生成为:
@keyframes foo {
0% {
color: #000;
}
100% {
color: #fff;
}
}
内置方法
red(color)
返回 color 中的红色比重。
red(#c00) // => 204
green(color)
返回 color 中的绿色比重。
green(#0c0) // => 204
blue(color)
返回 color 中的蓝色比重。
blue(#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%
push(expr, args…)
后面推送给定的 args 给 expr.
nums = 1 2
push(nums, 3, 4, 5)
nums // => 1 2 3 4 5
别名为
append().
unshift(expr, args…)
起始位置插入给定的 args 给 expr.
nums = 4 5
unshift(nums, 3, 2, 1)
nums // => 1 2 3 4 5
别名为
prepend().
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(12) // => 'unit'
typeof(12) // => 'unit'
typeof(#fff) // => 'rgba'
type-of(#fff) // => 'rgba'
别名有
type-of和type.
unit(unit[, type])
返回 unit 类型的字符串或空字符串,或者赋予 type 值而无需单位转换。
unit(10) // => ''
unit(15in) // => 'in'
unit(15%, 'px') // => 15px
unit(15%, px) // => 15px
match(pattern, string)
检测 string 是否匹配给定的 pattern.
match('^foo(bar)?', foo) // => true
match('^foo(bar)?', 'foobar') // => true
match('^foo(bar)?', 'bar') // => false
abs(unit)
返回绝对值。
abs(-5px) // => 5px
abs(5px) // => 5px
ceil(unit)
向上取整。
ceil(5.5in) // => 6in
floor(unit)
向下取整。
floor(5.6px) // => 5px
round(unit)
四舍五入取整。
round(5.5px) // => 6px
round(5.4px) // => 5px
min(a, b)
取较小值。
min(1, 5) // => 1
max(a, b)
取较大值。
max(1, 5) // => 5
even(unit)
返回是否为偶数。
even(6px)
// => true
odd(unit)
返回是否为奇数。
odd(5mm) // => true
sum(nums)
求和。
sum(1 2 3) // => 6
avg(nums)
求平均数。
avg(1 2 3) // => 2
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"
hsla(color | h,s,l,a)
转换给定 color 为 HSLA 节点,或 h,s,l,a 比重值。
hslaa(10deg, 50%, 30%, 0.5) // => HSLA
hslaa(#ffcc00) // => HSLA
hsla(color | h,s,l)
转换给定 color 为 HSLA 节点,或 h,s,l 比重值。
hsla(10, 50, 30) // => HSLA
hsla(#ffcc00) // => HSLA
rgba(color | r,g,b,a)
从 r,g,b,a 通道返回 RGBA, 或提供 color 来调整透明度。
rgba(255,0,0,0.5) // => rgba(255,0,0,0.5)
rgba(255,0,0,1) // => #ff0000
rgba(#ffcc00, 0.5) // rgba(255,204,0,0.5)
// 另外,stylus支持#rgba以及#rrggbbaa符号。
#fc08 // => rgba(255,204,0,0.5)
#ffcc00ee // => rgba(255,204,0,0.9)
rgb(color | r,g,b)
从 r,g,b 通道返回 RGBA 或生成一个 RGBA 节点。
rgb(255,204,0) // => #ffcc00
rgb(#fff) // => #fff
lighten(color, amount)
给定 color 增亮 amount值。该方法单位敏感,例如,支持百分比,如下:
lighten(#2c2c2c, 30) // => #787878
lighten(#2c2c2c, 30%) // => #393939
darken(color, amount)
给定 color 变暗 amount 值。该方法单位敏感,例如,支持百分比,如下:
darken(#D62828, 30) // => #551010
darken(#D62828, 30%) // => #961c1c
desaturate(color, amount)
给定 color 饱和度减小 amount.
desaturate(#f00, 40%) // => #c33
saturate(color, amount)
给定 color 饱和度增加 amount.
saturate(#c33, 40%) // => #f00
invert(color)
颜色反相。红绿蓝颜色反转,透明度不变。
invert(#d62828) // => #29d7d7
unquote(str | ident)
给定 str 引号去除,返回 Literal 节点。
unquote("sans-serif") // => sans-serif
unquote(sans-serif) // => sans-serif
unquote('1px / 2px') // => 1px / 2px
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)
为表现一致检测这个%字符串操作符。
operate(op, left, right)
在 left 和 right 操作对象上执行给定的 op.
op = '+'
operate(op, 15, 5) // => 20
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 警告,并不退出。
warn("oh noes!")
error(msg) // 伴随着给定的错误msg退出。
add(a, b)
unless a is a 'unit' and b is a 'unit'
error('add() expects units')
a + b
last(expr)
返回给定 expr 的最后一个值。
nums = 1 2 3
last(nums)
last(1 2 3) // => 3
list = (one 1) (two 2) (three 3)
last(list) // => (three 3)
p(expr)
检查给定的 expr.
fonts = Arial, sans-serif
p('test')
p(123)
p((1 2 3))
p(fonts)
p(#fff)
p(rgba(0,0,0,0.2))
add(a, b)
a + b
// p(add) 标准输出:
inspect: "test"
inspect: 123
inspect: 1 2 3
inspect: Arial, sans-serif
inspect: #fff
inspect: rgba(0,0,0,0.2)
inspect: add(a, b)
opposite-position(positions)
返回给定 positions 相反内容。
opposite-position(right) // => left
opposite-position(top left) // => bottom right
opposite-position('top' 'left') // => bottom right
image-size(path)
返回指定 path 图片的 width 和 height. 向上查找路径的方法和 @import 一样,paths 设置的时候改变。
width(img)
return image-size(img)[0]
height(img)
return image-size(img)[1]
image-size('tux.png') // => 405px 250px
image-size('tux.png')[0] == width('tux.png') // => true
add-property(name, expr)
使用给定的 expr 为最近的块域添加属性 name。
例如:
something()
add-property('bar', 1 2 3)
s('bar')
body
foo: something()
结果:
body {
bar: 1 2 3;
foo: bar;
}
接下来,神奇 的 current-property 局部变量将大放异彩,这个变量自动提供给函数体,且包含当前属性名和值的表达式。例如,使用 p()检查这个局部变量,可以得到:
p(current-property) // => "foo" (foo __CALL__ bar baz)
p(current-property[0]) // => "foo"
p(current-property[1]) // => foo __CALL__ bar baz
使用 current-property 可以让例子走得更远点,使用新值复制该属性,且确保功能的条件仅在属性值中使用。
something(n)
if current-property
add-property(current-property[0], s('-webkit-something(%s)', n))
add-property(current-property[0], s('-moz-something(%s)', n))
s('something(%s)', n)
else
error('something() must be used within a property')
body {
foo: something(15px) bar;
}
生成为:
body {
foo: -webkit-something(15px);
foo: -moz-something(15px);
foo: something(15px) bar;
}
未定义方法
未定义方法一字面量形式输出。例如,我们可以在CSS 中调用 rgba-stop(50%, #fff), 其会按照你所期望的显示,下面这个例子中我们简单定义了方法 stop(), 其返回了字面上 rgba-stop() 调用。
stop(pos, rgba)
rgba-stop(pos, rgba)
stop(50%, orange) // => rgba-stop(50%, #ffa500)