如何解决 uni-icons 样式无法覆盖?深入理解 deep() 在 uni-app 中的作用

在使用 uni-app 开发项目时,可能会遇到这样一个问题:
在子组件中通过 CSS 设置 uni-icons 图标颜色,却完全不生效。

无论怎么写:

.uni-icons {
    color: red;
}

图标就是纹丝不动。

先说结论

uni-icons 样式无法被覆盖,本质上是:

  1. scoped 样式隔离
  2. 小程序端重复嵌套结构
  3. 组件内部样式优先级太高

使用 :deep() + !important 可以一次性解决所有问题,在 H5 和小程序端都能稳定覆盖样式。

:deep() {
    .uni-icons {
        color: $brand-theme-color !important;
    }
}

真正做到跨端统一图标颜色,让项目风格保持一致。


解析问题原因

uni-icons 无法被子组件样式覆盖,通常来自三个方面:

1. <style scoped> 的样式隔离机制

scoped 会为当前组件的 DOM 自动添加一个独立的属性选择器,例如:

<view data-v-123456></view>

这会导致外部书写的样式无法穿透到子组件内部,也无法选中 uni-icons 的真实 DOM 节点。

2. 小程序端 DOM 结构会重复嵌套 uni-icons

在微信小程序、支付宝小程序等平台,uni-icons 会被编译成类似结构:

<uni-icons>
    <i class="uni-icons"></i>
</uni-icons>


结构比 H5 更深、更复杂,导致外部选择器无法命中内部的 .uni-icons

(补充) scoped 导致匹配不到的真正问题

除了结构嵌套本身更深之外,小程序端还有一个更隐蔽的问题——
scoped 会给父组件加上特殊属性选择器,但不会加到子组件内部的 .uni-icons 上,因此选择器无法匹配到真实 DOM。

例如父组件编译后选择器会变成:

.uni-layout[data-v-123abc] .uni-icons[data-v-123abc] { ... }

但小程序里最终的节点是:

<i class="uni-icons uniu-sound-filled"></i>

注意:这个 <i> 元素没有 data-v-123abc 属性。

也就是说:

  • 选择器期望匹配的是:.uni-icons[data-v-123abc]
  • 实际 DOM 只有:.uni-icons

两者不一致,导致选择器始终匹配不到内部的 <i.uni-icons>,样式自然不会生效。

:deep() 的作用就在于:
.uni-icons 这一部分不再附带 scoped 生成的作用域标记,从而可以直接命中子组件内部真实的 .uni-icons 元素,使样式得以生效。

3. 组件本身的默认样式优先级较高

uni-icons 是封装组件,内部已经定义了 color 样式。
普通 CSS 权重往往不够覆盖,于是出现“不生效”的假象。

解决方案:使用 :deep() 深度选择器穿透作用域

uni-app 中推荐的方式是使用 :deep(),它可以突破 scoped 的样式限制,直接作用于子组件内部。

示例:

:deep() {
    .uni-icons {
        color: $brand-theme-color !important;
    }
}

代码解析

① :deep() —— 深度选择器

Vue3 官方推荐的作用域穿透方式,它能够:

  • 穿透 <style scoped> 的边界
  • 选中子组件内部的元素
  • 小程序和 H5 均兼容有效
    尤其是小程序端因结构嵌套多层,:deep() 能确保样式真正落到内部的 .uni-icons 上。

② .uni-icons —— 组件生成的真实类名

uni-icons 最终渲染出的 DOM 会包含 .uni-icons 类名,只有选中它才能改变图标颜色。

③ $brand-theme-color —— 自定义主题变量

来自全局 scss 文件的变量,用于统一项目主题色。
例如:

$brand-theme-color: #28B389;

这样可以让所有图标颜色保持风格一致。

④ !important —— 提升样式优先级

由于封装组件内部有默认样式,使用 !important 可以确保你的样式最终覆盖默认设置。

额外建议:主题色统一管理

uni.scss 中定义全局主题变量:

$brand-theme-color: #28B389;

组件中直接使用即可:

color: $brand-theme-color;

既统一风格,也便于后期维护。


参考:
@咸虾米 7.13.定义scss颜色变量deep()修改子组件css样式_哔哩哔哩_bilibili