We must strive to become good ancestors.
We must strive to become good ancestors.
Sass 提供了双亲选择器 & 用以在嵌套选择器中引用外部的选择器,本文聊聊如何进一步往外引用,为当前选择器添加祖先选择器。
在 Sass 中双亲选择器(Parent Selector 有时也叫父选择器) &
是一个十分有用且常用的选择器,它可以复用外部选择器的名字,从而更轻松地实现多重样式编写。
.btn {
background: transparent;
&:hover {
background: grey;
}
}
会输出
.btn {
background: transparent;
}
.btn:hover {
background: grey;
}
有时候我们遇到这样一种模式,如主题样式,在元素根处可能有 .dark-theme
来说明目前处于黑暗模式;或者使用 Modernizr 检测浏览器特性,在根元素会根据环境添加相应 class 表示特性支持情况。这时候我们写样式可能就需要拆分开来写。
.btn {
background: transparent;
&:hover {
background: grey;
}
}
.dark-theme .btn { background: linear-gradient(cornflowerblue, rebeccapurple);}
这里有两点不太舒服的地方:
我们来看看如何解决这两个痛点。
在 Sass 中有一个 at 规则叫 @at-root
,它可以跳出当前嵌套直接在文档根输出内容。
.btn {
background: transparent;
&:hover {
background: grey;
}
@at-root .dark-theme & { background: linear-gradient(cornflowerblue, rebeccapurple); }}
会输出
.btn {
background: transparent;
}
.btn:hover {
background: grey;
}
.dark-theme .btn {
background: linear-gradient(cornflowerblue, rebeccapurple);
}
但这里依然没有解决祖先选择器名耦合的问题,于是我们进一步抽象。
将以上用法封装为 mixin 即可达到复用。
@mixin dark-theme {
@at-root .dark-theme & {
@content;
}
}
.btn {
background: transparent;
&:hover {
background: grey;
}
@include dark-theme {
background-image: linear-gradient(cornflowerblue, rebeccapurple);
}
}
一些过渡库,如 Vue transition 和 React Transition Group 会设置一系列的类型名,如 .fade-enter
、.fade-exit
,在 Sass 中我们可以直接拼接 &-enter
进行复用,现在让我们的 mixin 也支持:
@mixin dark-theme($modifiers...) {
@if length($modifiers) > 0 {
@each $modifier in $modifiers {
@at-root .dark-theme &#{$modifier} {
@content;
}
}
} @else {
@at-root .dark-theme & {
@content;
}
}
}
.btn {
background: transparent;
&:hover {
background: grey;
}
@include dark-theme {
background: linear-gradient(cornflowerblue, rebeccapurple);
}
@include dark-theme(-enter) {
background: cornflowerblue;
}
@include dark-theme(-enter-active, -exit) {
background: rebeccapurple;
}
}
输出
.btn {
background: transparent;
}
.btn:hover {
background: grey;
}
.dark-theme .btn {
background: linear-gradient(cornflowerblue, rebeccapurple);
}
.dark-theme .btn-enter {
background: cornflowerblue;
}
.dark-theme .btn-enter-active {
background: rebeccapurple;
}
.dark-theme .btn-exit {
background: rebeccapurple;
}
可以看到 @include dark-theme(-enter-active, -exit)
在多个修饰符的情况下生成了单独的重复内容。
要去掉重复我们可以直接拼接选择器。
@mixin dark-theme($modifiers...) {
@if length($modifiers) > 0 {
$selectors: ();
@each $modifier in $modifiers {
$selectors: append(
$selectors,
#{".dard-theme "}#{&}#{$modifier},
comma
);
}
@at-root #{$selectors} {
@content;
}
} @else {
@at-root .dark-theme & {
@content;
}
}
}
输出
.btn {
background: transparent;
}
.btn:hover {
background: grey;
}
.dark-theme .btn {
background: linear-gradient(cornflowerblue, rebeccapurple);
}
.dard-theme .btn-enter {
background: cornflowerblue;
}
.dard-theme .btn-enter-active, .dard-theme .btn-exit { background: rebeccapurple;}
最后我们将这个模式再进一步抽象出来,成为通用的 at-root
mixin。
@mixin at-root($ancestor, $modifiers...) {
@if length($modifiers) > 0 {
$selectors: ();
@each $modifier in $modifiers {
$selectors: append(
$selectors,
#{$ancestor}#{" "}#{&}#{$modifier},
comma
);
}
@at-root #{$selectors} {
@content;
}
} @else {
@at-root #{$ancestor} & {
@content;
}
}
}
现在 dark-theme
可以这么定义。
@mixin dark-theme($modifiers...) {
@include at-root('.dark-mode', $modifiers...) {
@content;
}
}
通过封装 mixin 我们可以方便地在规则内部直接引用祖先选择器定义规则,同时摆脱与祖先类型名的耦合,使到代码可以灵活应对变更。
评论没有加载,检查你的局域网
Cannot load comments. Check you network.