コンポーネント ライブラリ スタイルをオーバーライドするにはどうすればよいですか?次の記事では、React および Vue プロジェクトでコンポーネント ライブラリ スタイルをエレガントにオーバーライドする方法を紹介します。
コンポーネント ライブラリのスタイルは上書きできません。これは、多くのフロントエンドが作業中に遭遇する問題です。今日は実際の事例に基づいてその理由を分析し、最終的に React および Vue プロジェクトにおける最適な解決策を提供します。
この記事ではわかりやすく説明します:
React の CSS モジュールの原理とは何ですか? :global
は何をしますか?
Vue の Scoped の原則は何ですか?デプスアクションセレクターとは何ですか? (学習ビデオ共有: vue ビデオ チュートリアル)
最初に概念については話さず、ニーズから直接始めましょう。表示するために Antd コンポーネント ライブラリを使用しました。カレンダー。
次に、現在の日付の上にある青色の枠線を紫色に変更したいと思います。
それを達成できるかどうか試してみてください。
React であっても Vue であっても、Calendar 全体はカプセル化されているため、コンポーネントの外側にスタイルやクラスを追加するだけで内部スタイルを変更することはできません。
import { Calendar } from 'antd'; ... <div className="myWrapper"> <Calendar class="custom"/> </div>
最初に開発者ツールを使用して、対応するスタイルを見つけます: .ant-picker-calendar-date -今日
、これを修正したいと考えています。
.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today { border-color: #1890ff; }
webpack に詳しい人は、インポートされた CSS ファイルが最終的に style-loader によって処理されることを知っているはずです。簡単に言うと、その機能は CSS ファイルをパッケージ化し、スタイル タグ内に配置し、最終的に内部スタイル シートとして HTML に挿入することです。これは、コンポーネント ライブラリのスタイルであっても、作成したカスタム スタイルであっても行われます。
#カスタム スタイルが優先されるように、カスタム スタイルの前にコンポーネント ライブラリのスタイルを導入する必要があります。
最も単純かつ大雑把な方法は、コンポーネント ライブラリの CSS ソース コードを直接変更することです。プロジェクトのnode_modulesフォルダーを開き、レイヤーごとにクリックし、対応するスタイルファイルを見つけて、必要に応じて変更します。
個人的なプロジェクトをこの方法で処理することは確かに実現可能ですが、チームで作業する場合、他の人のローカルのノードモジュールを同期するのはさらに面倒であり、60 個の分解方法としか考えられません。 。
前述したように、コンポーネント ライブラリのスタイルの背後に独自の 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 組み合わせセレクターの優先順位も関係するためです。
基本的な優先順位は言うまでもありません: !重要>インライン スタイル>ID セレクター>クラス セレクター>タグ セレクター
。 (!このような重要なハックはプロジェクトの保守を困難にするため、使用はお勧めできません)
これに基づいて、優先度スコアを蓄積する必要がある 5 つの組み合わせセレクターがあります。例としてクラス セレクターを取り上げます。
子孫セレクター (スペース): .A .B
.A 要素の後のすべての .B 要素を選択します (
)子要素セレクター (記号より大きい): .A>.B
は、.A 要素の直接の子孫の中から .B 要素を選択します。
隣接する兄弟セレクター (プラス)番号): .A .B
.A 要素の直後にある最初の兄弟 .B 要素を選択
.A~ .B .A 要素の後のすべての兄弟 .B 要素を選択します
.A.Bそれ自身を同時に選択します 2 つの要素を持つ要素属性、.A および .B
.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today { border-color: #1890ff; }
.ant-picker-calendar-date-today { border-color: purple; // 覆盖为紫色 }
ここで 1 つ追加すべきことは、これは組み合わせセレクターでもありますが、共用体セレクター (カンマ) の優先順位は累積的ではないということです:.A, .B
を選択します。 A または .B 要素 (カンマスペースも可)
上面我们引入自定义的全局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 './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组件,覆盖也就不会成功。
所以,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; }
借助: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元素都没有该属性。
所以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>
借助深度作用选择器,可以将要用于覆盖CSS“渗透”进组件内部。
也可以将
写成
/deep/
或者::v-deep
。
相较于React的:global
,Vue的深度作用选择器是一种更优秀的方案,它必须要一个前导(也就是上面例子中的.myWrapper选择器),前导依旧会被打上哈希值作为属性选择器,要渗透进去的样式实际上是作为它的子选择器,只在当前这个文件下生效,彻底避免造成全局污染。
本文通过如何修改UI组件内部样式为切入点,分析了几种解法。了解了组合选择器的优先级分数累加,以及在实际React、Vue项目用到的样式隔离方案——CSS Module和Scoped的原理,最后是介绍了在样式隔离的情况下,如何使用:global和深度作用选择器做样式覆盖。
如果这篇文章对你有帮助,给我点个赞和在看吧~
以上がコンポーネント ライブラリのスタイルをオーバーライドするにはどうすればよいですか? React および Vue プロジェクトのソリューションの簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。