CSS/SCSS 高级用法指南:&、:not()、:where() 与工程实践
本文聚焦 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())与模块化,能显著提升工程可维护性与组件自治性。
💬 评论