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

Posted

技术标签:

【中文标题】在 Sass 中修改选择器的中间(添加/删除类等)【英文标题】:Modifying the middle of a selector in Sass (adding/removing classes, etc.) 【发布时间】:2015-04-20 00:52:15 【问题描述】:

我的菜单中有以下用于样式链接的 SCSS:

nav 
    ul 
        li 
            a 
                color: red
            
        
    

    ul.opened 
        li 
            a 
                color: green
            
        
    

这会生成以下(正确的)CSS:

nav ul li a 
  color: red;

nav ul.opened li a 
  color: green;

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

nav 
    ul 
        li 
            a 
                color: red;

                @at-root #selector-append('.opened', &) 
                  color: green;
                
            
        
    

输出(不正确!):

nav ul li a 
  color: red;

.openednav ul li a 
  color: green;

有没有一种方法可以重写 SCSS,以便正确附加类而无需复制选择器(类似于 selector-append() 方法)?

【问题讨论】:

【参考方案1】:

我做了一个 mixin 来解决这个问题。

Github:https://github.com/imkremen/sass-parent-append

示例:https://codepen.io/imkremen/pen/RMVBvq


用法(scss):

.ancestor 
  display: inline-flex;

  .grandparent 
    padding: 32px;
    background-color: lightgreen;

    .parent 
      padding: 32px;
      background-color: blue;

      .elem 
        padding: 16px;
        background-color: white;

        @include parent-append(":focus", 3) 
          box-shadow: inset 0 0 0 8px aqua;
        

        @include parent-append(":hover") 
          background-color: fuchsia;
        

        @include parent-append("p", 0, true) 
          background-color: green;
        
      
    
  

结果(css):

.ancestor 
  display: inline-flex;

.ancestor .grandparent 
  padding: 32px;
  background-color: lightgreen;

.ancestor .grandparent .parent 
  padding: 32px;
  background-color: blue;

.ancestor .grandparent .parent .elem 
  padding: 16px;
  background-color: white;

.ancestor:focus .grandparent .parent .elem 
  box-shadow: inset 0 0 0 8px aqua;

.ancestor .grandparent .parent:hover .elem 
  background-color: fuchsia;

.ancestor .grandparent .parent p.elem 
  background-color: green;

【讨论】:

【参考方案2】:

简短的回答

由于我们要替换的元素有一个唯一的名称,所以我们要查找的是:

nav 
    ul 
        li 
            a 
                color: red;

                @at-root #selector-replace(&, 'ul', 'ul.opened') 
                    color: green;
                
            
        
    

长答案

操作选择器是非常肮脏的,除非你绝对必须这样做,否则我建议不要这样做。如果您通过指定 table tr tdul li 之类的内容来过度限定选择器,那么首先要简化:tr 和 ul 在这些选择器中都是多余的(除非您试图避免在有序列表下设置元素样式)。调整你的嵌套更简单,等等。

从 Sass 版本 3.4 开始,有 2 个重要功能允许您修改选择器。

Selector functions 父选择器可以存储在变量中

例子:

.foo ul > li a, .bar 
    $sel: &;
    @debug $sel;

你总是会得到一个字符串列表,因为选择器可以用逗号链接在一起,即使你只有一个选择器。

.foo ul > li a, .bar  ... 
 (1  2  3  4 5), (1)

您会注意到这里计算了后代选择器(Sass 中的列表可以是空格或逗号分隔)。记住这一点非常重要。


selector-replace() 不起作用时

selector-replace()函数在以下情况下不起作用:

您要替换的选择器不是唯一的(例如ul ul li) 您想插入一个或多个选择器(例如ul ul li -> ul ul ul li) 您想删除一个选择器(例如ul > li -> ul li

在这种情况下,您需要遍历选择器,并且需要知道要修改哪个位置。以下函数将使用 call() function 的魔力获取一个函数并将其应用于选择器中的特定位置。

@function selector-nth($sel, $n, $f, $args...) 
    $collector: ();
    @each $s in $sel 
        $modified: call($f, nth($s, $n), $args...);
        $collector: append($collector, set-nth($s, $n, $modified), comma);
    

    @return $collector;

Append a class (when the selector isn't unique or you don't know its name)

我们这里需要的函数有 2 个参数:原始选择器和您想要附加到它的选择器。使用简单的插值来完成这项工作。

@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;

插入选择器

此函数还接受 2 个参数:原始选择器和您要在其之前插入的选择器。

@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 > .baz li a, .bar ul > .baz li 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 > a, .bar ul > a 
  color: blue;


TL;DR

选择器只是一个列表。任何列表操作函数都可以使用它,您可以循环访问它以根据需要对其进行修改。

是的,除非您真的真的需要,否则不要这样做。如果您决定仍然需要它,我已将这些功能打包到 selector-nth library 中。

【讨论】:

以上是关于在 Sass 中修改选择器的中间(添加/删除类等)的主要内容,如果未能解决你的问题,请参考以下文章

Sass 选择器函数

sass

sass 扩展

Sass

sass十分钟入门

sass的嵌套