伪类Mixin不应混用伪元素规则,因:hover等状态选择器无需content且不生成节点;应按语义独立命名如state-hover,分拆调用各状态,兼容性交由工具链处理。

伪类样式本身不依赖 content,但混用伪类和伪元素时容易误套伪元素的规则——Mixin 不能自动区分 :hover 和 ::before,写错就白编译。
为什么 @mixin pseudo 不该用于伪类
伪类(如 :hover、:focus、:disabled)是状态选择器,不生成新节点,也不需要 content;而伪元素(::before、::after)必须带 content 才渲染。很多开发者照搬伪元素 Mixin 套路去封装伪类,结果:
- 在
@mixin pseudo($display: block)里硬塞content: "",导致.btn:hover编译出非法 CSS(content在伪类中无效) - 用插值
&:#{$state}传hover,却忘了加冒号,写成:hover而非&:hover,Sass 编译报错或静默失败 - 把
:focus-visible和:focus当作同一参数处理,实际浏览器行为差异大,覆盖逻辑易出错
@mixin state-hover 这类命名更安全
直接按伪类语义命名 Mixin,不复用伪元素逻辑。例如:
@mixin state-hover($bg: #007bff, $text: #fff) {
&:hover {
background-color: $bg;
color: $text;
}
}
这样调用清晰、无歧义:
立即学习“前端免费学习笔记(深入)”;
-
@include state-hover(#0056b3);→ 只影响:hover - 不预设
content、display或定位属性,避免污染伪类上下文 - 支持链式状态,比如
&:hover:focus需单独写,不建议在同一个 Mixin 里强行合并——浏览器匹配优先级和触发条件不同
多个伪类共存时,别堆在一个 @include 里
一个按钮常同时需要 :hover、:focus、:disabled,但它们的样式逻辑完全不同:
-
:disabled必须显式重置cursor、opacity、pointer-events,不能只靠颜色变灰 -
:focus-visible在 Safari 和 Firefox 中行为不一致,需配合outline和outline-offset单独控制 - 用
@mixin btn-states把三者打包,看似省事,实则掩盖了各状态的独立约束 —— 比如深色模式下:disabled的文字色要从var(--text-muted)切换,而:hover仍走主题变量
更稳妥的做法是分拆调用:@include state-hover(...); @include state-focus(...); @include state-disabled(...);
IE 兼容不是伪类 Mixin 的责任
:focus-within、:is()、:has() 这些现代伪类在旧版 IE 完全不支持,Sass Mixin 无法 polyfill。试图用 @if browser == ie 做条件编译会引入不可靠的环境判断,且 Sass 本身不提供运行时 UA 检测能力。
真正要做的只有两件事:
- 在项目构建层(如 PostCSS)配
autoprefixer+postcss-preset-env,让:is()自动降级为展开选择器 - 对关键交互伪类(如
:focus)保留基础样式,确保键盘导航可用性不丢失 —— 这部分不能靠 Mixin 自动生成,得手写 fallback
伪类 Mixin 的边界很明确:它只负责生成合法、语义清晰、可预测的 CSS 块。兼容性兜底和降级策略,得交给工具链和人工审查,不是一句 @include 能解决的。


















