Git Product home page Git Product logo

postcss-css-variables's Introduction

PostCSS CSS Variables

npm version Build Status Gitter

PostCSS plugin to transform CSS Custom Properties (CSS variables) syntax into a static representation. This plugin provides a future-proof way of using most of CSS variables features, including selector cascading with some caveats, because this can only see the CSS, not the potentially dynamic HTML and DOM the CSS is applied to.

Install

npm install postcss postcss-css-variables --save-dev

Table of Contents

Try it in the playground and see what you think! Just add some CSS and see to see the final transformed/compiled CSS. You can try anything here in the playground, too.

Usage

For more general PostCSS usage, look here.

var postcss = require("postcss");
var cssvariables = require("postcss-css-variables");

var fs = require("fs");

var mycss = fs.readFileSync("input.css", "utf8");

// Process your CSS with postcss-css-variables
var output = postcss([cssvariables(/*options*/)]).process(mycss).css;

console.log(output);

Syntax

Defining Custom Properties with --*

A custom property is any property whose name starts with two dashes --. A property must be in a rule.

Note: :root is nothing more than the selector for the root DOM node. Any other selector like .class, #id, or even #foo ~ .bar > span.baz works.

:root {
  --foo-width: 100px;
  --foo-bg-color: rgba(255, 0, 0, 0.85);
}

.foo {
  --foo-width: 100px;
  --foo-bg-color: rgba(255, 0, 0, 0.85);
}

Custom properties can be declared multiple times, but like variable scope in other languages, only the most specific one takes precedence.

:root {
  --some-color: red;
}

.foo {
  /* red */
  color: var(--some-color);
}

.bar {
  --some-color: blue;
  /* blue */
  color: var(--some-color);
}

.bar:hover {
  --some-color: green;
  /* Automatically gets a `color: green;` declaration because we `--some-color` used within scope elsewhere */
}

W3C Draft: CSS Custom Properties for Cascading Variables, section 2

Using Variables/Custom Properties with var()

.foo {
  width: var(--foo-width);
  /* You can even provide a fallback */
  background: var(--foo-bg-color, #ff0000);
}

W3C Draft: CSS Custom Properties for Cascading Variables, section 3

Features

At-rules like @media, @support, etc.

It's perfectly okay to declare CSS variables inside media queries and the like. It'll work just as you would expect.

:root {
  --width: 100px;
}

@media (max-width: 1000px) {
  :root {
    --width: 200px;
  }
}

.box {
  width: var(--width);
}

Will be transformed to:

.box {
  width: 100px;
}

@media (max-width: 1000px) {
  .box {
    width: 200px;
  }
}

Pseudo-classes and Elements

Psuedo-classes are also dealt with correctly, because it's easy to statically determine.

.foo {
  --foo-color: red;
  color: var(--foo-color);
}

.foo:hover {
  --foo-color: green;
}

Will be transformed to:

.foo {
  color: red;
}

.foo:hover {
  color: green;
}

Nested Rules

This pairs very well with postcss-nested or postcss-nesting, adding support for nested rules. For either, you must put the plugin before postcss-css-variables in the plugin stack so that the & references are expanded first (postcss-css-variables doesn't understand them). For example, with postcss-nested, your PostCSS setup would look like this:

var postcss = require("postcss");
var cssvariables = require("postcss-css-variables");
var nested = require("postcss-nested");

var fs = require("fs");

var mycss = fs.readFileSync("input.css", "utf8");

var output = postcss([
  // Flatten/unnest rules
  nested,
  // Then process any CSS variables
  cssvariables(/*options*/)
]).process(mycss).css;

console.log(output);

For a simple example with nesting:

.box-foo {
  --some-width: 150px;
  width: var(--some-width);

  .box-bar {
    width: var(--some-width);
  }
}

With also postcss-nesting, this will be transformed to:

.box-foo {
  width: 150px;
}

.box-foo .box-bar {
  width: 150px;
}

For a more complex example with a media query:

:root {
  --some-width: 150px;
}

.box-foo {
  width: var(--some-width);

  .box-bar {
    width: var(--some-width);
  }
}

@media (max-width: 800px) {
  .box-foo {
    --some-width: 300px;
  }
}

Will be transformed to:

.box-foo {
  width: 150px;
}

.box-foo .box-bar {
  width: 150px;
}

@media (max-width: 800px) {
  .box-foo {
    width: 300px;
  }

  .box-foo .box-bar {
    width: 300px;
  }
}

Why?

This plugin was spawned out of a discussion on the cssnext repo and a personal need.

There is another similar plugin available, postcss-custom-properties, although it restricts itself much more than this plugin, preferring partial spec conformance. This plugin has the same capabilities but also adds imperfect feature support which stem from not being able to know what the DOM will look like when you compile your CSS. We instead look at the explicit structure of your CSS selectors.

Interoperability and differences from postcss-custom-properties

Putting postcss-css-variables in place of postcss-custom-properties should work out of the box.

In postcss-custom-properties, CSS variable declarations are specifically restricted to the :root selector.

In postcss-css-variables, this is not the case and they may be declared inside any rule with whatever selector. The variables are substituted based on statically known CSS selector inheritance.

Here's a quick overview of the differences:

  • CSS variables may be declared in any selector like .foo or .foo .bar:hover, and is not limited to just :root
  • CSS variables may be declared in @media, @support, and other at-rules.
  • CSS variables may be declared in :hover and other psuedo-classes, which get expanded properly.
  • Variables in nested rules can be deduced with the help of postcss-nested or postcss-nesting.

Continue to the next section to see where some of these might be unsafe to do. There are reasons behind the ethos of why the other plugin, postcss-custom-properties, is very limited in what it supports, due to differing opinions on what is okay to support.

Caveats

When you declare a CSS variable inside one selector, but consume it in another, this does make an unsafe assumption about it which can be non-conforming in certain edge cases. Here is an example where these limitations result in non-conforming behavior.

Note the nested markup below. We only know about the DOM's inheritance from your CSS selectors. If you want nest multiple times, you need to be explicit about it in your CSS which isn't necessary with browser that natively support CSS variables. See the innermost <div class="title">

<div class="component">
  Black

  <div class="title">
    Blue

    <div class="decoration">
      Green

      <div class="title">Blue with this plugin, but green per spec</div>
    </div>
  </div>
</div>
.component {
  --text-color: blue;
}

.component .title {
  color: var(--text-color);
}

.component .decoration {
  --text-color: green;
  color: var(--text-color);
}

postcss-custom-properties avoids this problem entirely by restricting itself to just the :root selector. This is because the developers there would prefer to not support a feature instead of something almost-spec-compliant like what postcss-css-variables does.

Options

preserve (default: false)

Allows you to preserve custom properties & var() usage in output.

Possible values:

  • false: Removes --var declarations and replaces var() with their resolved/computed values.
  • true: Keeps var() declarations in the output and has the computed value as a fallback declaration. Also keeps computed --var declarations.
  • 'computed': Keeps computed --var declarations in the output. Handy to make them available to your JavaScript.
  • (declaration) => boolean|'computed' : function/callback to programmatically return whether preserve the respective declaration

variables (default: {})

Define an object map of variables in JavaScript that will be declared at the :root scope.

Can be a simple key-value pair or an object with a value property and an optional isImportant bool property.

The object keys are automatically prefixed with -- (according to CSS custom property syntax) if you do not provide it.

preserveInjectedVariables (default: true)

Whether to preserve the custom property declarations inserted via the variables option from final output.

A typical use case is CSS Modules, where you would want to avoid repeating custom property definitions in every module passed through this plugin. Setting this option to false prevents JS-injected variables from appearing in output CSS.

var postcss = require("postcss");
var cssvariables = require("postcss-css-variables");

postcss([
  cssvariables({
    variables: {
      "--some-var": "100px",
      "--other-var": {
        value: "#00ff00"
      },
      "--important-var": {
        value: "#ff0000",
        isImportant: true
      }
    }
  })
]).process(css, opts);

preserveAtRulesOrder (default: false)

Keeps your at-rules like media queries in the order to defined them.

Ideally, this would be defaulted to true and it will be in the next major version. All of the tests expecations need to be updated and probably just drop support for preserveAtRulesOrder: false

Quick Reference/Notes

Testing

We have a suite of Mocha tests. If you see something that doesn't have coverage, make an issue or pull request.

Run once:

npm install

Run whenever you want to test:

npm run test

postcss-css-variables's People

Contributors

akdetrick avatar alexandrearpin avatar andycernst avatar asvny avatar benwest avatar chrisstiles avatar ekatioz avatar erikthalen avatar j9t avatar juliovedovatto avatar larslaade avatar madlittlemods avatar modosc avatar nhoizey avatar pixeldrew avatar poetro avatar pvande avatar sebastiandedeyne avatar simono avatar vincentorback avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

postcss-css-variables's Issues

Slow with lots of Rules and Declarations - Performance

@ddprrt wrote this article, PostCSS misconceptions, which brought to light a huge performance issue. When running just the large Bootstrap codebase with a single variable substitution, it takes 14 seconds to compile(on my system, 5 seconds for @ddprrt). You can find the test bench that he created, here.

I investigated and found that I was foolishly cloning the the whole root and then flushing it node.clone().removeAll(). I made a ./lib/shallow-clone-node.js helper to fix this problem.

The testbench now runs at 840ms overall. And when I pre-compile the postcss-import step and then run another process transform with postcss-css-variables, it now only contributes 230ms. Still not a stellar performance but a great improvement.

I hope to refactor and rework this whole codebase with postcss-selector-parser which I believe will greatly increase clarity and reduce complexity. The refactor will also give me a fresh start to address performance.


aside: Thank you Stefan(@ddprrt), for putting some umpf into that performance demo and writing about PostCSS. I really enjoyed your article, PostCSS misconceptions, and I have always viewed PostCSS this way.

Add option for @apply syntax

According to this video, the Polymer team at Google has been working with the CSS standards body to add the ability to @apply a group of properties, as you would @include a Sass @mixin.

Here's the syntax:

--ui-message-header-theme: {
    color: #297187;
    font-size: 15px;
    font-weight: 700;
    margin-bottom: 7px;
};
.header {
    @apply(--ui-message-header-theme)
}

If I were interested in using this functionality, do you think it would make sense to add it here, or to a different plugin, or should it be a separate plugin?

Cheers.

Media queries outputted in wrong order

So I have my CSS variables declared like so (from the end of Phillip Walton article http://philipwalton.com/articles/why-im-excited-about-native-css-variables/):

@media (min-width: 1px) and (max-width: 799px) {
  :root { 
    --navbar-padding: 5%;   
  }
}
@media (min-width: 800px) {
  :root { 
    --navbar-padding: 1rem;      
  }
}
@media (min-width: 992px) {
  :root { 
    --navbar-padding: 3rem;
  }
}

This CSS variable setup works perfectly, with the media queries being rendered in the correct order. When I run postcss-css-variables, however, the media queries get outputted in the opposite order, and my production file renders incorrectly because of overriding. Is there something I am doing wrong?

@media (min-width: 992px) {
  .navbar {
    padding: 1rem 3rem;
  }
}

@media (min-width: 800px) {
  .navbar {
    padding: 1rem 1rem;
  }
}

@media (min-width: 1px) and (max-width: 799px) {
  .navbar {
    padding: 1rem 5%;
  }
}

Update variables without server restart

I'm using postcss express middleware and i would like to use variables from external file. Something like this:

var postcss = require('postcss');
var cssvariables = require('postcss-css-variables');
var cssVariables   = require(path.join(__dirname, src, 'cssvariables.js'));
postcss([
    cssvariables({
        variables: cssVariables
        }
    })
])
.process(css, opts);

it works just fine but one tiny problem if i modify something in cssvariables.js i will need to restart server to see changes.

There was same issue with postcss-simple-vars and work around was this:

var cssVariables   = path.join(__dirname, src, '_cssVariables.js');

variables: function(){
    delete require.cache[require.resolve(cssVariables)];
    return require(cssVariables);
}

So it would be great to see changes without server restart.

Please clearly show in the README the limitation / bugs it can create

Currently you use a title like

.root {
  --text-color: red;
}

.component {
  --text-color: blue;
}

.component .header {
  color: var(--text-color);
}

.component .text {
  --text-color: green;
  color: var(--text-color);
}

With the current html, this is completlly wrong

<div class="component">
  Black
  <div class="header">
    Blue
    <div class="text">
      Green
      <div class="header">Green</div>
    </div>
  </div>
</div>

See native result on firefox http://jsbin.com/tireneluxo/1/edit?html,css,output

Your output give a completly different result

http://jsbin.com/zacakilamo/1/edit?html,css,output

It's unexpected according to what I can read in the readme https://github.com/MadLittleMods/postcss-css-variables#using-cascading-variables-the-var-notation

Using Cascading Variables: the var() notation
...

  • No limitation on what scope CSS variables can be declared or used (:root or wherever)
  • Proper value substition based on explicit DOM/structure traversal

So it's totally unclear.

"undefined" cross-file when using postcss-loader

Specifically I'm using rucksack and postcss-loader in Webpack. :root vars in the same file seem to work fine but otherwise the references just output undefined, any suggestions? They work fine if I assign them in JS. thanks!

Allow whitespace within var function

Input:

:root { --foo: red; }
.bar { color: var( --foo ); }

Expected output:

.bar { color: red; }

Actual output:

.bar { color: var( --foo ); }

Comma separated rules are unnecessarily expanded (duplicate blocks)

It appears that comma-separated rules are expanded even if the variable value is the same, creating additional unnecessary rules.

Input:

:root {
    --font-family: sans-serif;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-family);
}

Expected output:

h1, h2, h3, h4, h5, h6 {
    font-family: sans-serif;
}

Actual output:

h1 {
    font-family: sans-serif;
}

h2 {
    font-family: sans-serif;
}

h3 {
    font-family: sans-serif;
}

h4 {
    font-family: sans-serif;
}

h5 {
    font-family: sans-serif;
}

h6 {
    font-family: sans-serif;
}

Scoping issue on multiple class attributes - `undefined`

I am using postcss-nested and postcss-css-variables plugins in the order as mentioned.

I don't know which plugin is to blame, but if I have something like:

.test {
    --a: 10px;
    &.sub {
        width: var(--a);
    }
}

I get:

.test.sub {
    width: undefined;
}

If I add whitespace between & and .sub, it works as expected (apart from the fact it's no multiple class attribute anymore g). Even if I switch the order of the plugins, it works (but I've no idea what will not work then)...

Import variables from js module

Currently, the plugin supports defining "default" variables in the config as a plain javascript object.

Is there any way to similarly import values from a javascript module?

The syntax I had in mind was something like this:

// variables.json
{
  blue: '#0366d6'
}

// styles.css
@import 'variables.json';

.foo {
  color: var(--blue);
}

my use case is that I would like to reuse these values between javascript and css without duplicating values.

If this is not currently supported, I'd be happy to take a look at adding support.

Fallbacks seem to break other var() in same decl

For example, on line 133 of sanitize.css (currently), the following line appears:

font: var(--html-font-size, 100%)/var(--html-line-height, 1.5) var(--font-family, sans-serif);

The postcss-custom-properties plugin correctly resolves this to read:

font: 100% / 1.5 'Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif';

This plugin simply outputs:

font: 100%;

Reduce nested calc for IE11

Hello,
I'm using postcss-css-variables in combination with cssnext.

Given this (rather naive) css:

:root {
  --test1: calc(10vh - 20px);
  --test2: calc(var(--test1) * 2);
}
.testNestedCalc {
  height: var(--test2);
  background-color: red;
}

Generates this CSS output:

.testNestedCalc {
  height: calc(calc(10vh - 20px) * 2);
  background-color: red;
}

If I use the cssnext built in custom properties I'll get this output:

.testNestedCalc {
  height: calc(20vh - 40px);
  background-color: red;
}

Nested calc is OK for modern browsers, but ie11 does not understand nested calc.

cssnext uses the reduce-css-calc to remove nested calc. Is there a way to use the same reducer (or something similar) with postcss-css-variables?

My postcss config:

plugins = () => {
  let result = [
    require('postcss-import')({ /* ...options */ }), 
    require('postcss-url')({ /* ...options */ }), 
    require('postcss-mixins')({ /* ...options */ }), 
    require('postcss-cssnext')({
      features: {
        customProperties: false, 
        rem: false,
      } 
    }),
    require('postcss-css-variables')({ /* ...options */ }),
    require('postcss-hexrgba')({ /* ...options */ }),  
  ];
  return result;
};
module.exports = {
  plugins: plugins()
};

Extract rules with resolved variables to another stylesheet

Hi.

CSS Variable are quite well supported but are not in IE11<=11 and Android < 5.

So I was thinking if we could take the calculated rules and move to external file?

And load this file with JS (after detecting support for CSS variables)?

Breaks `linear-gradient` value list

following results in unexpected code:

textarea {
  background-image: linear-gradient(var(--primary-color, #ff5722), var(--primary-color, #ffff22));
}

results in:

textarea {
  background-image: linear-gradient(#ff5722), var(--primary-color, #ffff22);
}

but should:

textarea {
  background-image: linear-gradient(#ff5722, #ffff22);
}

tested also with playground

Variables Declaration Replaced

Hi,

I have a CSS file like this:

@import 'cssB.css';

:root {
  --varA: var(--varB);
}

h1 {
  color: var(--varA);
}

And in cssB.css:

:root {
  --varB: 'valueB';
}

If I run this through the following script:

var postcss = require('postcss');
var cssvariables = require('postcss-css-variables');
var importCSS = require('postcss-import');

var fs = require('fs');

var mycss = fs.readFileSync('cssA.css', 'utf8');

// Process your CSS with postcss-css-variables
var output = postcss([
  cssvariables( /*options*/ )
]).use(importCSS)
  .process(mycss)
  .css;

console.log(output);

I get this as a result:

:root {
  --varB: 'valueB';
}

h1 {
  color: undefined;
}

So the original cssA.css :root selector is replaced by the :root selector from cssB.css. Is that supposed to happen? Since suitcss theme uses multiple :root selectors in a single file, I assumed that this was OK?

I tried changing cssA.css to look like this:

/*
@import 'cssB.css';
*/

:root {
  --varB: 'valueB';
}

:root {
  --varA: var(--varB);
}

h1 {
  color: var(--varA);
}

When I run process.js I now get this as a result:

/*
@import 'cssB.css';
*/

h1 {
  color: 'valueB';
}

So it works with multiple :root selectors in the same file, although they are not removed once the variables are resolved.

I did one more experiment. It looks like this:

@import 'cssB.css';


:root {
  --varB: 'valueB';
}

:root {
  --varA: var(--varB);
}

h1 {
  color: var(--varA);
}

In this case the result is:

ole@MKI:~/Sandbox/test1$ node process.js 
:root {
  --varB: 'valueB';
}

h1 {
  color: 'valueB';
}

So the @import statement only replaces the first root selector...

Ole

CSS variables features support comparison

I have created a simple website that compares which CSS variable features are working with native CSS variables support vs. postcss-custom-properties and vs. postcss-css-variables. Anyone has pros and cons. You always have to think which features you need in your project and choose correct solution. If you need to support just modern browsers (latest Chrome, Firefox, Safari, Edge, excl. IE 11) the best choice is native CSS variables support without post processors plugins which cause many features working wrong. If you need to support older browsers you have to use post processors but you will be very limited what about the features. Owner of this plugin can check it and decide which features can be fixed/supported.

=> CSS variables features support comparison

When mixing vars with MQs, vars fallback if not redeclared

Quite a confusing title, I apologise. Essentially, if a variable is declared and altered in a MQ and then mixed in the same declaration as one that isn't, it falls back to its original value.

:root {
	--gutter: 1rem;
	--gutterLarge: 2rem;

	@include mq(tablet) {
		--gutter: 1.5rem;
		--gutterLarge: 3rem;
	}

	@include mq(desktop) {
		--gutterLarge: 4rem;
	}
}

div {
	padding: var(--gutter) var(--gutterLarge);
}

This will output:

div {
    padding:  1rem 2rem;
}

@media (min-width: 46.25em) {
    div {
        padding: 1.5rem 3rem;
    }
}

@media (min-width: 61.25em) {
    div {
        padding: 1rem 4rem;
    }
}

I would expect the last one to be 1.5rem 4rem.

Error event indexOf

This is an error I get when I try to run this plugin in my gulp postcss processors. Unsure of if this is related to any other issues, but it's definitely blocking me.

events.js:154
      throw er; // Unhandled 'error' event
      ^
TypeError: Cannot read property 'indexOf' of undefined
    at OldValue.check (/Users/Stephen/projects/navis-ui/node_modules/autoprefixer/lib/old-value.js:17:16)
    at /Users/Stephen/projects/navis-ui/node_modules/autoprefixer/lib/processor.js:198:25
    at /Users/Stephen/projects/navis-ui/node_modules/postcss/lib/container.js:94:28
    at /Users/Stephen/projects/navis-ui/node_modules/postcss/lib/container.js:81:26
    at Rule.each (/Users/Stephen/projects/navis-ui/node_modules/postcss/lib/container.js:68:22)
    at Rule.walk (/Users/Stephen/projects/navis-ui/node_modules/postcss/lib/container.js:80:21)
    at /Users/Stephen/projects/navis-ui/node_modules/postcss/lib/container.js:83:32
    at Root.each (/Users/Stephen/projects/navis-ui/node_modules/postcss/lib/container.js:68:22)
    at Root.walk (/Users/Stephen/projects/navis-ui/node_modules/postcss/lib/container.js:80:21)
    at Root.walkDecls (/Users/Stephen/projects/navis-ui/node_modules/postcss/lib/container.js:92:25)
    at Processor.remove (/Users/Stephen/projects/navis-ui/node_modules/autoprefixer/lib/processor.js:172:18)
    at plugin (/Users/Stephen/projects/navis-ui/node_modules/autoprefixer/lib/autoprefixer.js:64:28)
    at LazyResult.run (/Users/Stephen/projects/navis-ui/node_modules/postcss/lib/lazy-result.js:206:20)
    at /Users/Stephen/projects/navis-ui/node_modules/postcss/lib/lazy-result.js:120:37
    at LazyResult.asyncTick (/Users/Stephen/projects/navis-ui/node_modules/postcss/lib/lazy-result.js:134:15)
    at /Users/Stephen/projects/navis-ui/node_modules/postcss/lib/lazy-result.js:132:27

Feature request: Support for context

Thanks a lot for your project and the work you put into it. This is very useful!

Do you plan to support context for variables in a way similar how media queries and hover effects work?

Existing functionality:

/* Works well: */

:root {
  --color: blue;
}

a {
  color: var(--color);
}
/* =>
  a {
    color: blue;
  }
*/

a:hover {
  --color: green;
}
/* =>
  a:hover {
    color: green;
  }
*/

New functionality:

/* Not supported: */

:root {
  --color: blue;
}

a {
  color: var(--color);
}
/* =>
  a {
    color: blue;
  }
*/

.my-theme {
  --color: red;
}
/* =>
  .my-theme a {
    color: red;
  }
*/

Use variable only from last pseudo-element

Input

.bar {
  --color: pink;
  color: var(--color);
}

.bar:active {
  --color: blue;
}

.bar:hover {
  --color: red;
}

.bar:focus {
  --color: green;
}

Expected

.bar {
  color: pink;
}

.bar:active {
  color: blue;
}

.bar:hover {
  color: red;
}

.bar:focus {
  color: green;
}

Will be transformed to (Actual)

😞

.bar {
  color: pink;
}

.bar:focus {
  color: green;
}

.bar:hover {
  color: green;
}

.bar:active {
  color: green;
}

Default variable overwrite

Hi! It would be great if there was something familiar with sass default variables especially when using postcss-import. so for example you have one css file where you make some css and define some variables. than you import this file to another one where default variables will be overwritten with other ones.

Extra declaration for pseudo class

Input:

:root {
    --color: blue;
}

.c:focus {
    --color: red;
    border-color: var(--color);
}

Output:

.c:focus {
    border-color: blue;
}

.c:focus:focus {
    border-color: red;
}

Expected:

.c:focus {
    border-color: red;
}

Dependent property redefinition

Dependent property should be redefined if source property is changed.

Input:

.a {
    --source: red;
    --dependent: var(--source);

    color: var(--dependent);
}

.a .b {
    --source: blue;

    color: var(--dependent);
}

Actual:

.a {
    color: red;
}

.a .b {
    color: red;
}

Expected:

.a {
    color: red;
}

.a .b {
    color: blue;
}

Define global variables as css file

It's just a suggestion for implement.

Now global variables defined as 'variables' in options. And it is an js object.

For me it would be better to import variables as file instead, for example:

options: { variablesPath: 'src/variables.css' }

P.S. Why I need it:

It's because I use css-modules and have no way to set variables declarations somewhere top.

It is possible to import variables from every file which needs them, but I'm using variables as a method to decouple components from global files :) As a context for component...

The solution I use for now is implicitly importing of variables file in sass-loader.

Plugin doesn't return messages or warnings for undefined variable usage

I am coming up with an issue that when I have declarations with a missing or non-existent variable the CSS returns undefined (which is expected) however no warnings or messages coming through to the result…here is a gist that contains a rudimentary setup.

if you pull down that gist and run node index.js you will see the compiled CSS compiles with an undefined but results.messages & results.warnings() both return blank.

:root {
    --font-family: 'Wingdings', 'Comic Sans', 'Papyrus', sans-serif;
}

body {
    font-family: var(--font-family);
    color: var(--black);
}

Please let me know if I can help in anyway! 🍻

Parenthesis pair mangled when variables declared within a CSS function

Hello,

I try to transform a css file (material-components-web.css) that contains variables declared in differents ways.
Some of them are not replaced by the plugin. For example :
background-color: color(var(--mdc-theme-text-primary-on-primary, white));
gives :
background-color: color(white;
So it miss a ')' before ';'

I had a look to the code of the plugin and I think that I found a solution. In the file resolve-value.js, I modified the regex variable :
RE_VAR_FUNC = (/var\((--[^,\s]+?)(?:\s*,\s*(.+))?\)/)
to
RE_VAR_FUNC = (/var\((--[^,\s]+?)(?:\s*,\s*([^\)\(]+|(.+)))?\)/);

It seems to work. If it is ok for you, can you implement it in your future versions?
Thx

Resolve nested `var` in fallback

Just a spec clarification , are we allowed to refer fallback as another var ie var(--color-2) from root

:root {
 --color-1:red;
 --color-2:green;
}

.Component {
  background: var(--color-10,var(--color-2))
}

I expect output to be

.Component {
  background: green
}

but the current output is

.Component {
  background: var(--color-2)
}

Config defined variables do not work with option `preserve: true`

When postcss-css-variables is configured with both preserve: true and preconfigured variables, the end result is css code that do not work.

Configuration:

{
   preserve: true,
  variables: { '--red': '#FF0000' },
}

Usage:

    background-color: var(--red);

Resulting css:
image

Expected result:
All configured variables should be should be added to :root so that they can be used together with the preserve: true option.

Very cool, but incorrect variable overriding

At first.. lib is awesome!

But I think following output for that fixture isn't correct.

:root {
    --some-width: 150px;
}

.box-foo {
    --some-width: 333px;
    width: var(--some-width);

    .box-bar {
        width: var(--some-width);
    }
}

@media (max-width: 800px) {
    .box-foo {
        --some-width: 300px;
    }
}

output

.box-foo {
    width: 333px;

    .box-bar {
        width: 333px;
    }

    @media (max-width: 800px) {

        .box-bar {
            width: 300px; /* here should be also 333px */
        }
    }
}

@media (max-width: 800px) {
    .box-foo {
        width: 300px;
    }
}

notice the .box-bar in media query. I think it should be 333px, not 300px as defined in box-foo media query?

Chaining variables in media queries results in duplicated blocks

The issue might seem related to #64, the difference being that there is no problem with nesting in the example below.

The issue can be replicated in the playground with the following input:

:root {
  --space-small: 10px;
  --space-large: 20px;
}

@media (min-width: 768px) {
  :root {
    --space-small: 20px;
    --space-large: 30px;
  }
}

h1 {
  padding: var(--space-small) var(--space-large);
}

h2 {
  padding: var(--space-small);
}

In the output, the h2 is defined as expected, while h1's media query block gets duplicated a few times:

h1 {
  padding: 10px 20px;
}

@media (min-width: 768px) {

  h1 {
  padding: 20px 30px;
  }
}

@media (min-width: 768px) {

  h1 {
  padding: 20px 30px;
  }
}

@media (min-width: 768px) {

  h1 {
  padding: 20px 30px;
  }
}

@media (min-width: 768px) {

  h1 {
  padding: 20px 30px;
  }
}

If using 3 values for padding, the level of replication is increased.

wrong media query order

Thanks for your work.
Recently I've been using this plugin, It worked well but some error occurs.

Here is my original code:

:root {
	--color: green; 
}

div {
	color: var(--color);
}

@meida (max-width: 10000px) {
	:root {
		--color: red;
	}
}

@meida (max-width: 1000px) {
	:root {
		--color: yellow;
	}
}

and I used playground output is:

div {
	color: green;
}

@meida (max-width: 1000px) {

	div {
		color: yellow;
	}
}

@meida (max-width: 10000px) {

	div {
		color: red;
	}
}

The media query order is a in a wrong one, is that something can be fixed?

Thanks!~

Displaying readable errors

For now it looks like this great plugin doesn’t log any errors at all.
If I for example have a setup like this:

:root {
  --my-color: red;
}

.btn {
  color: var(--other-color);
}

All I get is a postcss error that looks something like this:
TypeError: Cannot read property 'indexOf' of undefined]

Would be nice if this plugin could show what the error is, which file and which linenumber. And maybe using postcss-reporter.

Inherited calculation not using correctly scoped variable

I enter following:

:root {
    --aaa: 2;
    --bbb: calc(var(--aaa) * 2);
}

.btn {
    --aaa: 3;
    width: var(--aaa);
    height: var(--bbb);
}

.btn:hover {
    --aaa: 4;
}

and receive:

.btn {
    width: 3;
    height: calc(4 * 2); /*here is the error, it should be 3*2*/
}

.btn:hover {
    height: calc(4 * 2);
}

.btn:hover {
    width: 4;
}

Not working when variables file is @import -ed

I have variables in one file, let's call it 'vars.css'

In 'main.css' I try to @import './vars.css'and use variables. This fails and renders undefined. If I define variables in the same file where I use them, it's working.

vars.css

:root {
  --red: #D85743;
}

main.css

@import './vars.css'; /*or @import url('./vars.css')*/

.red {
  color: var(--red);
}

Option 'preserve' doesn't work inside @media rules

input css with option preserve = true

@media screen and (max-width: 700px) {
    :root {
        --color-link: purple;
    }
}
.link {
    color: var(--color-link);
}

output

@media screen and (max-width: 700px) {
    .link {
        color: purple;
    }
}

Expected output

@media screen and (max-width: 700px) {
    .link {
        color: purple;
        color: var(--color-link);
    }
}

Nested selectors break compilation

Given:

:root {
  --color: red;
}

h1 {
  background: var(--color);
  &:hover {
    background: var(--color);
  }
}
h2, input[type=text] {
  background: var(--color);
  &:hover {
    background: var(--color);
  }
}

Expected:

h1 {
  background: red;
  &:hover {
    background: red;
  }
}
h2 {
  background: red;
  &:hover {
    background: red;
  }
}
input[type=text] {
  background: red;
  &:hover {
    background: red;
  }
}

Actual:

h1 {
  background: red;
  &:hover {
    background: red;
  }
}
h2 {
  background: red;
  &:hover {
    background: var(--color);
  }
}
input[type=text] {
  background: red;
  &:hover {
    background: var(--color);
  }
}

Using deprecated PostCSS methods

Hey there! Just a heads-up that this is using some deprecated PostCSS methods (or so my logs tell me)!

Container#eachDecl is deprecated. Use Container#walkDecls instead.
Node#removeSelf is deprecated. Use Node#remove.
Container#eachRule is deprecated. Use Container#walkRules instead.
Container#eachAtRule is deprecated. Use Container#walkAtRules instead.
Node#style() is deprecated. Use Node#raw()
Node#before is deprecated. Use Node#raws.before
Node#_value was deprecated. Use Node#raws.value

Selector which is separated by comma

I expected .a x, .b x would be separated into two ruleset but the output wasn't.

Input:

.a {
    --color: red;
}
.b {
    --color: blue;
}

.a x, .b x {
    color: var(--color);
}

Real output:

.a x, .b x {
    color: blue;
}

Expected:

.a x {
    color: red;
}

.b x {
    color: blue;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.