I'm using styled-jsx with nextjs.
but, I think the priority of CSS selector is a something wrong. it's expected that color of click text is blue. because the priority of class is higher than tags.
https://gist.github.com/mjj2000/5873872
<div>
<div>
<span className="clickTest">click</span>
</div>
</div>
<style jsx>{`
div > div > span {
color: red;
}
.clickTest {
color: blue;
}
`}</style>
but, click text rendered color red.
div > div > span selector must not complie to like div.jsx-1217126016>div.jsx-1217126016>span.jsx-1217126016. because selector like [tag].[classname] is higher than just .[classname] selector.


Good point. The specificity:
div > div > span is [0,0,0,3].clickTest is [0,0,1,0]When scoped instead:
div.jsx-123 > div.jsx-123 > span.jsx-123 is [0,0,3,3].clickTest.jsx-123 is [0,0,2,0]I guess the only way to fix this is to balance the specificity when we add the scoped classes. In this case:
.clickTest.jsx-123.jsx-123.jsx-123Do you have better ideas on how we could fix this?
Maybe we should prefix only first token in selectors. This will round specificity for elements and pseudo-elements with other 🤔
div > div > span → 0,0,0,3.clickTest → 0,0,1,0div.jsx-XXX > div > span → 0,0,1,3.clickTest.jsx-XXX → 0,0,2,0the styles for those unscoped selectors would leak into the descendants
Yeah, but this is the price for using nested tag styles.
P.S. Styling elements with tags is usually an exceptional or bad idea.
If we had to break something then I'd rather rewrite selectors to have all the same specificity e.g.:
div > div > span -> .div > .div > .span
.clickTest -> .clickTest
And state that in styled-jsx types have all the same specificity.
just add a scoped class. first or last one.
but, I'm not sure this is right solution.
what do you think?
div > div > span is [0,0,0,3]
.clickTest is [0,0,1,0]
When scoped instead:
div.jsx-123 > div > span is [0,0,1,3]
.clickTest.jsx-123 is [0,0,2,0]
@blueshw actually that is a great idea. The only adjustment to it would be that we only scope the last selector (not the first):
div > div > span.jsx-123
.clickTest.jsx-123
I need to verify it though to make sure that this couldn't lead to conflicts or unwanted results.
Opened an issue on Stylis https://github.com/thysultan/stylis.js/issues/101
for the record we realized that we also need an upper boundary https://github.com/thysultan/stylis.js/issues/101#issuecomment-375853514
@blueshw's suggestion would actually be really great, because right now styled-jsx is kind of clunky when it comes to styling third-party components without having to sprinkle :global the whole way down. It would be awesome to have local scope with an unaltered cascade. Then the following would work:
<div className="foo">
<ThirdPartyComponent className="bar">
<style jsx>{`
.foo .bar .someInnerClass a {
...
}`</style>
</div>
as it would get transformed to
<div className="foo.jsx-123">
<ThirdPartyComponent className="bar">
</div>
with styles like
.foo.jsx-123 .bar .someInnerClass a { ... }
The third-party component styling situation would be so much better with a feature like this. 2-birds-1-stone kind of situation.
@merrywhether this issue is not about making changes to :global or how to reach to descendants without using :global but to fix the specificity issue while keeping the scoping behavior valid :)
The solution is to always scope the innermost and outermost selectors. To not break specificity then we need to add the scoped class twice when the selector is single eg.
div.jsx-123.jsx-123
True enough, was just pointing out the similarity in the use-cases. OP could've used :global in a similar way to downscale the element selectors' specificity to achieve the same outcome as your suggestion: :global(div) > :global(div) > span (or div > :global(div) > :global(span) to achieve @blueshw's suggestion).
It seems like it'd be weird to have to use :global to drop class injection in some cases but then have it done automatically in other cases.
Is this still an issue?
I'm seeing this when try to move my styles to a separate JS file and try to import them.
I have tried using css.resolve, but no luck.
Most helpful comment
just add a scoped class. first or last one.
but, I'm not sure this is right solution.
what do you think?
When scoped instead: