使用 @emotion/css
实现的组件库在接入到使用多个技术栈实现的项目中,面临着样式被反复覆盖的问题。
从上图可以看到,组件上样式被宿主项目引入的 css
文件中定义的样式覆盖,究其原因是因为 css-in-js
生成的 css-[hash]
的选择器权重比较低。
根据 Selectors Level 3 的 Calculating a selector's specificity 的章节可以得出一下结论。
/* count the number of ID selectors in the selector (= a) */
/* count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= b) */
/* count the number of type selectors and pseudo-elements in the selector (= c) */
/* ignore the universal selector */
Examples:
* /* a=0 b=0 c=0 -> specificity = 0 */
LI /* a=0 b=0 c=1 -> specificity = 1 */
UL LI /* a=0 b=0 c=2 -> specificity = 2 */
UL OL+LI /* a=0 b=0 c=3 -> specificity = 3 */
H1 + *[REL=up] /* a=0 b=1 c=1 -> specificity = 11 */
UL OL LI.red /* a=0 b=1 c=3 -> specificity = 13 */
LI.red.level /* a=0 b=2 c=1 -> specificity = 21 */
#x34y /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */
div[data-tag="some-tag-name"] input /* a=0 b=1 c=2 -> specificity = 12 */
input[type="text"] /* a=0 b=1 c=1 -> specificity = 11 */
.css-1t321tv /* a=0 b=1 c=0 -> specificity = 10 */
要解决这个问题,第一时间想到的可能是给每一个冲突的样式添加 !important
,但是这样做的工作量太大了,而且很容易留下后患。那么如何优雅的解决这个问题呢?紧接着 Calculating a selector's specificity 下面有一段话
Note: Repeated occurrences of the same simple selector are allowed and do increase specificity.
这也就是说,如果能让 @emotion/css
在为元素生成 class
的同时能为生成的样式选择器添加一个重复的 class
就可以解决这个问题了。@emotion/css
是支持如下的语法的:
<div
css={{
'&': {
width: '100%',
}
}}
/
那么如果使用&&
,@emotion/css
会为我们生成重复的类名选择器吗?
<div
css={{
'&&': {
width: '100%',
}
}}
/>
答案是会的。
从上图看出,@emition/css
为元素生成了两个相同了 class
。这样生成的样式选择器的权重就是 a = 0 b = 2 c = 0 -> specificity = 20
足够覆盖大多数场景了。