伪类库实为开发者自定义的状态类名约定(如is-active、has-error),非CSS原生功能,需JS或服务端控制增删,用于原生伪类不可用或需跨层级共享状态的场景。

伪类库不是CSS原生功能,不能“引入”
所谓“伪类库”,其实是开发者自己封装的一套类名约定,比如 is-active、has-error 这类手动添加的类,用来替代原生伪类(如 :hover、:focus)在某些受限场景下的使用。浏览器根本不认识这些类名,它们没有魔法,只是普通类,靠 JS 控制增删或服务端渲染时写死。
常见错误现象:Cannot style :hover via class-based library —— 有人试图用 .is-hover 直接模拟悬停,但不配 JS 就完全无效;也有人误以为有类似 @import "pseudo.css" 的语法,实际不存在。
- 原生伪类(
:hover、:disabled、:valid等)只能由浏览器根据 DOM 状态自动触发,无法通过 class “激活” - 扩展类名(如
is-open)本质是状态标记,必须由 JS 显式切换:比如点击后el.classList.toggle('is-open') - 服务端渲染场景下可预设类名(如表单提交失败时直接输出
input has-error),但仍是静态标记,不响应交互
什么时候该用扩展类名代替原生伪类
核心判断标准:原生伪类不可用,或需要跨组件/跨层级共享状态。比如:下拉菜单展开时,不仅菜单本身要变样式,旁边图标也要旋转,而图标和菜单 DOM 不相邻——这时用 :hover 无能为力,必须靠一个共同祖先上的 is-dropdown-open 类来驱动。
典型使用场景:
- 父级控制子元素状态(如
.nav.is-mobile-open .nav-list显示侧边栏) - 表单验证反馈需持久化(
input.is-invalid比依赖:invalid更可控) - CSS-in-JS 或 Shadow DOM 中伪类穿透困难,退而求其次用 class
- 需要动画过渡起点/终点(
:focus是瞬时的,.is-focused可配合transition做入场)
is-、has-、js- 前缀怎么选
前缀不是语法要求,而是协作契约。选错会导致语义混乱或维护成本上升。
-
is-表示当前元素的**运行时状态**(is-loading、is-disabled),JS 频繁切换,CSS 用&.is-loading覆盖 -
has-表示**后代存在某种特征**(has-submenu、has-image),通常服务端渲染一次写死,不常变动 -
js-纯属 JS 钩子,**不写样式**(如js-toggle-button),避免样式和逻辑耦合 - 别混用:
is-open和js-open同时存在会让人困惑哪个该由 JS 控制
参数差异很小,但语义错位会让后续接手的人多花三倍时间猜意图。
性能与兼容性要注意什么
这类类名本身没性能问题,坑出在滥用和联动上。
- 大量使用
document.querySelectorAll('.is-*')查询会拖慢 JS 执行,优先用事件委托或data-属性过滤 - IE11 不支持
classList.toggle('a', boolean)的第二个参数,需降级为if (bool) add() else remove() - 如果用 Web Components,
:host(.is-open)是合法的,但.is-open ::slotted(*)可能不触发重绘,得加forceRedrawhack - 不要用
!important强行覆盖伪类样式,容易引发层叠冲突;正确做法是提高选择器权重,比如从.btn:hover升级到.btn.is-hover
最易被忽略的是:状态类名一旦漏删(比如 JS 报错中断),UI 就卡在错误态,比原生伪类更难 debug。加个 console.warn 检查未清理的 is- 类,真有用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











