0

0

如何覆盖组件库样式?React和Vue项目的解决方法浅析

青灯夜游

青灯夜游

发布时间:2022-05-16 11:15:52

|

4687人浏览过

|

来源于掘金社区

转载

如何覆盖组件库样式?下面本篇文章给大家介绍一下reactvue项目中优雅地覆盖组件库样式的方法,希望对大家有所帮助!

如何覆盖组件库样式?React和Vue项目的解决方法浅析

组件库的样式覆盖不掉,这应该是很多前端在工作中遇到过的问题。今天从实际案例出发分析原因,最后会给出在React和Vue项目中的最优解。

本文会讲清:

先不讲概念,直接从需求出发:我使用了Antd组件库来展示一个日历。

1.png

现在我想将当前日期上面的蓝色边框变成紫色。

可以试试你能不能实现。

不管是React还是Vue,整个Calendar是被封装起来的,我们没有办法在组件外简单加上style/class改动内部的样式。

import { Calendar } from 'antd';
...
<div className="myWrapper">
  <Calendar class="custom"/>
</div>

定位要覆盖的样式


首先用开发者工具定位对应的样式:.ant-picker-calendar-date-today,这就是我们要修改的地方。

2.png

.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
    border-color: #1890ff; 
}

熟悉webpack的人应该知道,引入的CSS文件最终都会被style-loader处理。简单来说,它的作用就是把CSS文件打包,放在style标签内,最后塞进HTML中作为一个内部样式表。不管是组件库的样式还是我们写的自定义样式都是这样处理的。

3.png

我们要把组件库的样式先于自定义样式引入,这样自定义样式才能有更高的优先级。

修改源文件


直接改组件库的CSS源码是最简单粗暴的方法。打开你项目的node_modules文件夹,一层层点开,找到对应样式文件,按照需求修改即可。

个人项目这样处理确实可行,但是团队合作时,同步别人本地的node_modules就比较麻烦,只能算一个60分解法。

全局CSS文件


之前提到,把自己写的的CSS文件放在组件库的样式后面,可以保障自定义有更高优先级。只要重写同名的样式,理论上就能实现覆盖组了。

但这样?处理会发现并不起作用:

/* src/demo.css */
.ant-picker-calendar-date-today {
  border-color: purple; /* 覆盖为紫色 */
}
// src/Demo.js

// 组件库的样式
import 'ant-design-vue/dist/antd.css'; 
// 自定义样式
import './demo.css'
import { Calendar } from 'antd';
...
<div className="myWrapper">
  <Calendar />
</div>
...

因为这里还涉及CSS组合选择器的优先级。

基础的优先级应该不用赘述:!important>内联样式>ID选择器>类选择器>标签选择器。(!important这种hack会导致项目不好维护,不提倡使用)

在这个基础上还有五种组合选择器要对优先级分数做累计,以类选择器为例:

  • 后代选择器(空格):.A .B选择.A元素后的所有.B元素,

  • 子元素选择器(大于号):.A>.B选择.A元素的直接后代中的.B元素

  • 相邻兄弟选择器(加号):.A+.B选择.A元素后紧邻的第一个兄弟.B元素

  • 后续兄弟选择器(~号):.A~.B选择.A元素后所有的兄弟.B元素

  • 交集选择器(连在一起):.A.B选择自身同时拥有.A和.B两个属性的元素

上面几个规则看着很复杂,其实用的多的就是第一个后代选择器,记住它就行。Antd组件库用的就是它:

.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
    border-color: #1890ff; 
}

如果说一个类选择器优先级分数是10分,那三个形成的后代选择器就是30分。

而自定义的样式?只有10分,所以即使放在更后面引入,也不能成功覆盖。

.ant-picker-calendar-date-today {
  border-color: purple; // 覆盖为紫色
}

需要完整重写整个选择器才能实现想要的效果。

这里补充一点,同样也是组合选择器,但并集选择器(逗号)优先级不累计:.A, .B选择.A或者.B元素(可以是逗号+空格)

样式隔离CSS Module和Scoped


上面我们引入自定义的全局CSS文件,实现了样式的覆盖,但是这种解法只能给80分。因为在实际工作中,项目Owner通常不允许使用全局CSS,这会造成样式污染:你定义了一个样式my_button,团队其他人恰巧也命名为my_button,这就造成样式冲突。

In3D
In3D

把真人变成化身,创建逼真且可自定义的虚拟角色

下载

我们需要给每个文件做样式隔离,就好像是给它一个命名空间。通常使React项目使用的是用的是CSS Module,Vue项目使用Scoped标记。

接下来会讲清两种样式隔离的原理,以及使用样式隔离时怎么覆盖组件库的样式。

React的CSS Module

首先来了解一下CSS Module的原理。它的使用很简单,在CSS文件加一个后缀.module,然后当做一个变量引入到JS文件中。

// src/Demo.js
import styles from './demo.module.css';
export default function Demo() {
  return (
    <div className={styles.myWrapper}>
      <Calendar />
    </div>
  );
}
/* src/demo.module.css */
.myWrapper {
  border: 5px solid black;
}

被编译后?,插入的样式表和元素的class属性都会加上一个哈希值作为命名空间。

<style>
.demo_myWrapper__Hd9Qg {
  border: 5px solid black;
}
</style>
<div class="demo_myWrapper__Hd9Qg">
...
</div>

可以看到,原本的CSS选择器和HTML元素类名都从myWrapper变成了demo_myWrapper__Hd9Qg,前面加上了文件名,后面加上了哈希值,这样就能保障样式只在当前这个文件下生效了。

但是在这种样式隔离情况下,我们原本用作覆盖的CSS也被加上了哈希值,就像下图这样,这时没有办法选中UI组件,覆盖也就不会成功。

4.png

所以,React给我们提供了一个语法:global。它生效范围内的样式会被当作全局CSS。

具体使用如下,在CSS文件中,使用:global包裹希望全局生效的样式

:global(.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today) {
  border-color:purple; /* 覆盖为紫色 */
}

SCSS或SASS中,还可以使用嵌套语法:

:global {
  .ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
    border-color:purple;
  }
}

最后编译出来的代码如下:

/* 加上了哈希*/
.demo_myWrapper__Hd9Qg {
  border: 5px solid black;
}
/* :global作用域下都不会加上哈希*/
.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
  border-color:purple;
}

5.png

借助:global语法,即使使用CSS Module进行样式隔离也可以如愿实现覆盖功能。

Vue中的Scoped

Vue中也有类似的样式隔离功能,使用Scoped标记CSS部分,使用也很简单?:

<style scoped>
.myWrapper{
  border: 5px solid black
}
</style>
...
<div class="myWrapper" >
  <Calendar />
</div>
...

编译出来的代码如下:

<style>
.myWrapper[data-v-2fc5154c] {
  border: 5px solid black
}
</style>
<div class="myWrapper" data-v-2fc5154c>
  ...
</div>

可以看到,它的原理和CSS Module不太一样,Vue的Scoped会使CSS选择器后加上一个中括号。

这并不是Vue独创的语法,而是属性选择器。.myWrapper[data-v-2fc5154c]代表选择拥有data-v-2fc5154c这个属性的、同时是myButton类的HTML元素。只有这个文件内部的HTML元素才会被打上data-v-2fc5154c这个属性。其余文件的HTML元素即使是myWrapper类,这个样式也不会对他生效。

回到相同的问题,假如Vue项目在使用了Scoped做样式隔离,我们用于覆盖的样式也会加上属性选择器,但是UI组件内部的HTML元素都没有该属性。

6.png

所以Vue提供了一个类似的语法:深度作用选择器。

使用很简单,把要“渗透“进组件内部的样式前面加上>>>,作用域内的CSS样式都不会带上哈希值作为属性选择器。

<style scoped>
.myWrapper>>>
.ant-picker-calendar-full 
.ant-picker-panel 
.ant-picker-calendar-date-today{
  border-color:purple
}
</style>
<template>
  <div class="myWrapper" >
    <Calendar  />
  </div>
</template>

编译后

<style>
.myWrapper[data-v-2fc5154c]
.ant-picker-calendar-full
.ant-picker-panel
/* 作用域内的CSS都没有带上属性选择器 */
.ant-picker-calendar-date-today {
  border-color:purple
}
</style>

<div class="myWrapper" data-v-2fc5154c>
  <div class="ant-picker-calendar-full" data-v-2fc5154c>
    <div class="ant-picker-date-panel">
      <td class="ant-picker-cell-today"></td>
    </div>
  </div>
</div>

7.png

借助深度作用选择器,可以将要用于覆盖CSS“渗透”进组件内部。

也可以将>>>写成/deep/或者::v-deep

相较于React的:global,Vue的深度作用选择器是一种更优秀的方案,它必须要一个前导(也就是上面例子中的.myWrapper选择器),前导依旧会被打上哈希值作为属性选择器,要渗透进去的样式实际上是作为它的子选择器,只在当前这个文件下生效,彻底避免造成全局污染。

结语

本文通过如何修改UI组件内部样式为切入点,分析了几种解法。了解了组合选择器的优先级分数累加,以及在实际React、Vue项目用到的样式隔离方案——CSS Module和Scoped的原理,最后是介绍了在样式隔离的情况下,如何使用:global和深度作用选择器做样式覆盖。

如果这篇文章对你有帮助,给我点个赞和在看吧~

(学习视频分享:web前端开发编程基础视频

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

76

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

117

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

350

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

63

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

109

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

108

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

243

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

684

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

179

2026.03.04

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue 教程
Vue 教程

共42课时 | 9.6万人学习

Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 1.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号