如何否决 SCSS 中的 @extend 指令?

How can I overrule an @extend directive in SCSS?

我在按钮组中有按钮。按钮组有不同的大小,例如button-group-large。我的目标是通过让它从按钮组推断大小来避免必须显式设置按钮组中每个按钮的大小。也就是说,而不是

<div class="button-group-large">
  <button class="button-large">Foo</button>
  <button class="button-large">Bar</button>
</div>

我宁愿这样写:

<div class="button-group-large">
  <button>Foo</button>
  <button>Bar</button>
</div>

我可以这样做(在 SASS):

.button-group-large {
  button { @extend .button-large; }
}

这可行,但会产生以下问题。如果我的某个按钮有特殊的 class,.button-large class 将优先。也就是说,如果我这样做

<div class="button-group-large">
  <button class="special">Foo</button>
  <button>Bar</button>
</div>

然后任何在 .special.button-large 之间不同的属性将获得 .button-large 值而不是 .special 值。我希望这是相反的; .special 应该在这里获胜。 (作为一个真实世界的例子,.special 可能会设置 "primary" 按钮颜色)。

这是一个说明问题的 jsfiddle:https://jsfiddle.net/wwr63qmv/3/

作为参考,Bootstrap button groups 通过要求在每个按钮上单独设置 class 来避免此问题,而不是在按钮组上。这可能是唯一的答案。有没有其他方法可以让 .special class 在这里获胜?

您面临的问题不是由于 Sass 或 @extend 指令引起的。 CSS 就是这样工作的。如果多个选择器指向同一元素,则最具体的选择器获胜(或者)如果特异性相同,则文件中定义的最新选择器获胜。

您的 fiddle 中的 SCSS 代码在编译时将产生以下输出:

.button, ul.button-group li button { /* check this selector */
  border: 1px solid black;
  color: black;
  border-radius: 2px;
}
.special-button { /* and this */
  border: 1px solid green;
  color: green;
}
ul.button-group {
  margin: 10px;
}
ul.button-group li {
  list-style-type: none;
  display: inline-block;
  padding: 5px;
}
p {
  font-family: monospace;
}

这两个选择器 - ul.button-group li button.special-button 都会将具有 class 的按钮作为 .special-button 的目标。第一个选择器的特异性是 013(因为它有 1 个 class 和 3 个类型选择器作为完整复杂选择器的一部分)而第二个选择器的特异性是 010(因为它只有一个 class 选择器).因此,从本质上讲,第一个选择器获胜,并且只有在其下指定的属性才适用于该元素。

为了应用 .special-button 样式,应该增加该选择器的特异性。这可以简单地通过将选择器更改为 ul.button-group li button.special-button 来完成,但这意味着选择器现在将仅针对 buttonclass='special-button',它们在 li 中,其 ul parent 有 class='button-group'。这使得它非常具体,并且意味着如果 button.special-buttonul.button-group li.

之外,则属性将不适用

另一种选择是在 li 中扩展 .special-button,如下所示:

ul.button-group {
  margin: 10px;
  li {
    list-style-type: none;
    display: inline-block;
    padding: 5px;
    button { 
      @extend .button;
      &.special-button { /* note this */
        @extend .special-button;
      }
    }
  }
}

Fiddle Demo