Home > Web Front-end > Vue.js > How to override component library styles? A brief analysis of solutions to React and Vue projects

How to override component library styles? A brief analysis of solutions to React and Vue projects

青灯夜游
Release: 2022-05-16 21:01:41
forward
4390 people have browsed it

How to override component library styles? The following article will introduce to you how to elegantly override component library styles in React and Vue projects. I hope it will be helpful to you!

How to override component library styles? A brief analysis of solutions to React and Vue projects

The style of the component library cannot be overwritten. This should be a problem that many front-ends have encountered in their work. Today we will analyze the reasons based on actual cases, and finally give the optimal solutions in React and Vue projects.

This article will explain clearly:

  • What is the principle of CSS Module in React? What does :global do?

  • What is the principle of Scoped in Vue? What is a depth action selector? (Learning video sharing: vue video tutorial)

Let’s not talk about the concept first, and start directly from the needs: I used the Antd component library to display a calendar.

How to override component library styles? A brief analysis of solutions to React and Vue projects

Now I want to change the blue border above the current date to purple.

You can try to see if you can achieve it.

Whether it is React or Vue, the entire Calendar is encapsulated. We cannot simply add style/class outside the component to change the internal style.

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

Locate the style to be overwritten


First use the developer tools to locate the corresponding style: .ant-picker-calendar-date-today , this is what we want to modify.

How to override component library styles? A brief analysis of solutions to React and Vue projects

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

Those who are familiar with webpack should know that the imported CSS files will eventually be processed by style-loader. Simply put, its function is to package the CSS file, place it in the style tag, and finally insert it into HTML as an internal style sheet. This is done whether it is the style of the component library or the custom style we wrote.

How to override component library styles? A brief analysis of solutions to React and Vue projects

We need to introduce the styles of the component library before the custom styles, so that the custom styles can have a higher priority.

Modify the source file


The simplest and crudest method is to directly change the CSS source code of the component library. Open the node_modules folder of your project, click on it layer by layer, find the corresponding style file, and modify it according to your needs.

It is indeed feasible to handle personal projects in this way, but when working in a team, it is more troublesome to synchronize other people's local node_modules, and it can only be regarded as a 60 decomposition method.

Global CSS file


As mentioned before, putting your own CSS files behind the styles of the component library can ensure higher customization priority. As long as you rewrite the style with the same name, you can theoretically implement an override group.

But this? The processing will find that it does not work:

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

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

Because this also involves the priority of the CSS combination selector.

The basic priority should go without saying: !important>Inline style>ID selector>Class selector>Tag selector. (!important hacks like this will make the project difficult to maintain and are not recommended for use)

On this basis, there are five combination selectors that need to accumulate priority scores. Take the class selector as an example:

  • Descendant selector (space): .A .B Selects all .B elements after the .A element,

  • Child element selector (greater than sign): .A>.B selects the .B element among the direct descendants of the .A element

  • adjacent sibling selector (plus Number): .A .BSelect the first sibling .B element immediately after the .A element

  • ## Subsequent sibling selector (~ number):

    .A~.BSelect all sibling .B elements after .A element

  • Intersection selector (connected together):

    .A.BSelect itself at the same time Elements with two attributes, .A and .B

The above rules may seem complicated, but in fact the most practical one is the first descendant selector, just remember it. It is used by the Antd component library:

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

If the priority score of a class selector is 10 points, then the three formed descendant selectors will be 30 points.

And the custom style only has 10 points, so even if it is introduced later, it cannot be successfully overwritten.

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

You need to completely rewrite the entire selector to achieve the desired effect.

One thing to add here is that it is also a combination selector, but the priority of the union selector (comma) is not cumulative:

.A, .BSelect the .A or .B element ( Can be comma space)

样式隔离CSS Module和Scoped


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

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

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

React的CSS Module

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

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

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

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

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

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

How to override component library styles? A brief analysis of solutions to React and Vue projects

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

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

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

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

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

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

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

How to override component library styles? A brief analysis of solutions to React and Vue projects

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

Vue中的Scoped

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

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

编译出来的代码如下:

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

可以看到,它的原理和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元素都没有该属性。

How to override component library styles? A brief analysis of solutions to React and Vue projects

所以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>
Copy after login

编译后

<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>
Copy after login

How to override component library styles? A brief analysis of solutions to React and Vue projects

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

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

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

结语

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

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

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

The above is the detailed content of How to override component library styles? A brief analysis of solutions to React and Vue projects. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:juejin.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template