修改Sass中选择器的中间部分(添加/删除类等)

修改Sass中选择器的中间部分(添加/删除类等),sass,css-selectors,Sass,Css Selectors,我的菜单中有以下用于设置链接样式的SCS: nav { ul { li { a { color: red } } } ul.opened { li { a { color: green } } } } 这将生成以下(正确的)CSS: 我尝试

我的菜单中有以下用于设置链接样式的SCS:

nav {
    ul {
        li {
            a {
                color: red
            }
        }
    }

    ul.opened {
        li {
            a {
                color: green
            }
        }
    }
}
这将生成以下(正确的)CSS:

我尝试修改JavaScript,将该类应用于nav元素,并在Sass中使用
selector-append()
来附加该类。但这似乎是以错误的顺序进行追加(如果参数颠倒,则类将追加到最后一个元素!):

输出(不正确!):

有没有一种方法可以重写SCS,以便在不需要重复选择器的情况下正确追加类(类似于
selector-append()
方法)?

简短的答案 由于要替换的元素具有唯一的名称,因此我们要查找的是:

nav {
    ul {
        li {
            a {
                color: red;

                @at-root #{selector-replace(&, 'ul', 'ul.opened')} {
                    color: green;
                }
            }
        }
    }
}
长话短说 操纵选择器是非常肮脏的,我建议不要这样做,除非你必须这样做。如果您通过指定
table tr td
ul li
之类的内容来过度限定选择器,那么从简化开始:tr和ul在这些选择器中都是冗余的(除非您试图避免在有序列表下设置元素的样式)。调整嵌套以使其更简单,等等

从Sass 3.4版开始,有两个重要的特性允许您修改选择器

  • 父选择器可以存储在变量中
例如:

.foo ul > li a, .bar {
    $sel: &;
    @debug $sel;
}
您总是会得到一个字符串列表,因为选择器可以用逗号链接在一起,即使您只有一个选择器

.foo ul > li a, .bar { ... }
 (1  2  3  4 5), (1)
您将注意到,子体选择器在这里被计数(Sass中的列表可以是空格或逗号分隔的)。记住这一点非常重要


选择器-replace()不起作用时
选择器-replace()
功能在以下情况下不起作用:

  • 要替换的选择器不是唯一的(例如,
    ul-li
  • 您想插入一个或多个选择器(例如
    ulli
    ->
    ulli
  • 您要删除选择器(例如,
    ul>li
    ->
    ul-li
在这种情况下,您需要在选择器上循环,并且需要知道要修改的位置。下面的函数将获取一个函数,并使用的魔法将其应用于选择器中的特定位置

附加类(当选择器不唯一或您不知道其名称时) 这里需要的函数有两个参数:原始选择器和要附加到它的选择器。使用简单的插值来完成这项工作

@function append-class($a, $b) {
    @return #{$a}#{$b};
}

.foo, .bar {
    ul > li a {
        color: red;

        @at-root #{selector-nth(&, -2, append-class, '.baz')} {
            color: blue;
        }
    }
}
输出:

.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > li.baz a, .bar ul > li.baz a {
  color: blue;
}
.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > .baz li a, .bar ul > .baz li a {
  color: blue;
}
.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > a, .bar ul > a {
  color: blue;
}
插入选择器 此函数还接受两个参数:原始选择器和要在其前面插入的选择器

@function insert-selector($a, $b) {
    @return $b $a;
}

.foo, .bar {
    ul > li a {
        color: red;

        @at-root #{selector-nth(&, -2, insert-selector, '.baz')} {
            color: blue;
        }
    }
}
输出:

.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > li.baz a, .bar ul > li.baz a {
  color: blue;
}
.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > .baz li a, .bar ul > .baz li a {
  color: blue;
}
.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > a, .bar ul > a {
  color: blue;
}
卸下选择器 删除选择器就像用空字符串替换选择器一样简单

@function remove-selector($sel) {
    @return '';
}

.foo, .bar {
    ul > li a {
        color: red;

        @at-root #{selector-nth(&, -2, remove-selector)} {
            color: blue;
        }
    }
}
输出:

.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > li.baz a, .bar ul > li.baz a {
  color: blue;
}
.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > .baz li a, .bar ul > .baz li a {
  color: blue;
}
.foo ul > li a, .bar ul > li a {
  color: red;
}
.foo ul > a, .bar ul > a {
  color: blue;
}

TL;博士 选择器只是一个列表。任何列表操作函数都会对其起作用,您可以在其上循环以根据需要对其进行修改


所以,除非你真的需要,否则不要这样做。如果您决定仍然需要它,我将这些函数打包到中。

我制作了一个mixin来解决这个问题

Github:

例如:


用法(scss):

祖先{
显示:内联flex;
.祖父母{
填充:32px;
背景颜色:浅绿色;
.家长{
填充:32px;
背景颜色:蓝色;
埃伦先生{
填充:16px;
背景色:白色;
@包含父追加(“:focus”,3){
盒影:嵌入0.8px浅绿色;
}
@包含父附加(“:悬停”){
背景色:紫红色;
}
@包含父附加(“p”,0,true){
背景颜色:绿色;
}
}
}
}
}
结果(css):

祖先{
显示:内联flex;
}
.祖父母{
填充:32px;
背景颜色:浅绿色;
}
.祖先.祖父母.父母{
填充:32px;
背景颜色:蓝色;
}
.祖先.祖父母.父母.元素{
填充:16px;
背景色:白色;
}
.祖先:专注。祖父母。父母。元素{
盒影:嵌入0.8px浅绿色;
}
.祖先.祖父母.父母:hover.elem{
背景色:紫红色;
}
.祖先.祖父母.父母p.elem{
背景颜色:绿色;
}