虽然 Stylus 没有一个名为 compose
的特定关键字,但"组合"这个概念指的是复用和组合现有样式规则 ,以创建更复杂、更一致的样式,同时保持代码的 DRY(Don't Repeat Yourself)原则。Stylus 提供了几种强大的机制来实现这一点,主要是 Mixins 和 @extend
(继承)。
下面详细讲解这两种主要方式:
1. 使用 Mixins (混合)
Mixins 允许你定义一组可重用的 CSS 声明,然后在需要的地方像调用函数一样"混入"这些声明。这是最灵活和常用的样式组合方式。
概念:
- 定义一个包含一组样式规则的块。
- 在其他选择器中调用这个块,将这些规则复制到调用处。
- Mixins 可以接受参数,实现动态样式。
代码示例:
stylus
// --- 定义 Mixins ---
// 1. 一个简单的无参 Mixin (例如:清除浮动)
clear-fix()
&:after // 使用父选择器引用符 &
content: ""
display: table
clear: both
// 2. 一个带参数的 Mixin (例如:设置圆角,带默认值)
border-radius(radius = 5px) // 默认 radius 为 5px
-webkit-border-radius: radius
-moz-border-radius: radius
border-radius: radius
// 3. 一个更复杂的 Mixin (例如:创建按钮基础样式,带多个参数)
button-base(padding = 10px 20px, bg-color = #eee, text-color = #333)
display: inline-block
padding: padding
background-color: bg-color
color: text-color
border: 1px solid darken(bg-color, 10%) // 使用 Stylus 内建函数 darken
cursor: pointer
text-align: center
text-decoration: none
&:hover
background-color: darken(bg-color, 5%)
border-color: darken(bg-color, 15%)
// --- 使用 Mixins ---
.container
width: 960px
margin: 0 auto
clear-fix() // 使用 clear-fix Mixin
.card
border: 1px solid #ccc
padding: 15px
border-radius(10px) // 使用 border-radius Mixin,传入 10px
.profile-image
width: 50px
height: 50px
border-radius(50%) // 使用 border-radius Mixin 实现圆形
.button-primary
button-base(12px 25px, blue, white) // 使用 button-base,提供所有参数
.button-secondary
button-base(bg-color = #6c757d, text-color = white) // 使用 button-base,只覆盖部分参数,padding 用默认值
.button-default
button-base() // 使用 button-base,所有参数都用默认值
编译后的 CSS (部分):
css
.container {
width: 960px;
margin: 0 auto;
}
.container:after { /* 来自 clear-fix() */
content: "";
display: table;
clear: both;
}
.card {
border: 1px solid #ccc;
padding: 15px;
-webkit-border-radius: 10px; /* 来自 border-radius(10px) */
-moz-border-radius: 10px;
border-radius: 10px;
}
.profile-image {
width: 50px;
height: 50px;
-webkit-border-radius: 50%; /* 来自 border-radius(50%) */
-moz-border-radius: 50%;
border-radius: 50%;
}
.button-primary { /* 来自 button-base(12px 25px, blue, white) */
display: inline-block;
padding: 12px 25px;
background-color: #0000ff; /* blue */
color: #fff; /* white */
border: 1px solid #0000cc; /* darken(blue, 10%) */
cursor: pointer;
text-align: center;
text-decoration: none;
}
.button-primary:hover {
background-color: #0000e6; /* darken(blue, 5%) */
border-color: #000099; /* darken(blue, 15%) */
}
/* .button-secondary 和 .button-default 类似,应用各自的参数或默认值 */
优点:
- 高复用性: 可以轻松在多处应用同一组样式。
- 可维护性: 修改 Mixin 定义,所有使用它的地方都会更新。
- 灵活性: 参数化使得 Mixin 可以适应不同场景。
- 清晰: 代码意图明确,将样式逻辑封装起来。
缺点:
- 每次调用 Mixin 都会在编译后的 CSS 中复制代码,如果 Mixin 非常大且被大量使用,可能会导致 CSS 文件体积增大。
2. 使用 @extend
(继承)
@extend
允许一个选择器继承另一个选择器的所有样式规则,而不会复制代码。它通过将继承者选择器添加到被继承选择器的规则声明处来实现。
概念:
- 将当前选择器附加到你想要继承样式的那个选择器的规则列表中。
- 最终生成的 CSS 中,共享样式的规则会包含所有继承和被继承的选择器。
代码示例:
stylus
// --- 定义基础样式或占位符 ---
// 1. 定义一个基础类样式
.message
border: 1px solid #ccc
padding: 10px 15px
margin-bottom: 10px
font-family: sans-serif
// 2. 定义一个占位符选择器 (%) - 推荐与 @extend 结合使用
// 占位符本身不会输出到 CSS,除非被 @extend
%alert-base
border-width: 1px
border-style: solid
padding: 12px 18px
margin: 1em 0
font-weight: bold
// --- 使用 @extend ---
// 继承 .message 类
.message-success
@extend .message
border-color: green
background-color: #eaffea
color: darkgreen
.message-error
@extend .message
border-color: red
background-color: #ffeeee
color: darkred
// 继承 %alert-base 占位符
.alert-warning
@extend %alert-base
border-color: orange
background-color: #fffbea
color: #d98200
.alert-info
@extend %alert-base
border-color: blue
background-color: #eafaff
color: darkblue
编译后的 CSS:
css
/* 继承 .message */
.message, .message-success, .message-error { /* 选择器被组合在一起 */
border: 1px solid #ccc;
padding: 10px 15px;
margin-bottom: 10px;
font-family: sans-serif;
}
.message-success {
border-color: green;
background-color: #eaffea;
color: darkgreen;
}
.message-error {
border-color: red;
background-color: #ffeeee;
color: darkred;
}
/* 继承 %alert-base */
/* 注意 %alert-base 本身没有输出 */
.alert-warning, .alert-info { /* 选择器被组合在一起 */
border-width: 1px;
border-style: solid;
padding: 12px 18px;
margin: 1em 0;
font-weight: bold;
}
.alert-warning {
border-color: orange;
background-color: #fffbea;
color: #d98200;
}
.alert-info {
border-color: blue;
background-color: #eafaff;
color: darkblue;
}
优点:
- DRY: 真正实现了样式规则的共享,避免了代码重复。
- 更小的 CSS: 通常会生成比使用 Mixins 更小的 CSS 文件,因为规则只写一次。
- 语义关联: 明确表达了选择器之间的继承关系。
缺点:
- 紧密耦合: 继承者和被继承者在生成的 CSS 中紧密关联。如果滥用,可能导致选择器列表过长、过于复杂,难以调试。
- 特异性 (Specificity) 问题: 可能无意中改变了样式的应用顺序或特异性。
- 无法参数化:
@extend
不能像 Mixins 那样接受参数。它只是简单地继承样式。 - 潜在的选择器膨胀: 如果继承链过长或交叉继承过多,最终生成的选择器列表可能非常庞大。
占位符 (%
) 的作用:
使用占位符 (%placeholder
) 作为 @extend
的目标是个好习惯。这样可以确保基础样式本身不会生成不必要的 CSS 类,只在被 @extend
时才输出组合后的规则。这避免了在 HTML 中可能根本不会使用的 .base-class
。
总结与选择
-
何时使用 Mixins?
- 当你需要参数化的样式片段时(例如,不同的颜色、大小)。
- 当你想要应用一组工具性 的样式(例如
clear-fix
,text-ellipsis
)而不希望它们在 CSS 输出中产生复杂的选择器组合时。 - 当你希望保持较低的选择器耦合度时。
-
何时使用
@extend
?- 当你有一组元素共享完全相同 的基础样式,并且你想在语义上表达这种"is-a"关系时(例如,
.button-primary
is a.button
)。 - 当你非常关心最终 CSS 的体积,并且确定继承关系不会导致过于复杂的选择器时。
- 强烈建议与占位符 (
%
) 结合使用,以避免输出未使用的基类。
- 当你有一组元素共享完全相同 的基础样式,并且你想在语义上表达这种"is-a"关系时(例如,
在实际项目中,通常会结合使用 Mixins 和 @extend
。例如,用 @extend
继承基础结构和主题,用 Mixins 添加可配置的功能或变体。