Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

the problem with the priority of CSS selector #424

Open
dev-bono opened this issue Mar 22, 2018 · 13 comments
Open

the problem with the priority of CSS selector #424

dev-bono opened this issue Mar 22, 2018 · 13 comments
Labels
Milestone

Comments

@dev-bono
Copy link

dev-bono commented Mar 22, 2018

What is the current behavior?

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>

What is the expected behavior?

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.
2018-03-22 3 02 20
2018-03-22 3 02 33

Environment (include versions)

  • OS: macOS HighSierra
  • Browser: Chrome
  • styled-jsx: 2.2.3
@giuseppeg
Copy link
Collaborator

giuseppeg commented Mar 22, 2018

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-123

Do you have better ideas on how we could fix this?

@giuseppeg giuseppeg added the bug label Mar 22, 2018
@a-ignatov-parc
Copy link
Contributor

Maybe we should prefix only first token in selectors. This will round specificity for elements and pseudo-elements with other 🤔

  • div > div > span0,0,0,3
  • .clickTest0,0,1,0
  • div.jsx-XXX > div > span0,0,1,3
  • .clickTest.jsx-XXX0,0,2,0

@giuseppeg
Copy link
Collaborator

the styles for those unscoped selectors would leak into the descendants

@a-ignatov-parc
Copy link
Contributor

a-ignatov-parc commented Mar 22, 2018

Yeah, but this is the price for using nested tag styles.

P.S. Styling elements with tags is usually an exceptional or bad idea.

@giuseppeg
Copy link
Collaborator

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.

@dev-bono
Copy link
Author

dev-bono commented Mar 23, 2018

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]

@giuseppeg
Copy link
Collaborator

@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.

@giuseppeg
Copy link
Collaborator

Opened an issue on Stylis thysultan/stylis#101

@giuseppeg
Copy link
Collaborator

for the record we realized that we also need an upper boundary thysultan/stylis#101 (comment)

@merrywhether
Copy link

merrywhether commented Apr 30, 2018

@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.

@giuseppeg
Copy link
Collaborator

giuseppeg commented May 1, 2018

@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

@merrywhether
Copy link

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.

@giuseppeg giuseppeg modified the milestone: v3 Jul 18, 2018
@giuseppeg giuseppeg added this to the v4 milestone Sep 28, 2018
@herodrigues
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants