Skip to content

Commit 1264286

Browse files
HiDeooematipico
andauthored
fix: scope css with only pseudo selectors (#1100)
Co-authored-by: ematipico <[email protected]>
1 parent 2a27aca commit 1264286

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

.changeset/shiny-walls-grab.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@astrojs/compiler": patch
3+
---
4+
5+
Fixes a CSS scoping issue when a selector contains only pseudo selectors.

internal/transform/scope-css_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,21 @@ func TestScopeStyle(t *testing.T) {
166166
source: ".class\\:class:focus{}",
167167
want: ".class\\:class:where(.astro-xxxxxx):focus{}",
168168
},
169+
{
170+
name: "only pseudo element",
171+
source: ".class>::before{}",
172+
want: ".class:where(.astro-xxxxxx)>:where(.astro-xxxxxx)::before{}",
173+
},
174+
{
175+
name: "only pseudo class + pseudo element",
176+
source: ".class>:not(:first-child)::after{}",
177+
want: ".class:where(.astro-xxxxxx)>:where(.astro-xxxxxx):not(:first-child)::after{}",
178+
},
179+
{
180+
name: "nested only pseudo element",
181+
source: ".class{& .other_class{&::after{}}}",
182+
want: ".class:where(.astro-xxxxxx){& .other_class:where(.astro-xxxxxx){&:where(.astro-xxxxxx)::after{}}}",
183+
},
169184
// the following tests assert we leave valid CSS alone
170185
{
171186
name: "attributes",

lib/esbuild/css_printer/astro_features.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ func (p *printer) printCompoundSelector(sel css_ast.CompoundSelector, isFirst bo
6666
}
6767
}
6868

69+
var onlyPseudoSubclassSelectors *bool
70+
6971
for i, sub := range sel.SubclassSelectors {
7072
whitespace := mayNeedWhitespaceAfter
7173

@@ -126,6 +128,22 @@ func (p *printer) printCompoundSelector(sel css_ast.CompoundSelector, isFirst bo
126128
p.print("]")
127129

128130
case *css_ast.SSPseudoClass:
131+
if sel.TypeSelector == nil && onlyPseudoSubclassSelectors == nil {
132+
onlyPseudoSubclassSelectors = new(bool)
133+
*onlyPseudoSubclassSelectors = true
134+
for _, ss := range sel.SubclassSelectors {
135+
_, ok := ss.(*css_ast.SSPseudoClass)
136+
if !ok {
137+
*onlyPseudoSubclassSelectors = false
138+
break
139+
}
140+
}
141+
}
142+
// If there is no type selector and all subclass selectors are pseudo
143+
// selectors, we need to add the scope before the first pseudo selector.
144+
if sel.TypeSelector == nil && *onlyPseudoSubclassSelectors && i == 0 && s.Name != "global" && s.Name != "root" {
145+
scoped = p.printScopedSelector()
146+
}
129147
p.printPseudoClassSelector(*s, whitespace)
130148
if s.Name == "global" || s.Name == "root" {
131149
scoped = true

0 commit comments

Comments
 (0)