虽然 Karol 的答案近乎完美,但它没有考虑伪元素或伪选择器。此外,如果使用多个复杂选择器,则会重复代码。我想出了一个简化版本:
@mixin parent {
$parents: ();
$parent: '';
@each $selector in & {
$length: length($selector);
$index: 0;
$last-selector: nth($selector, $length);
@if ($length == 1) {
@error "Used parent mixin on a top-level selector";
} @else {
$index: str-index($last-selector, '::');
@if ($index) {
$last-selector: str-slice($last-selector, 1, $index - 1);
} @else {
$last-selector: null;
}
// Inspect allows us to combine two selectors in one block.
$parent: inspect(set-nth($selector, $length, #{$last-selector}));
$parents: join($parents, $parent, comma);
}
}
@at-root #{$parents} {
@content;
}
}
有第一个循环遍历选择器列表(选择器末尾带有逗号)。因为复杂的选择器也被视为一个列表,我们只需要删除列表的最后一个元素。没有循环遍历复合选择器或简单选择器,因为我们只需要丢弃最后一个。
Sass 中没有删除列表元素的功能,但我们可以使用 设置元素的值set-nth
。通过将最后一个元素设为空字符串并取消引用,我们可以从列表的打印表示(字符串)中删除最后一个元素。由于选择器可以是字符串,我们只需将新字符串用作选择器。
使用以下内容时:
.grandmother,
.grandfather {
.parent {
.child {
font-size: 10em;
@include parent {
font-size: 5em;
}
&::after {
font-size: 1px;
@include parent {
font-weight: bold;
}
}
}
}
}
我们得到以下信息:
.grandmother .parent .child,
.grandfather .parent .child {
font-size: 10em;
}
.grandmother .parent,
.grandfather .parent {
font-size: 5em;
}
.grandmother .parent .child::after,
.grandfather .parent .child::after {
font-size: 1px;
}
.grandmother .parent .child,
.grandfather .parent .child {
font-weight: bold;
}
注意:伪元素和伪选择器不是元素的子元素,而是附加到元素上,因此它们本身没有父元素。我认为父母是指 Sass 嵌套意义上的父母。