用--is-visible/--is-hidden等语义化状态修饰符控制动态内容展示更可靠,因其表达客观状态而非行为,避免语义污染、主题耦合与实现绑定,并需统一语义、规范类名使用及状态同步。

直接说结论:用 --is-visible、--is-hidden 这类语义化状态修饰符控制动态内容展示,比写 --show、--hide 或直接操作 display: none 更可靠。
为什么不能用 --show / --hide 作修饰符
这类命名把行为当成了状态——show 是动词,不是组件当前所处的客观状态;JS 调用 element.classList.add('card--show') 后,如果 CSS 没配 display: block,它就啥也不干;换主题时还得同步改所有 --show 的样式,容易漏。
更麻烦的是语义污染:card--show 和 modal--show 看似一样,实际可能一个靠 opacity 过渡、一个靠 transform 位移,强行复用会出错。
推荐做法:
- 统一用
--is-visible表达“当前应被用户感知”这一事实状态 - 对应 CSS 中只声明视觉结果(如
opacity: 1; visibility: visible;),不绑定具体实现方式 - 让 JS 只负责同步状态,不关心怎么渲染
--is-visible 配合 visibility 和 opacity 怎么选
关键看是否需要保留布局空间和事件响应能力:
-
visibility: hidden保留占位、仍可响应事件(适合禁用但需保持 tab 键导航) -
opacity: 0保留占位、但鼠标穿透(适合淡入淡出过渡) -
display: none完全脱离文档流(适合彻底隐藏、节省重绘开销)
不要在同一个修饰符里混用三者。例如:
.card--is-visible { opacity: 1; transition: opacity .2s; }
.card--is-hidden { opacity: 0; }
这样写,--is-hidden 不等于 “不可见”,而是“正在淡出中”,语义就偏了。应该拆成:
-
--is-visible→ 显式可见 -
--is-invisible→ 显式不可见(对应visibility: hidden) -
--is-fading-out→ 过渡中(单独加动画类,不参与状态管理)
动态插入内容时,如何避免修饰符失效
常见错误是 JS 插入 DOM 后没同步添加状态类,或类名拼错导致选择器不匹配。比如:
- React 中写
className={`card ${isVisible ? 'card--is-visible' : ''}`,但isVisible初始为undefined,结果生成card card--is-visible空格后缀,CSS 不生效 - Vue 用
:class="{ 'card--is-visible': isVisible }"更安全,但要注意isVisible必须是响应式数据 - 手拼类名时漏掉
--,写成card-is-visible,BEM 解析器直接忽略
建议:
- 所有状态类名用常量定义:
const VISIBLE_CLASS = 'card--is-visible'; - 插入新节点后,立刻调用
el.classList.toggle(VISIBLE_CLASS, shouldShow) - 用
getComputedStyle(el).visibility !== 'hidden'辅助调试,而不是只信 class 存在与否
最易被忽略的一点:状态修饰符一旦写进 HTML,就默认承诺了它的稳定性——--is-visible 在整个项目里必须代表同一语义,不能在按钮上表示“可点击”,在卡片上又表示“已加载完成”。否则 JS 逻辑和 CSS 样式会逐步脱节,最后谁也说不清这个类到底该干嘛。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











