本文聚焦 CSS 与 SCSS 的进阶技巧,重点讲解 SCSS 的 & 父选择器,CSS 的 :not():where()(以及相关的 :is()),并结合工程化与可维护性策略给出实战建议。

概览

  • SCSS &:在嵌套环境中引用父选择器,构建语义化结构与状态样式。
  • CSS :not():排除匹配的子选择器,控制选择范围,特异性受参数影响。
  • CSS :where():降权选择器,参数不参与特异性计算,改善覆盖与复用。
  • CSS :is():聚合选择器减少重复书写,特异性取决于最强参数。

SCSS 的 `&` 父选择器

基本用法与 BEM 结构

.button {
  &--primary { background: #2563eb; color: #fff; }
  &--danger { background: #dc2626; color: #fff; }
  &__icon { width: 1em; height: 1em; }
  &:hover { filter: brightness(1.05); }
  &.is-loading { cursor: wait; opacity: .7; }
}

嵌套伪类与状态组合

.card {
  &:hover &__title { text-decoration: underline; }
  &:has(.badge) &__content { padding-top: 1.5rem; }
}

在 @mixin 中使用 `&`

@mixin focus-ring {
  &:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; }
}

.input {
  @include focus-ring;
}

注意事项

  • & 代表当前选择器的完整文本,位置敏感。
  • 避免过度嵌套导致选择器过长与权重过高。
  • 对于跨层引用,优先通过类语义与模块化组织,而不是深层 & 链接。

`:not()`、`:is()`、`:where()` 的差异与特性

  • :not(selector):排除匹配项;特异性取决于参数中最强的选择器。
  • :is(selector-list):对多个选择器做并集匹配;特异性取决于参数中最强的选择器。
  • :where(selector-list):与 :is() 行为类似,但特异性为 0(参数不计入特异性)。
/* 使用 :is() 聚合 */
:is(h1, h2, h3).title { margin: 0 }

/* 使用 :not() 排除 */
.list-item:not(.disabled) { cursor: pointer }

/* 使用 :where() 降权,便于被局部样式覆盖 */
:where(.prose) h1 { font-size: 2rem }

特异性对比

  • .a :not(#id) 的特异性包含 #id,可能导致覆盖困难。
  • :where(.a, #id) 的特异性为 0,更易被局部样式覆盖。
  • 结合策略:在全局样式与组件样式之间,使用 :where() 以避免全局权重过高。

实战组合技巧

利用 `:where()` 设计可覆盖的基线样式

:where(.btn) { padding: .5rem 1rem; border-radius: .5rem; }
.btn--primary { background: #2563eb; color: #fff }

用 `:not()` 排除特定状态

.tab:not(.is-disabled) { color: #111; }
.tab.is-disabled { color: #777; cursor: not-allowed; }

`&` 与伪类结合实现状态扩展

.nav {
  &__item {
    &:hover { background: #f3f4f6; }
    &:not(.active) { opacity: .8; }
  }
}

使用 `:is()` 降低重复

:is(article, section, aside) > h2 { margin-top: 1.5rem }

复杂场景建议

  • 全局主题或排版规则使用 :where() 降权。
  • 组件内具体状态用类选择器与 & 组织,保持权重可控。
  • 避免在 :not() 中放入高权重选择器(如 #id),以防覆盖困难。

工程化与模块化

Sass 模块系统

// utils/_mixins.scss
@mixin sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; }

// styles.scss
@use 'utils/mixins' as u;
.title { @include u.sr-only; }
  • 使用 @use/@forward 替代旧版 @import,避免全局污染。
  • 命名空间(as u)使工具与变量来源清晰。

`@extend` 与 `@mixin` 的取舍

  • @extend 会生成选择器合并,可能产生意外耦合与大范围选择器膨胀。
  • 优先使用 @mixin + 参数实现复用与可控输出。

现代 CSS 能力(相关)

级联层(Cascade Layers)

@layer reset, base, components, utilities;
@layer reset { *, *::before, *::after { box-sizing: border-box } }
@layer base { :where(html) { font-size: 16px } }
@layer components { .card { padding: 1rem } }
@layer utilities { .mt-4 { margin-top: 1rem } }
  • 层级控制覆盖顺序,与 :where() 组合可实现低权重、可覆盖的基础层。

容器查询(Container Queries)

.card { container-type: inline-size; }
@container (min-width: 480px) {
  .card { display: grid; grid-template-columns: 1fr 1fr }
}
  • 以组件容器尺寸为条件,替代全局媒体查询的局限,增强组件自适应能力。

`:has()`(父选择器能力)

.form:has(.error) { border-color: #dc2626 }
  • 选择包含特定子元素的父节点,实现更灵活的结构选择(注意浏览器支持)。

性能与可维护性建议

  • 控制选择器复杂度与层级,尽量保持 3 层以内。
  • 建立权重策略:全局用 :where() 降权,组件用类与 & 精准控制。
  • 避免 ID 选择器与高权重组合在复用场景中出现。
  • 使用模块化(@use)与语义类(BEM)保持清晰边界。

总结

  • & 让 SCSS 在嵌套中保持父选择器语义,适合 BEM 与状态样式。
  • :not() 控制排除范围,但需警惕其参数带来的特异性提升。
  • :where() 提供零特异性的聚合选择器,是设计可覆盖基线样式的利器。
  • 结合现代能力(级联层、容器查询、:has())与模块化,能显著提升工程可维护性与组件自治性。