Skip to content

Commit c0dab9f

Browse files
tanhauhaualmaz-khan
authored andcommitted
fix css specificity (#4146)
Co-authored-by: Almaz <gouffr@gmail.com>
1 parent 140bfd0 commit c0dab9f

File tree

7 files changed

+68
-8
lines changed

7 files changed

+68
-8
lines changed

src/compiler/compile/css/Selector.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,13 @@ export default class Selector {
6363
});
6464
}
6565

66-
transform(code: MagicString, attr: string) {
66+
transform(code: MagicString, attr: string, max_amount_class_specificity_increased: number) {
67+
const amount_class_specificity_to_increase = max_amount_class_specificity_increased - this.blocks.filter(block => block.should_encapsulate).length;
68+
attr = attr.repeat(amount_class_specificity_to_increase + 1);
69+
6770
function encapsulate_block(block: Block) {
6871
let i = block.selectors.length;
72+
6973
while (i--) {
7074
const selector = block.selectors[i];
7175
if (selector.type === 'PseudoElementSelector' || selector.type === 'PseudoClassSelector') {
@@ -131,6 +135,16 @@ export default class Selector {
131135
}
132136
}
133137
}
138+
139+
get_amount_class_specificity_increased() {
140+
let count = 0;
141+
for (const block of this.blocks) {
142+
if (block.should_encapsulate) {
143+
count ++;
144+
}
145+
}
146+
return count;
147+
}
134148
}
135149

136150
function apply_selector(blocks: Block[], node: Element, stack: Element[], to_encapsulate: any[]): boolean {

src/compiler/compile/css/Stylesheet.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,12 @@ class Rule {
9595
code.remove(c, this.node.block.end - 1);
9696
}
9797

98-
transform(code: MagicString, id: string, keyframes: Map<string, string>) {
98+
transform(code: MagicString, id: string, keyframes: Map<string, string>, max_amount_class_specificity_increased: number) {
9999
if (this.parent && this.parent.node.type === 'Atrule' && is_keyframes_node(this.parent.node)) return true;
100100

101101
const attr = `.${id}`;
102102

103-
this.selectors.forEach(selector => selector.transform(code, attr));
103+
this.selectors.forEach(selector => selector.transform(code, attr, max_amount_class_specificity_increased));
104104
this.declarations.forEach(declaration => declaration.transform(code, keyframes));
105105
}
106106

@@ -115,6 +115,10 @@ class Rule {
115115
if (!selector.used) handler(selector);
116116
});
117117
}
118+
119+
get_max_amount_class_specificity_increased() {
120+
return Math.max(...this.selectors.map(selector => selector.get_amount_class_specificity_increased()));
121+
}
118122
}
119123

120124
class Declaration {
@@ -239,7 +243,7 @@ class Atrule {
239243
}
240244
}
241245

242-
transform(code: MagicString, id: string, keyframes: Map<string, string>) {
246+
transform(code: MagicString, id: string, keyframes: Map<string, string>, max_amount_class_specificity_increased: number) {
243247
if (is_keyframes_node(this.node)) {
244248
this.node.expression.children.forEach(({ type, name, start, end }: CssNode) => {
245249
if (type === 'Identifier') {
@@ -258,7 +262,7 @@ class Atrule {
258262
}
259263

260264
this.children.forEach(child => {
261-
child.transform(code, id, keyframes);
265+
child.transform(code, id, keyframes, max_amount_class_specificity_increased);
262266
});
263267
}
264268

@@ -275,6 +279,10 @@ class Atrule {
275279
child.warn_on_unused_selector(handler);
276280
});
277281
}
282+
283+
get_max_amount_class_specificity_increased() {
284+
return Math.max(...this.children.map(rule => rule.get_max_amount_class_specificity_increased()));
285+
}
278286
}
279287

280288
export default class Stylesheet {
@@ -397,8 +405,9 @@ export default class Stylesheet {
397405
});
398406

399407
if (should_transform_selectors) {
408+
const max = Math.max(...this.children.map(rule => rule.get_max_amount_class_specificity_increased()));
400409
this.children.forEach((child: (Atrule|Rule)) => {
401-
child.transform(code, this.id, this.keyframes);
410+
child.transform(code, this.id, this.keyframes, max);
402411
});
403412
}
404413

test/css/samples/preserve-specificity/expected.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<a class="svelte-xyz">
2+
<b>
3+
<c>
4+
<span class="svelte-xyz">
5+
Big red Comic Sans
6+
</span>
7+
<span class="foo svelte-xyz">
8+
Big red Comic Sans
9+
</span>
10+
</c>
11+
</b>
12+
</a>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!-- svelte-ignore a11y-missing-attribute -->
2+
<a>
3+
<b>
4+
<c>
5+
<span>
6+
Big red Comic Sans
7+
</span>
8+
<span class='foo'>
9+
Big red Comic Sans
10+
</span>
11+
</c>
12+
</b>
13+
</a>
14+
15+
<style>
16+
a b c span {
17+
color: red;
18+
font-size: 2em;
19+
font-family: 'Comic Sans MS';
20+
}
21+
.foo {
22+
color: green;
23+
}
24+
</style>

test/js/samples/collapses-text-around-comments/expected.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,4 @@ class Component extends SvelteComponent {
6363
}
6464
}
6565

66-
export default Component;
66+
export default Component;

test/js/samples/css-media-query/expected.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,4 @@ class Component extends SvelteComponent {
4646
}
4747
}
4848

49-
export default Component;
49+
export default Component;

0 commit comments

Comments
 (0)