Skip to content
This repository was archived by the owner on Dec 19, 2024. It is now read-only.

Should custom properties be ignored when not scoped to :root? #186

Closed
Zacqary opened this issue Jul 18, 2015 · 12 comments
Closed

Should custom properties be ignored when not scoped to :root? #186

Zacqary opened this issue Jul 18, 2015 · 12 comments

Comments

@Zacqary
Copy link

Zacqary commented Jul 18, 2015

Just started playing around with cssnext, and I immediately got this error when testing out what happened when I assigned something a custom property:

› cssnext: <css input>:4:2: Custom property ignored: not scoped to the top-level :root element (header { ... --test: ... })

So I see what this is about. Custom properties, when used for var(), want to be placed inside :root so that they're globally available. But var() isn't the only reason why you might want to use custom properties.

I haven't seen a lot of people connecting the dots and talking about this, but custom properties are incredibly useful for writing web components. Here's a situation I ran into a few days ago:
<pie-chart percent="33"></pie-chart>

This is a custom element that extends <canvas>, and will draw a pie chart to itself based on the value of the percent attribute. The thing is, the JS to do this needs to be passed two different colors: the color of the empty section of the pie chart, and the color of the full section. I wanted to be able to do this with CSS. I was left with having to use the various color properties in non-standard ways. For example, I'd render the canvas with something like:

drawEmptyPortion();
context.fillStyle = document.querySelector('pie-chart').style.backgroundColor;
context.fill();
drawFullPortion();
context.fillStyle = document.querySelector('pie-chart').style.color;
context.fill();

and then

pie-chart {
    color: #f00; // The full color
    background-color: #888; // The empty color
}

But that creates a problem of giving the entire canvas a gray background instead of rendering everything surrounding the pie chart transparent. So instead, I had to use:

outline-color: #888;

Thankfully, I didn't also need to render my pie chart with a CSS outline, so this variable was otherwise unused. Also the color variable, because there was no text. But that's a lucky situation, and this is still a hack using CSS properties in a non-standard way. What I'd really like to be able to do is:

pie-chart {
    --full-color: #f00;
    --empty-color: #888;
}

Unfortunately, cssnext isn't equipped to handle that kind of situation. I don't know if this sort of behavior is outside the scope of cssnext, vis-a-vis exposing custom properties to JS for this kind of purpose, but it's something that I think a lot of people will be increasingly exploring as web components become more popular. So it's a question I'd at least like to discuss.

@MoOx
Copy link
Owner

MoOx commented Jul 19, 2015

You just want to get rid of the warnings right?
If so, we might implement a simple option to do that. Would it be enough for you?

@Zacqary
Copy link
Author

Zacqary commented Jul 19, 2015

That sounds like it'll work.

At some point I might be able to submit a PR for a way to expose custom
props to Javascript, though this would probably require a runtime so I'm
not sure if it's within the scope of the project.
On Jul 19, 2015 1:19 PM, "Maxime Thirouin" notifications@github.com wrote:

You just want to get rid of the warnings right?
If so, we might implement a simple option to do that. Would it be enough
for you?


Reply to this email directly or view it on GitHub
#186 (comment).

@MoOx
Copy link
Owner

MoOx commented Jul 21, 2015

To expose (keep) custom props, you can use the following option:

{
  features: {
    customProperties: {
      preserve: true
    }
  }
}

With that in mind, will you be happy if we add an option in customProperties to hide warnings (like warnings: false)?

@Zacqary
Copy link
Author

Zacqary commented Jul 21, 2015

Sure, sounds fantastic.
On Jul 21, 2015 9:31 AM, "Maxime Thirouin" notifications@github.com wrote:

To expose (keep) custom props, you can use the following option:

{
features: {
customProperties: {
preserve: true
}
}
}

With that in mind, will you be happy if we add an option in
customProperties to hide warnings (like warnings: false)?


Reply to this email directly or view it on GitHub
#186 (comment).

@MoOx
Copy link
Owner

MoOx commented Jul 21, 2015

If you install and reinstall cssnext, you should get the new version of postcss-custom-properties (4.2.0) that include the warnings option.

@0xcaff
Copy link

0xcaff commented Jan 2, 2017

What is the reason for this warning? Say for example I have the following

.red {
  --bg-color: red;
  --fg-color: orange;
}

.green {
  --bg-color: green;
  --fg-color: blue;
}

.box {
  color: var(--fg-color);
  background: var(--bg-color);
}

with the following markup:

<div class='box green'>Some text</div>

This warning is thrown:

 Custom property ignored: not scoped to the top-level :root element (.red { ... --bg-color: ... })

Is it ok to use variables this way? Is it ok to just disable warnings in this case?

@0xcaff
Copy link

0xcaff commented Jan 2, 2017

Never mind. The readme has the answer:

N.B. The transformation is not complete and cannot be (dynamic cascading variables based on custom properties relies on the DOM tree). It currently just aims to provide a future-proof way of using a limited subset (to :root selector) of the features provided by native CSS custom properties. Since we do not know the DOM in the context of this plugin, we cannot produce safe output. Read #1 & #9 to know why this limitation exists.

These warnings are emitted because postcss can't backfill compatibility only by modifying the css files. Postcss doesn't know that .box.green will occur during runtime.

@Aiky30
Copy link

Aiky30 commented Jun 23, 2017

Hi,

The warnings: false option works but is not documented anywhere. Just a heads up.

@jimblue
Copy link

jimblue commented Oct 23, 2017

Hi @Aiky30, I'm using webpack and I've tried so many solution without success.
How did you made the warnings option to work? Thank you.

Here is my actual setup:

module: {
   rules: [
      test: /\.(scss|sass|css)$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
            {
              loader: 'css-loader',
              options: {
                sourceMap: true,
                importLoaders: 1
              }
            },
            {
              loader: 'postcss-loader',
              options: {
                sourceMap: true,
                ident: 'postcss',
                plugins: (loader) => [
                  customProperties({ warnings: false }),
                  mqpacker({ sort: sortCSSmq }),
                  cssnext(),
                  cssnano({ safe: true })
                ]
              }
            }
          ]
        })
      }
   ]
}

@Aiky30
Copy link

Aiky30 commented Oct 24, 2017

@jimblue It looks like you'll need to set the warnings property as a config for cssnext. My snippet of that module is below:

{
          loader: 'postcss-loader',
          options: {
            plugins: function () {
              return [
                require('postcss-import'),
                require('postcss-url'),
                require('postcss-cssnext')({
                  features: {
                    customProperties: {
                      warnings: false
                    }
                  }
                }),
                // add your "plugins" here
                require('postcss-nested'),
                // and if you want to compress,
                // just use css-loader option that already use cssnano under the hood
                require('postcss-browser-reporter'),
                require('postcss-reporter')
              ];
            }
          }

I'm using webpack v2. I hope that helps.

In your setup I'd probably do:

cssnext({                  
  features: {
    customProperties: {
      warnings: false
    }
  }
})

@jimblue
Copy link

jimblue commented Oct 24, 2017

@Aiky30 tks it's working 😄 !

@jimblue
Copy link

jimblue commented Oct 24, 2017

@Aiky30 about using css-loader option that already use cssnano under the hood.

I found two benefit from declare cssnano in postcss:

  • better efficiency (200ko vs 205ko) 🤣
  • automatically remove medias (fonts or images) that are imported but not used

What's your point on this, maybe I'm wrong...

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

No branches or pull requests

5 participants