stylus语法简介
stylus的安装与使用
stylus介绍就不需要了,直接进入主题吧。
stylus的安装
此处只介绍sublime中使用stylus编译的安装方法,因个人比较喜欢使用sublime。
- node肯定是要有的;
- 全局安装stylus: npm install stylus -g;
- sublime中搜索stylus插件,下载安装,设置stylus的个人配置;
- 重启sublime,创建 .styl 文件保存就会自动编译了。
- 以上的stylus插件只提供了编译与高亮,并不会有语法补与提示,所以还要安装一个stylus-clean-completions插件就ok了!
如果需要自动前置添加的话,最好还是工程化后结合gulp对编译后的css进行处理,此点less也是如此。
基本配置如下:
{ "envPATH": "", //环境的路径 "binDir": "", //项目路径 "compileOnSave": true, //是否编辑保存 "compileDir": true, //编译到指定目录 "compress": true, //是否压缩 "compilePaths": {"": ""} //输出路径,此项不要默认在styl相同路径生成css }
stylus语法简介
语法的话参考 张鑫旭翻译的stylus文档 就行了,本文只挑选一些常用的语法出来,便于及时查看。感谢张大大的无私奉献!
选择器
stylus的冒号、花括号、分号均可以省略替代;
stylus通过空格,缩排来代替花括号,故缩进很重要;body color #fff
Stylus就跟CSS一样,允许你使用逗号为多个选择器同时定义属性,使用新行是一样的效果:
textarea input border 1px solid #eee //等同于: textarea, input border 1px solid #eee
父级引用,同less一样,用
&
代表;
消除歧义,类似padding - n的表达式可能既被解释成减法运算,也可能被释义成一元负号属性。为了避免这种歧义,用括号包裹表达式:pad(n) padding (- n) body pad(5px)
然而,只有在函数中才会这样(因为函数同时用返回值扮演混合或回调)。
变量
stylus以等式的方式定义变量,变量替换时,会将变量值全部替换到使用的变量名位置,变量值中还可以包含变量;标识符(变量名,函数等),也可能包括$字符。变量冒失只能在冒号右边有效,左边属性名内会被当成属性名而无效。
font-size = 14px
font = font-size "Lucida Grande", Arial
body
font font sans-serif
//会被编译为:
body {
font: 14px "Lucida Grande", Arial 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)
我们不使用这里的变量w和h, 而是简单地前置 `@` 字符在属性名前来访问该属性名对应的值:
#logo
position: absolute
top: 50%
left: 50%
width: 150px
height: 80px
margin-left: -(@width / 2)
margin-top: -(@height / 2)
若 `@` 的属性没有被定义,则属性会“向上冒泡”查找堆栈直到被发现,或者返回null(如果属性搞不定)。下面这个例子,@color被弄成了blue。
body
color: red
ul
li
color: blue
a
background-color: @color
变量赋值时,若后面的值内容有空格分隔,则变量可以当做数组来看待:
size = 10px 15px
body
font-size size[0]
padding size
//编译为:
body {
font-size:10px;
padding:10px 15px
}
插值
Stylus支持通过使用{}字符包围 表达式 来插入值,其会变成标识符的一部分。例如,-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 1px 2px / 3px 4px // 编译为 button { -webkit-border-radius: 1px 2px / 3px 4px; -moz-border-radius: 1px 2px / 3px 4px; border-radius: 1px 2px / 3px 4px; } table for row in 1 2 tr:nth-child({row}) height: 10px * row // 编译为 table tr:nth-child(1) { height: 10px; } table tr:nth-child(2) { height: 20px; }
运算符
这一部分比较杂乱,复杂的运用一般不多,若遇到了可以参考 此文档。
混合书写
混入和函数定义方法一致,但是应用却大相径庭。mixins作为状态调用,而非表达式调用,仅仅是一些模块化的状态封装而已;minxins使用的时候,其内部属性会被复制到对应的选择器中。
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] border-radius 5px // 编译为如下,mix调用时,甚至不需要编写括号。 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 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); }
混合书写可以利用父级引用字符
&
, 继承父业而不是自己筑巢,也就是mixins最外层的&
引用引的是mixins调用的环境父级。自然,混合书写可以利用其它混合书写,建立在它们自己的属性和选择器上。
方法
语言函数定义,其定义与混入(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
返回多值:Stylus的函数可以返回多个值,就像你给变量赋多个值一样。
sizes() 15px 10px sizes()[0] // => 15px
有个小小的例外就是返回值是标识符。例如,下面看上去像一个属性赋值给Stylus(因为没有操作符)。为避免歧义,我们可以使用括号,或是return关键字。
swap(a, b) b a swap(a, b) (b a) swap(a, b) return b a
条件:简单的 if…else… 应用。
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
注意:yes和no并不是布尔值。本例中,它们只是简单的未定义标识符。
别名:给函数起别名类似于定义变量。
add(a, b) a + b plus = add plus(1, 2) // => 3
变量函数:把函数当作变量传递到新的函数中。
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是所有函数体都有的局部变量,包含传递的所有参数。mixins中也有arguments变量,同函数一致。
sum() n = 0 for num in arguments n = n + num sum(1,2,3,4,5) // => 15
关键字参数
Stylus支持关键字参数,或”kwargs”. 允许你根据相关参数名引用参数,参数的顺序可以打乱,因为有的关键字,但这种情况一般使用的很少,个人感觉其实是加大了开发的复杂度,故此处就不再讨论。
内置方法
red(color):返回color中的红色比重。
green(color):返回color中的绿色比重。
blue(color):返回color中的蓝色比重。
alpha(color):返回color中的透明度比重。
dark(color):检查color是否是暗色。
light(color):检查color是否是亮色。
hue(color):返回给定color的色调。
push(expr, args…):后面推送给定的args给expr,别名为append()。
nums = 1 2 push(nums, 3, 4, 5) nums // => 1 2 3 4 5
unshift(expr, args…):起始位置插入给定的args给expr,别名为prepend(),单个单个数据的操作,不是一次将所有args按给定顺序插入。
nums = 4 5 unshift(nums, 3, 2, 1) nums // => 1 2 3 4 5
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-of和type。
type(12) // => 'unit' typeof(12) // => 'unit' typeof(#fff) // => 'rgba' type-of(#fff) // => 'rgba'
unit(unit[, type]):返回unit类型的字符串或空字符串,或者赋予type值而无需单位转换。
unit(10) // => '' unit(15in) // => 'in' unit(15%, 'px') // => 15px unit(15%, px) // => 15px
match(pattern, string):检测string是否匹配给定的pattern。
abs(unit):绝对值。
abs(-5px) // => 5px
ceil(unit):向上取整。
floor(unit):向下取整。
round(unit):四舍五入取整。
min(a, b):取较小值。
max(a, b):取较大值。
even(unit):是否为偶数。
even(6px) // => true
odd(unit):是否为奇数。
sum(nums):求和。
avg(nums):求平均数。
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"
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)
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警告,并不退出。
error(msg):伴随着给定的错误msg退出。
last(expr):返回给定expr的最后一个值。
opposite-position(positions):返回给定positions相反内容。
opposite-position(right) // => left opposite-position(top left) // => bottom right
其余参数
Stylus支持
name...
形式的其余参数。这些参数可以消化传递给混写或函数的参数们。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; }
offset-x设定一个专门的变量接收第一个传入的参数,剩余的参数统统传到args类数组中,不过传入的数据好像不能实现表达式的精确传递,比如逗号就有问题,故推荐直接使用
arguments
参数处理。注释
Stylus支持三种注释,单行注释,多行注释,以及多行缓冲注释。
// 我是注释! body padding 5px // 蛋疼的padding /* * 给定数值合体 */ add(a, b) a + b /*! * 给定数值合体 */ add(a, b) a + b
单行注释跟JavaScript一样,双斜杠,CSS中不输出;多行注释看起来有点像CSS的常规注释。然而,它们只有在compress选项未启用的时候才会被输出;多行缓冲注释跟多行注释类似,不同之处在于开始的时候,这里是/*!. 这个相当于告诉Stylus压缩的时候这段无视直接输出。
条件
if / else if / else:跟一般的语言一致,if表达式满足(true)的时候执行后面语句块,否则,继续后面的else if或else。
box(x, y, margin-only = false) if margin-only margin y x else padding y x
unless:除非,基本上与if相反,本质上是(!(expr))。
后缀条件:Stylus支持后缀条件,这就意味着if和unless可以当作操作符;当右边表达式为真的时候执行左边的操作对象,有点类似于三目运算;
negative(n) error('无效数值') unless n is a 'unit' return yes if n < 0 no
迭代
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; }
后缀:就跟if/unless可以利用后面语句一样,for也可以。如下后缀解析的例子:
sum(nums) sum = 0 sum += n for n in nums
不过为了方便理解,个人不建议使用这种方式。
导入
Stylus支持字面@import CSS, 也支持其他Stylus样式的动态导入。
@import "reset.css"
当使用@import没有
.css
扩展,会被认为是Stylus片段(如:@import "mixins/border-radius"
)。媒体
@media
工作原理和在常规CSS中一样,但是,要使用Stylus的块状符号。@media print #header #footer display none
自定义字体
@font-face
跟其在CSS中作用表现一样,在后面简单地添加个块状属性即可,类似下面:@font-face font-family Geo font-style normal src url(fonts/geo_sans_light/GensansLight.ttf) .ingeo font-family Geo
动画定义
Stylus支持@keyframes规则,当编译的时候转换成@-webkit-keyframes,使用@keyframes,通过vendors变量,会自动添加私有前缀(webkit moz official),official 为标准解析。
继承
Stylus的
@extend
指令受SASS实现的启发,基本一致,除了些轻微差异。此功能大大简化了继承其他语义规则集的语义规则集的维护;把对应的选择器传给@extend
即可继承已存在的选择器规则;此方式用 mixins 也可以实现,两种方式均比较简便,对于已有的规则集,一般使用 extend,若公共的规则比较多,建议使用 mixins 。.message { padding: 10px; border: 1px solid #eee; } .warning { @extend .message; color: #E2E21E; }
目前Stylus与SASS不同之处在于SASS不允许@extend嵌套选择器,Stylus中,只要选择器匹配,就可以生效。
CSS字面量
不管什么原因,如果遇到Stylus搞不定的特殊需求,你可以使用@css使其作为CSS字面量解决之。
@css { body { font: 14px; } } // 编译为 body { font: 14px; }
字符转码
Stylus可以字符转码。这可以让字符变成标识符,或是渲染成字面量。注意Stylus中
/
当作为属性使用的时候需要用括号括起来:body padding 1 \+ 2 body font 14px/1.4 font (14px/1.4) // 编译为 body { padding: 1 + 2; } body { font: 14px/1.4; font: 10px; }
慢慢回味学习吧~