wrapper block 是唯一可控路径,因其建立静态业务语义容器边界,确保第三方组件动态类名(如.ant-select-dropdown)在Portal或JS状态变更时仍可被精准定位;HTML需独立包裹、CSS须带空格层级、穿透需框架适配,三层缺一不可。

不能直接给第三方组件类名加 BEM 前缀,也不能用 .ant-btn 这类全局选择器覆盖样式——这么做会在 UI 库升级后立刻失效,且破坏构建时的 CSS Modules 隔离。
为什么 wrapper block 是唯一可控路径
第三方组件(如 AntDesign、Element Plus)的类名由库内部生成,JS 可能动态插入弹层(如 .ant-select-dropdown)、添加状态类(如 .ant-btn-loading),甚至在 Portal 模式下脱离原始 DOM 位置。你写的 .search-form__trigger .ant-btn 在弹层中根本找不到父级上下文。
Wrapper 的作用不是“包一下完事”,而是建立一个可预测的、静态的、带业务语义的容器边界:
- HTML 必须用独立容器包裹:
,不是把className直接塞进组件里 - CSS 中必须带空格层级:
.search-form__date-picker .ant-picker-input input,不是.search-form__date-picker.ant-picker-input - 所有定制样式都以 wrapper 类为前缀,禁止单独出现
.ant-*选择器
Vue / React 中如何穿透到第三方组件内部
当需要调整输入框内边距、下拉项高度等细节时,必须显式穿透,但方式因框架而异:
- Vue SFC +
:只能用:deep(.ant-input),且只允许一层,:deep(:deep(.ant-input))无效 - React + CSS Modules:用属性选择器替代,如
.search-form__field [class^="ant-input"],注意必须加[class^="ant-input"]而非.ant-input - Webpack css-loader 开启
modules: true时,含属性选择器的 CSS 文件顶部必须加注释:/* webpackMode: "global" */
modifier 组合必须显式声明,不能靠父级推导
常见错误是写 .search-form--compact .ant-btn,指望按钮自动变小——这在 Portal 渲染或跨组件复用时必然失效。
正确做法是把状态绑定到 wrapper 自身,并单独定义:
-
.search-form__date-picker--compact单独控制 padding / font-size - 不依赖
.search-form--compact是否存在,因为可能被抽成独立 Hook 或全局调用 - 如果要支持多状态组合(如紧凑+只读),就写
.search-form__date-picker--compact.search-form__date-picker--readonly,而非嵌套修饰符
真正容易被忽略的是:wrapper 不是写一次就一劳永逸。它必须贯穿 HTML 结构、CSS 选择器、构建配置三层——漏掉任意一层(比如忘了加 :deep() 或漏了 webpackMode 注释),隔离就彻底失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











