emotion version: 5.2.0react version: 15.6.1Relevant code:
import {css} from "emotion";
import React, {Component} from "react";
import ReactDOM from "react-dom";
const fakeBlue = css([
{
color: "blue"
}
]);
const red = css([
{
color: "red"
}
]);
const blue = css([
red,
{
color: "blue"
}
]);
ReactDOM.render(
<div className={blue}>Hello</div>,
document.getElementById("main")
);
What you did:
I added some styles which I thought would make some text blue
What happened:
I saw that the text was red, instead! 😮
Reproduction:
Webpackbin example of this happening: https://www.webpackbin.com/bins/-KokR2IRsfMsEaoiVBTX
Problem description:
Hey there, co-creator of Aphrodite here. Just looking at the class names that you generate from calls to css() I spotted a bug in emotion. I'm pretty sure what's happening here is that you're inserting styles from the first fakeBlue css() call into a stylesheet first, then from the red css() call, and then when you get to the blue css() call you assume that both of those objects have already been added to the stylesheet, and return a class name that looks like red-something blue-something. Unfortunately, because CSS precedence rules say that for styles of equal specificity (which all of yours are, they only have one class name) the styles that come later in the stylesheet win! So since you inserted the red styles later, they're going to beat out the blue styles no matter what you do.
Suggested solution:
Something other than concatenating class names together with spaces! There are a bunch of solutions that other libraries are using, like merging the styles and using a single class name, using a single class name per style value, or duplicating the class name selector to ensure that you get the correct specificity. All of those are fine. :)
I wrote up a blurb about what we do in Aphrodite here (and why concatenating the class names is bad): https://github.com/khan/aphrodite#overriding-styles
Hope this is helpful!
Thank you for taking the time to write this up. 👍
Funny thing... It never occurred to me that you could use emotion in a repl site now. 🤦♂️
@tkh44 which one?
Look at his link. @xymostech is using object styles so it works fine.
@tkh44 ah. So it's object only. I thought you can customize babel plugin in repl these days
I looked for the option to add babel options but it looks like they don't have that capability yet. You should probably test this with the babel transform to make sure it exhibits the same behavior, but I'd guess you do the same thing with class names regardless.
@xymostech I believe @CompuIves has it working with https://codesandbox.io/. Don't know if it's released yet though.
https://github.com/CompuIves/codesandbox-client/pull/16
We don't do any intelligent class name merging with objects so it wouldn't matter. (try on https://emotion.sh) I'm still deciding which approach to take.
Copy paste of case if you use the repl on the site
const imageStyles = css({
width: 96,
height: 96
})
const fakeBlue = css([
{
color: "blue"
}
]);
const red = css([
{
color: "red"
}
]);
const blue = css([
red,
{
color: "blue"
}
]);
const prettyStyles = css([
{
borderRadius: '50%',
transition: 'transform 400ms ease-in-out',
':hover': {
transform: 'scale(1.2)'
}
},
{ border: '3px solid currentColor' }
])
const Avatar = styled('img')`
composes: ${prettyStyles} ${imageStyles} ${blue}
`
render(
<Avatar src={avatarUrl} />,
mountNode
)
it looks like @kentcdodds figured this out for us.
https://github.com/paypal/glamorous/blob/master/src/get-glamor-classname.js
Making progress...
