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

[RFC] Use CSS Custom Properties for dynamic styles #595

Open
giuseppeg opened this issue Nov 8, 2019 · 2 comments
Open

[RFC] Use CSS Custom Properties for dynamic styles #595

giuseppeg opened this issue Nov 8, 2019 · 2 comments

Comments

@giuseppeg
Copy link
Collaborator

giuseppeg commented Nov 8, 2019

The scope of this "RFC" is to discuss about the possibility to use CSS Custom Properties for dynamic styles.

Switching to use CSS Custom Properties might allow us to explore static extraction in the future.

This mode would be optional and disabled by default as many might still need to support IE, it will also be a breaking change because we would need to allow interpolations only for CSS values:

// ✅
<style jsx>{`div { color: ${props.color}  }`}</style>
// ✅ the expression below must be hoisted
<style jsx>{`div { color: ${Math.random() > 0.5 ? 'green' : 'black' }  }`}</style>
// 🛑 invalid
<style jsx>{`div { ${props.color ? `color: ${props.color}` : '' }  }`}</style>

How dynamic styles work right now

Interpolations, and therefore the entire template literal containing the CSS, are flagged as dynamic when they have an expression that cannot be evaluated at build time.

When this is the case we rewrite the styles as follow:

<JSXStyle id="123">{`div.__jsx-style-dynamic-selector { color: ${props.color}  }`}</JSXStyle>

We also hash the string above to have a base ID, say 123. Then we rewrite the className attribute of every JSX element to include a fn that generates the proper ID at runtime based on props:

<div className={JSXStyle.dynamic([  ['123', [props.color] ])}>
   <JSXStyle id="123">{`div.__jsx-style-dynamic-selector { color: ${props.color}  }`}</JSXStyle>
</div>

JSXStyle.dynamic's signature is:

type ClassNames = string // space separated class names
type JSXStyleInfo = [BaseID, Array<Props>]
type Dynamic = (Array<JSXStyleInfo>) => ClassNames 

It takes an Array<JSXStyleInfo> because there could be multiple style tags per component.

At runtime then it basically maps JSXStyleInfo to create an hash from JSXStyleInfo, and then flattens the result to finally return classnames

jsx-123abc

Internally then JSXStyle does the same and replaces __jsx-style-dynamic-selector with jsx-123abc.

Proposal

I think that we could rework this part to instead use custom properties:

We won't use any __jsx-style-dynamic-selector but rather use the BaseID to generate the scoped class jsx-123.

Interpolations would be replaced with custom properties:

<JSXStyle id="123">{`div.jsx-123 { color: var(--styled-jsx-123-1)  }`}</JSXStyle>

and the root JSXElement would set custom properties using JSXStyle.dynamic:

<div className="jsx-123" style={{ '--styled-jsx-123-1': props.color }}>
   <JSXStyle id="123">{`div.jsx-123 { color: var(--styled-jsx-123-1)  }`}</JSXStyle>
</div>
@giuseppeg
Copy link
Collaborator Author

giuseppeg commented Nov 8, 2019

This is just an idea I had a while ago, likely I might not have time to implement it soon but I wanted to put it out there in case anybody is interested

cc @developit

@hpachy
Copy link

hpachy commented Mar 31, 2021

I tried the following code from the documentation but I got the __jsx-style-dynamic-selector after each selector.... it's very annoying...

import React from "react";
import css from "styled-jsx/css";

function getLinkStyles(color: string) {
  return css.resolve`
    div > h1 {
      color: ${color};
    }
  `;
}

export default () => {
  const { className, styles } = getLinkStyles("red");

  return (
    <div>
      <div className={className}>
        <h1>tot</h1>
      </div>
      {styles}
    </div>
  );
};

But I got something annoying when I tried to add selector directly after each one I got

jsx-1807396575

in my case so I get a wrong selector and no style on my elements...

Capture d’écran, le 2021-03-31 à 16 20 53

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

No branches or pull requests

5 participants