bem 的 modifier 类名中不能包含媒体查询或断点标识(如 --hidden@md),因其违背“类名只表达状态、不表达条件”的原则,导致语义不清、维护困难、ssr 不一致等问题;正确做法是将断点逻辑统一收口至 _breakpoints.scss,用语义化修饰符(如 nav-menu--hidden-below-md)配合外部 @media 规则控制。

不能在 BEM 的 Modifier 类名里写媒体查询,也不该把断点逻辑塞进类名中——比如 block--hidden@md 或 card--mobile 这类写法,浏览器根本不会识别,CSS 也不支持。
为什么 Modifier 里不能出现 @md、--sm 这类断点标识
这类命名直接把实现细节(如断点值、设备类型)暴露到 HTML 层,违背 BEM “类名不表达条件,只表达状态” 的核心原则。一旦设计调整断点值(比如从 768px 改成 744px),你得同步改三处:模板里的类名、JS 控制逻辑、CSS 文件里的 @media 规则——漏一就出 bug。
-
block--mobile模糊:是“仅在手机显示”,还是“在手机上隐藏”?语义不清,协作时容易误用 -
card--sm歧义:“sm” 指尺寸?断点?哪个断点值?没人能一眼确认 - 服务端渲染(SSR)时无法获取
window.innerWidth,JS 动态加类会和 SSR 输出不一致,引发 FOUC 或 layout shift
正确的响应式断点收口方式
修饰符只负责表达「视觉或行为状态」,比如 nav-menu--collapsed、card--stacked;而「这个状态在什么条件下生效」,必须由外部 @media 规则控制。
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
- 所有断点定义统一收口到
_breakpoints.scss,禁止在组件样式文件里直接写@media - 修饰符命名用动词 + 范围结构,例如:
nav-menu--hidden-below-md、card--stacked-above-lg - 对应 CSS 必须显式包裹在媒体查询中:
@media (max-width: 767px) { .nav-menu--hidden-below-md { display: none; } } - React 中通过状态控制类名,而不是监听
resize:用clsx('nav-menu', isMobileView && 'nav-menu--hidden-below-md'),而非window.addEventListener('resize', ...)
React + CSS Modules 场景下的典型陷阱
很多人以为「组件自己管自己的响应式」更灵活,结果导致断点逻辑散落各处,后期无法全局调控。ESLint 必须启用自定义规则拦截字符串拼接类名——`button--${size}@${breakpoint}` 是明确禁止的写法。
- 禁止在 JSX 中硬编码修饰符:
className="button button--primary button--mobile"❌ - 禁止用 JS 动态拼接断点类:
className={`card card--${breakpoint}`}❌ - 正确做法是把断点判断逻辑抽到 CSS 层,HTML 只保留语义化修饰符:
className={clsx('card', isStacked && 'card--stacked')}✅ - 若需不同断点下切换不同布局,优先考虑容器查询(
@container)或 CSSaspect-ratio+width组合,而非靠 JS 加类
最容易被忽略的一点:修饰符本身没有“自动响应”能力,它只是个钩子;真正起作用的是媒体查询规则是否命中、是否被正确加载、是否与其他规则发生层叠冲突。别指望加个 --mobile 就能自动适配——那只是把问题从 CSS 推给了 JS 和 HTML。










