选择器语法
约 2469 字大约 8 分钟
2025-04-17
提示
如果你觉得 Stylus 的极简语法可读性差,你可以在项目中使用 CSS 风格,保留冒号 :
、分号 ;
、逗号 ,
和括号{ }
,配合 Stylus 的混入、函数、继承等功能,来实现复杂的样式。
这样能避免极简语法带来的一些歧义,避免实际的编译结果和期望不一致,从而提高代码可读性和维护性。
一、基本语法
在 Stylus 中,其语法风格主要如下:
- 缩进:使用缩进代替
{
和}
,来代表嵌套结构。 - 省略冒号
:
:分隔属性和值的:
冒号可以省略。 - 省略分号
;
:行末的;
分号可以省略。 - 省略逗号
,
:分隔属性和值的,
逗号可以省略,群组选择器的,
逗号也可以省略。 - 换行:换行不缩进代表群组选择器,但是建议通过保留逗号来提高代码可读性。
- 兼容 CSS:Stylus 完全兼容 CSS 语法,可以按照 CSS 风格去写。
1、缩进
Stylus 语法是 “python 式”的 (即,基于缩进)。缩进的空格很重要,所以我们使用缩进来代替 {
和 }
,如下所示:
body
color white
编译后:
body {
color: #fff;
}
2、规则嵌套
同样,Stylus 允许通过缩进来实现嵌套。我们可以使用以下原生的 CSS 组合选择符来表示辅助层级关系:
:空格,表示后代元素。
>
:表示直接后代元素- 缩进即
空格
:表示后代元素。
例如:
body
color white
div
color red
> span
color blue
.class1 .class2
color #f00
编译后:
body {
color: #fff;
}
body div {
color: #f00;
}
body > span {
color: blue;
}
body .class1 .class2 {
color: #f00;
}
当我们给嵌套较深的一个层级节点添加或者修改样式时,建议使用空格代替缩进,提高代码可读性。 例如:
.class1 .class2 .class3
color #f00
和
.class1
.class2
.class3
color #f00
二者编译后的结果是一样的,但是前者的可读性更强。
.class1 .class2 .class3 {
color: #f00;
}
3、规则集(群组选择器)
和 CSS 一样,Stylus 允许通过逗号分隔,同时配置多个选择器的属性。
textarea, input
border 1px solid #eee
也可以通过 换行 来实现:
textarea
input
border 1px solid #eee
两种写法都会编译为:
textarea,
input {
border: 1px solid #eee;
}
除此以外,我们还可以使用 CSS 组合选择符来实现一些特殊的关系:
+
: 表示相邻兄弟元素~
: 表示后面的兄弟元素
div + span
border 1px solid #eee
span ~ p
border 1px solid #eee
编译为:
div + span {
border: 1px solid #eee;
}
span ~ p {
border: 1px solid #eee;
}
4、避免歧义
在使用极简风格书写样式代码时,有些选择器或者变量看起来像属性,在我们不注意的情况可能导致解析结和预期不一样。
函数和 Mixin 也是支持省略括号的,也需要注意这个问题。
例如,下面的foo bar baz
中,在其代码上下文中,可能有两种编译结构:
选择器: 属性1 属性2
选择器1 选择器2 选择器3
div
foo bar baz
> input
border 1px solid
可能会被编译为:
div {
foo: bar baz;
}
div > input {
border: 1px solid;
}
出于提高代码可读性的原因,我们可以在末尾添加一个逗号,来表示这是一个选择器:
div
foo bar baz,
> input
border 1px solid
编译为:
div foo bar baz,
div > input {
border: 1px solid;
}
二、引用
^[N..M]
可以在选择器的任意位置使用,其中 N
和 M
都可以是数字,表示局部引用范围。
N
是起始层级(从 0 开始,0 表示当前层级)。M
是结束层级(可选,如果省略则默认到最外层)。- 类似于
../
路径引用,但更灵活。
1、父引用 &
&
符号代表当前选择器的父级选择器。相当于^[0..M]
, M
是当前选择器的层级。
例如,在以下例子中:
&
代表的是div texrarea, div input
,- 而
&:hover
代表的是div texrarea:hover, div input:hover
。
div
textarea
input
color #A7A7A7
&:hover
color #000
编译为:
div textarea,
div input {
color: #a7a7a7;
}
div textarea:hover,
div input:hover {
color: #000;
}
下面是一个使用混入(mixin)
中的父引用为 IE 浏览器中的元素添加 2px
边框的例子:
box-shadow()
-webkit-box-shadow arguments
-moz-box-shadow arguments
box-shadow arguments
html.ie8 &,
html.ie7 &,
html.ie6 &
border 2px solid arguments[length(arguments) - 1]
body
#login
box-shadow 1px 1px 3px #eee
编译为:
body #login {
-webkit-box-shadow: 1px 1px 3px #eee;
-moz-box-shadow: 1px 1px 3px #eee;
box-shadow: 1px 1px 3px #eee;
}
html.ie8 body #login,
html.ie7 body #login,
html.ie6 body #login {
border: 2px solid #eee;
}
如果需要在选择器中单纯地使用&
符,不使用其父级引用的功能,可以通过转义符\
来转义:
.foo[title*='\&']
// => .foo[title*='&']
2、局部引用 ^[N]
^[N]
可以在选择器的任意位置使用,其中 N
代表一个数字,表示局部引用。
局部引用其实就是父级引用的局部引用,父级引用包含整个选择器,而局部选择器只包含嵌套选择器的前N
个合并层级,因此您可以单独访问这些嵌套层级。
^[0]
会返回第一层级的完整选择器,^[1]
会返回第二层级的渲染后选择器,以此类推:
.foo
&__bar
width: 10px
^[0]:hover &
width: 20px
^[1]:hover
width: 20px
编译为:
.foo__bar {
width: 10px;
}
.foo:hover .foo__bar {
width: 20px;
}
.foo__bar:hover {
width: 20px;
}
2、负值引用 ^[-N]
负值表示从末尾开始计数,因此 ^[-1]
会返回 &
之前的最后一个选择器:
.foo
&__bar
&_baz
width: 10px
^[-1]:hover &
width: 20px
编译为:
.foo__bar_baz {
width: 10px;
}
.foo__bar:hover .foo__bar_baz {
width: 20px;
}
负值在混入(mixin)中特别有用,当你不确定当前调用所处的嵌套层级时。
需要注意的是,局部引用包含整个渲染后的选择器链,从顶层直到指定的嵌套级别
3、范围引用 ^[N..M]
如果您需要获取选择器的原始部分,或以编程方式获取部分范围,可以在局部引用中使用范围。
如果范围从正值开始,结果将不包含前几级的选择器,您将得到的结果就像这些级别的选择器被插入到样式表的根目录中,并省略了组合器:
.foo
& .bar
width: 10px
^[0]:hover ^[1..-1]
width: 20px
编译为:
.foo .bar {
width: 10px;
}
.foo:hover .bar {
width: 20px;
}
范围中的第一个数字表示起始索引,第二个数字表示结束索引。需要注意的是,这些数字的顺序并不重要,因为选择器总是从第一层级到最后层级进行渲染,所以^[1..-1]
等同于^[-1..1]
。
当两个数字相等时,结果将只是选择器的一个原始层级。因此,您可以将前面示例中的^[1..-1]
替换为^[-1..-1]
,这样会得到相同的最后一个原始选择器,但在混入(mixin)
中使用时会更可靠。
4、初始引用 ~/
选择器开头的~/
字符可用于指向嵌套层级的最外层选择器,可以视为^[0]
的快捷方式。唯一的限制是初始引用只能在选择器(每一行)的开头使用:
.block
&__element
~/:hover &
color: red
编译为:
.block:hover .block__element {
color: red;
}
5、相对引用 ../
选择器开头的../
字符表示相对引用,指向&
编译后的前一个选择器。你可以嵌套相对引用:../../
来获取更深层级的引用,但请注意它只能在选择器的开头使用。
.foo
.bar
width: 10px
&,
../ .baz
height: 10px
编译为:
.foo .bar {
width: 10px;
}
.foo .bar,
.foo .baz {
height: 10px;
}
相对引用可以视为局部引用范围(如^[0..-(N + 1)]
)的快捷方式,其中N
表示相对引用的使用次数。
6、根引用 /
选择器开头的/
字符表示根引用。它引用根上下文,这意味着选择器不会在其前面添加父选择器(除非与&
一起使用)。当您需要同时为嵌套选择器和不在当前作用域中的另一个选择器编写样式时,这很有帮助。
textarea
input
color #A7A7A7
&:hover,
/.is-hovered
color #000
编译为:
textarea,
input {
color: #a7a7a7;
}
textarea:hover,
input:hover,
.is-hovered {
color: #000;
}
三、selector() 内置函数
1、获取选择器
你可以使用内置的 selector()
函数来获取当前编译后的选择器。这个函数可以在混入(mixin)
中使用,用于检查或实现其他巧妙的功能。
.foo
selector()
// => '.foo'
.foo
&:hover
selector()
// '.foo:hover'
2、生成选择器节点
该内置函数还可以接受一个可选的字符串参数,这种情况下它会返回编译后的选择器。
需要注意的是,如果参数中不包含任何&
符号,它不会在当前作用域的选择器前添加前缀。
.foo
selector('.bar')
// => '.bar'
.foo
selector('&:hover')
// '.foo:hover'
2、多个选择器
selector()
内置函数可以接受多个值或以逗号分隔的列表,方便我们更轻松地创建嵌套选择器结构。
{selector('.a', '.b', '.c, .d')}
color: red
等同于:
.a
.b
.c,
.d
color: red
最终会渲染为:
.a .b .c,
.a .b .d {
color: #f00;
}
四、歧义消除
像 margin - n
这样的表达式可能被解释为减法运算,也可能被解释为带有负号的属性。为了消除歧义,需要用括号将表达式括起来:
pad(n)
margin (- n)
body
pad(5px)
编译为:
body {
margin: -5px;
}
然而,这种情况仅适用于函数中(因为函数既可以作为混入使用,也可以作为返回值调用)。
例如,以下写法也是可行的(并且会产生与上面相同的结果):
body
margin -5px
遇到 Stylus 无法处理的特殊属性值?unquote()
函数可以帮你解决:
filter unquote('progid:DXImageTransform.Microsoft.BasicImage(rotation=1)')
编译为:
filter progid:DXImageTransform.Microsoft.BasicImage(rotation=1)
更新日志
e7112
-1于