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

Values! #28

Merged
merged 23 commits into from Oct 21, 2015

Conversation

Projects
None yet
@geelen
Member

geelen commented Sep 13, 2015

EDIT: the final version replaces @let and @import with, simply, @value. See the postcss-modules-values for more info

Hey friends, I've got an implementation of a legit extension to CSS Modules that I think we should adopt, fully, in core, and tell people to use it. I.e. this would become the third of three features (local scoping & composition are the first two), so this is a reasonably big change to our public API.

But I think it's the final piece of the puzzle to make CSS Modules really capable of changing the way people structure their CSS.

I thought I'd start with the syntax I'm proposing. We're totally going to bikeshed these names, but let's do that in a chat room, not in this issue. This issue is for discussing whether this deserves to be part of CSS Modules core.

And with that, my proposal:


Constants Values

/* colors.css */
@let primary: #BF4040;
@let secondary: #1F4F7F;

.text-primary {
  color: primary;
}

.text-secondary {
  color: secondary;
}
/* breakpoints.css */
@let small: (max-width: 599px);
@let medium: (min-width: 600px) and (max-width: 959px);
@let large: (min-width: 960px);
/* my-component.css */
@let colors: "./colors.css";
@import primary, secondary from colors;
@import small as bp-small, large as bp-large from "./breakpoints.css";

.header {
  composes: text-primary from colors;
  box-shadow: 0 0 10px secondary;
}

@media bp-small {
  .header {
    box-shadow: 0 0 4px secondary;
  }
}
@media bp-large {
  .header {
    box-shadow: 0 0 20px secondary;
  }
}

So, it breaks down to two things:

@let to declare a constant. It can be one of the following:

  • a complex expression in quotes e.g. "/path/to/file.css". The quotes are kept, so when this is used, it has to be somewhere that quotes would make sense (i.e. an @import or composes statement)
  • a valid CSS value e.g. #BF4040 or inset 0 0 2px 2px black
  • a media expression e.g. screen and (max-width: 599px)

@import to import a constant.

  • You can give it a local alias @import theirName as myName
  • You can import multiple on one line @import a, b from "./c.css".
  • You can use a constant in place of the stringed-path @let foo: "./foo.css"; @import bar from foo;

Once you have your constant defined, it'll be substituted in in one of two places:

  • A CSS declaration value: e.g. box-shadow: 0 0 20px secondary where secondary is a Constant
  • A media expression e.g. @media small where small is a Constant

One more thing, for Sass compiler compatibility, both at-rules can be prefixed with a single -, so @-import and @-let will work (@import will make Sass try to load a file and your computer will set on fire). And the @let x: y; statement doesn't need the : in the middle since Sass crashes on that too. I prefer using the : (I think it reads better) but Sass folks won't be able to insert it.


Rationale

First up, this solves some problems people are having: #25 #33 #36

It also completely removes the need for my custom-media PR: #18

It gives the whole system a flexibility we just don't have right now. I mean, none of what we're doing can't be done with other things, like a PostCSS plugin or Sass. But consider the following when you mix & match Sass & CSS Modules:

/* vars.scss */
$primary: #BF4040;
$secondary: #1F4F7F;
/* colors.css */
@import "./vars";

.text-primary {
  color: $primary;
}

.text-secondary {
  color: $secondary;
}
/* my-component.scss */
@import "./vars";

.header {
  composes: text-primary from "./colors.scss";
  box-shadow: 0 0 10px $secondary;
}

It works, and I think I'd like to put out a blog post about why you, if you have a big Sass app and want to start using CSS Modules, you should aim to get to here as a stepping-stone, but I think if that's the only way to do anything advanced with CSS Modules it's confusing at best and misleading at worst.

My key complaint is that you're mixing and matching two different ways of including other files. When you use Sass @import "./vars", you're effectively concatenating that file into yours. So if you have any actual CSS markup there (i.e. not just variable definitions) that'll get duplicated through your app. That's because Sass is designed to be a single-global compilation and CSS Modules is a multi-file system. CSS Modules won't inject the same content twice, but if you use Sass @import it will. I think we can do better.

My other argument is that we have an opportunity here. If CSS Modules can handle symbol-passing between files, we can totally break our dependency on global preprocessors. Let's look at the above situation with my Constants proposal:

/* colors.scss */
$primary: #BF4040;
$secondary: #1F4F7F;

/* We can use Sass to fill these @let declarations */
@let primary $primary; 
@let secondary $secondary;

/* We can get kinda clever with what we export too */
@let secondary-dark darken($secondary, 20%);

/* And then the rest of the file can be normal Sass */
.text-primary {
  color: $primary;
}

.text-secondary {
  color: $secondary;
}
/* my-component.scss */
@-import primary, secondary-dark as secondary from "./colors.scss";

.header {
  composes: text-primary from "./colors.scss";
  box-shadow: 0 0 10px secondary;
}

Now, we're still using Sass (as a lot of people will want to do), but we've made it a single-file preprocessor. We now use CSS Modules to export information (using @let), but we've broken the global shackles of Sass. And, in fact, our component file isn't Sass at all! We're starting to actually use modularity to change the level of abstraction that component authors are working against.

I believe that by promoting Sass as being the go-to for all the variables, mixins & functions that are missing from CSS Modules is missing a huge opportunity to better inform people about the way they can structure the app. By offering Constants, we can say "sure, use all the Sass you want, but make it compile constants & classes that you can import and compose throughout your application." By breaking the old-school idea of files being concatenated together, we get to truly modularise our code.

This all applies to PostCSS as well, since they almost all assume they're working on a single global css object. I just think that the unit of "single global css object" is now a single file, not the concatenation of many files.

Oh and one more thing, this would allow CSS Modules to @import constants from, say, a JSON file that's shared between some inline styles and your whole CSS codebase. Some folks have been asking for that, and this would let us offer it.


And just to be clear, I'm proposing adding this and basically no more. Beyond this, everything people want to use can live in userland (probably as PostCSS plugins). But at the moment we have no human-accessible way to pass information between files, and I think we need it.

Thoughts?

@geelen

This comment has been minimized.

Show comment
Hide comment
@geelen

geelen Sep 13, 2015

Member

Oh and obviously the code in this PR would be broken out into its own repo, but at least right now the tests pass!

Member

geelen commented Sep 13, 2015

Oh and obviously the code in this PR would be broken out into its own repo, but at least right now the tests pass!

@superhighfives

This comment has been minimized.

Show comment
Hide comment
@superhighfives

superhighfives Sep 13, 2015

👍 x 1,000,000.

👍 x 1,000,000.

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Sep 13, 2015

Member

👍 Sounds pretty good. There is a small thing missing, importing stuff into another name. We need this, to avoid conflicts when importing. I would propose:

@import a as newA, b as c from "./file";

Oh and one more thing, this would allow CSS Modules to @import constants from, say, a JSON file that's shared between some inline styles and your whole CSS codebase. Some folks have been asking for that, and this would let us offer it.

or you write the constants in a CSS file and import in js for inline-styles.

/* colors.css */
@let highlight: #EF4312;
import { highlight } from "./colors.css";
Member

sokra commented Sep 13, 2015

👍 Sounds pretty good. There is a small thing missing, importing stuff into another name. We need this, to avoid conflicts when importing. I would propose:

@import a as newA, b as c from "./file";

Oh and one more thing, this would allow CSS Modules to @import constants from, say, a JSON file that's shared between some inline styles and your whole CSS codebase. Some folks have been asking for that, and this would let us offer it.

or you write the constants in a CSS file and import in js for inline-styles.

/* colors.css */
@let highlight: #EF4312;
import { highlight } from "./colors.css";
@markdalgleish

This comment has been minimized.

Show comment
Hide comment
@markdalgleish

markdalgleish Sep 13, 2015

Member

You make a really strong case for this. Nice work 👍

Member

markdalgleish commented Sep 13, 2015

You make a really strong case for this. Nice work 👍

@ojame

This comment has been minimized.

Show comment
Hide comment
@ojame

ojame Sep 13, 2015

Naming conventions need work, but this looks pretty good 👍

ojame commented Sep 13, 2015

Naming conventions need work, but this looks pretty good 👍

@nelix

This comment has been minimized.

Show comment
Hide comment
@nelix

nelix Sep 13, 2015

Pretty great, I would agree with @sokra that we need named imports. But other than that I'm pretty happy with this.

nelix commented Sep 13, 2015

Pretty great, I would agree with @sokra that we need named imports. But other than that I'm pretty happy with this.

@markdalgleish

This comment has been minimized.

Show comment
Hide comment
@markdalgleish

markdalgleish Sep 13, 2015

Member

Didn't @geelen already address named imports with this line?

@import small as bp-small, large as bp-large from "./breakpoints.css";
Member

markdalgleish commented Sep 13, 2015

Didn't @geelen already address named imports with this line?

@import small as bp-small, large as bp-large from "./breakpoints.css";
@nelix

This comment has been minimized.

Show comment
Hide comment
@nelix

nelix Sep 13, 2015

OH. I totally missed that bit.
I'm happy.

nelix commented Sep 13, 2015

OH. I totally missed that bit.
I'm happy.

@joshwnj

This comment has been minimized.

Show comment
Hide comment
@joshwnj

joshwnj Sep 14, 2015

Member

great 👍

Member

joshwnj commented Sep 14, 2015

great 👍

@geelen

This comment has been minimized.

Show comment
Hide comment
@geelen

geelen Sep 14, 2015

Member

or you write the constants in a CSS file and import in js for inline-styles.

Yep, that's totally possible too! Though it does raise the question, if I have this:

/* colors.css */
@let primary: #BF4040;

.text-primary {
  color: primary;
}
import styles from "./colors.css";

Should I get a single flat JSON object with { primary: "#BF4040", 'text-primary': "_text-primary_abcd12345" } or should I get something that you could import like this:

import { classes, constants } from "./colors.css";

ICSS :export statements are totally flat, so I prefer the original. But I could see the argument for the latter.

Member

geelen commented Sep 14, 2015

or you write the constants in a CSS file and import in js for inline-styles.

Yep, that's totally possible too! Though it does raise the question, if I have this:

/* colors.css */
@let primary: #BF4040;

.text-primary {
  color: primary;
}
import styles from "./colors.css";

Should I get a single flat JSON object with { primary: "#BF4040", 'text-primary': "_text-primary_abcd12345" } or should I get something that you could import like this:

import { classes, constants } from "./colors.css";

ICSS :export statements are totally flat, so I prefer the original. But I could see the argument for the latter.

@geelen

This comment has been minimized.

Show comment
Hide comment
@geelen

geelen Sep 14, 2015

Member

Oh and if you'd like to talk naming, join the Gitter (https://gitter.im/css-modules/css-modules). I'm by no means fixed on @let and @import but I do think they're the best of the options I've heard.

Member

geelen commented Sep 14, 2015

Oh and if you'd like to talk naming, join the Gitter (https://gitter.im/css-modules/css-modules). I'm by no means fixed on @let and @import but I do think they're the best of the options I've heard.

@jhewlett

This comment has been minimized.

Show comment
Hide comment
@jhewlett

jhewlett Sep 14, 2015

@geelen Is there any value in aligning the syntax with the CSS variables proposal, a la --name: value and var(--name) ? Or are the semantics a bit different?

@geelen Is there any value in aligning the syntax with the CSS variables proposal, a la --name: value and var(--name) ? Or are the semantics a bit different?

@chrisui

This comment has been minimized.

Show comment
Hide comment
@chrisui

chrisui Sep 14, 2015

Love how this is looking 👍 as @jhewlett has mentioned I wonder if variable reference needs some more syntax around it to separate it from clashing with CSS values. (Eg. defining a constant blue)

Also a big +1 to @sokra's suggestion to avoiding naming conflict. The ES6 modules spec has been argued about for an age and has churned out an incredibly well thought out feature-set. I would continue looking to this for inspiration as the module and constant scoping there shares a lot of similarity with CSS Modules.

Also really like the idea of being able to import values from CSS into JS!

chrisui commented Sep 14, 2015

Love how this is looking 👍 as @jhewlett has mentioned I wonder if variable reference needs some more syntax around it to separate it from clashing with CSS values. (Eg. defining a constant blue)

Also a big +1 to @sokra's suggestion to avoiding naming conflict. The ES6 modules spec has been argued about for an age and has churned out an incredibly well thought out feature-set. I would continue looking to this for inspiration as the module and constant scoping there shares a lot of similarity with CSS Modules.

Also really like the idea of being able to import values from CSS into JS!

@chenxsan chenxsan referenced this pull request Sep 15, 2015

Closed

JSPM 模块化 CSS #5

@rtsao

This comment has been minimized.

Show comment
Hide comment
@rtsao

rtsao Sep 15, 2015

Contributor

Nice proposal!

A couple things:

  1. I think a single @let syntax should be chosen, preferably without a colon (which will have greater support in arbitrary CSS or CSS-like parsers). I think consistency across all CSS Modules is a bigger win then the small readability gains.

  2. I would prefer separating constants from classes when importing, so you would have your second suggestion of:

import {classes, constants} from "./file.css";

If constants and classes were combined into a single flat object, iteration over just the classes or just the constants would be difficult.

Contributor

rtsao commented Sep 15, 2015

Nice proposal!

A couple things:

  1. I think a single @let syntax should be chosen, preferably without a colon (which will have greater support in arbitrary CSS or CSS-like parsers). I think consistency across all CSS Modules is a bigger win then the small readability gains.

  2. I would prefer separating constants from classes when importing, so you would have your second suggestion of:

import {classes, constants} from "./file.css";

If constants and classes were combined into a single flat object, iteration over just the classes or just the constants would be difficult.

@markdalgleish

This comment has been minimized.

Show comment
Hide comment
@markdalgleish

markdalgleish Sep 15, 2015

Member

The problem with classes and constants being separate is you can't do named imports like this:

import { header, content, footer } from './file.css';

It's definitely a more future-proof API, though, so I can see the tradeoff being worth it.

Member

markdalgleish commented Sep 15, 2015

The problem with classes and constants being separate is you can't do named imports like this:

import { header, content, footer } from './file.css';

It's definitely a more future-proof API, though, so I can see the tradeoff being worth it.

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Sep 15, 2015

Member

I prefer the flat namespace, because it can be mapped to ES6 exports. Using CSS Modules like this:

import { header, content, footer } from "./file.css";
import * as styles from "./file.css";

may allow automatically detection of unused classes/constants in future. It makes references more "static".

Colisions between classes and constants may be a problem, but I think the naming is a bit different and colisions could be easily detected by the compiler.

For iteration we could offer exports @styles and @constants which are arrays of all local/constant names.

Member

sokra commented Sep 15, 2015

I prefer the flat namespace, because it can be mapped to ES6 exports. Using CSS Modules like this:

import { header, content, footer } from "./file.css";
import * as styles from "./file.css";

may allow automatically detection of unused classes/constants in future. It makes references more "static".

Colisions between classes and constants may be a problem, but I think the naming is a bit different and colisions could be easily detected by the compiler.

For iteration we could offer exports @styles and @constants which are arrays of all local/constant names.

@rtsao

This comment has been minimized.

Show comment
Hide comment
@rtsao

rtsao Sep 15, 2015

Contributor

What happens if there's a constant and a class with the same name?
style.css

@let primary #aabbcc;

.primary {
  color: primary;
  padding: 4px;
}

component.js

import primary from './style.css'
// what is `primary`?

I feel like something like the above style.css ought to be totally valid. To me, it is unintuitive that class names and constants should occupy the same namespace and that an error should be thrown.

Contributor

rtsao commented Sep 15, 2015

What happens if there's a constant and a class with the same name?
style.css

@let primary #aabbcc;

.primary {
  color: primary;
  padding: 4px;
}

component.js

import primary from './style.css'
// what is `primary`?

I feel like something like the above style.css ought to be totally valid. To me, it is unintuitive that class names and constants should occupy the same namespace and that an error should be thrown.

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Sep 15, 2015

Member

What happens if there's a constant and a class with the same name?

It won't compile. The CSS Modules parser can detect it and throw an error. You must rename it i. e. to primary-color.

Member

sokra commented Sep 15, 2015

What happens if there's a constant and a class with the same name?

It won't compile. The CSS Modules parser can detect it and throw an error. You must rename it i. e. to primary-color.

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Sep 15, 2015

Member

@geelen I think you can move the postcss plugin into a separate repo, with the infrastructure similar to the other postcss plugins.

Member

sokra commented Sep 15, 2015

@geelen I think you can move the postcss plugin into a separate repo, with the infrastructure similar to the other postcss plugins.

@rtsao

This comment has been minimized.

Show comment
Hide comment
@rtsao

rtsao Sep 15, 2015

Contributor

@sokra Good point about static resolution of ES6 imports and potential dead code elimination. With that in mind, I reverse my opinion as that's worth the tradeoff. 👍

Contributor

rtsao commented Sep 15, 2015

@sokra Good point about static resolution of ES6 imports and potential dead code elimination. With that in mind, I reverse my opinion as that's worth the tradeoff. 👍

@geelen

This comment has been minimized.

Show comment
Hide comment
@geelen

geelen Sep 15, 2015

Member

@sokra I agree. I'll do that at my next chance (maybe on my flight to Berlin this weekend). For the record, I prefer the flat namespace and a compiler error if you try to export the same thing twice.

I also think @define and @import (which we can also allow @import-define to avoid clashing) is the best thing. Our imports are precisely like JS imports, so we should keep the same keyword. Our constants definition aren't really the same as var, let, or const, so we shouldn't adopt those.

One question though, @import * from "./constants.css";. Should we permit that? Implementation is easy enough, but you lose greppability of your source files. We could also permit @import * as constants from "./constants.css"; but then you have this problem:

@import * as constants from "./constants.css";

.foo {
  color: constants.red; // syntax error in Sass
}

@media constants.small { // syntax error in Sass
  .foo {}
}
Member

geelen commented Sep 15, 2015

@sokra I agree. I'll do that at my next chance (maybe on my flight to Berlin this weekend). For the record, I prefer the flat namespace and a compiler error if you try to export the same thing twice.

I also think @define and @import (which we can also allow @import-define to avoid clashing) is the best thing. Our imports are precisely like JS imports, so we should keep the same keyword. Our constants definition aren't really the same as var, let, or const, so we shouldn't adopt those.

One question though, @import * from "./constants.css";. Should we permit that? Implementation is easy enough, but you lose greppability of your source files. We could also permit @import * as constants from "./constants.css"; but then you have this problem:

@import * as constants from "./constants.css";

.foo {
  color: constants.red; // syntax error in Sass
}

@media constants.small { // syntax error in Sass
  .foo {}
}
@ustccjw

This comment has been minimized.

Show comment
Hide comment
@ustccjw

ustccjw Sep 17, 2015

how about add @export keyword, then we can control export className(like es2015/es2016 export), this is very useful when we override the default style:

/*default.css*/
.root {
    width: 200px;
}
.head {
    background: #5ca941;
}
@export default {root, head, ...}

/*custom.css*/
@import defaultStyle from 'default.css'
.head {
    border: 1px solid #ccc;
    composes: defaultStyle.head;
}
@export {...defaultStyle, head}  /*head will override*/

ustccjw commented Sep 17, 2015

how about add @export keyword, then we can control export className(like es2015/es2016 export), this is very useful when we override the default style:

/*default.css*/
.root {
    width: 200px;
}
.head {
    background: #5ca941;
}
@export default {root, head, ...}

/*custom.css*/
@import defaultStyle from 'default.css'
.head {
    border: 1px solid #ccc;
    composes: defaultStyle.head;
}
@export {...defaultStyle, head}  /*head will override*/
@geelen

This comment has been minimized.

Show comment
Hide comment
@geelen

geelen Sep 19, 2015

Member

@ustccjw thanks for the suggestion but I think that's too complex for our purposes. The name you use within your file is your export name — that's the way it works for classes, that should be the way it work for constants.

Implementation is really coming on now, new project broken out here: https://github.com/css-modules/postcss-modules-constants

Member

geelen commented Sep 19, 2015

@ustccjw thanks for the suggestion but I think that's too complex for our purposes. The name you use within your file is your export name — that's the way it works for classes, that should be the way it work for constants.

Implementation is really coming on now, new project broken out here: https://github.com/css-modules/postcss-modules-constants

@bclinkinbeard

This comment has been minimized.

Show comment
Hide comment
@bclinkinbeard

bclinkinbeard Sep 19, 2015

Wouldn't @const reflect the purpose better?

Wouldn't @const reflect the purpose better?

@bclinkinbeard

This comment has been minimized.

Show comment
Hide comment
@bclinkinbeard

bclinkinbeard Sep 19, 2015

More specifically, if the feature is called constants, I would expect @const. If the syntax is @define, maybe they should be called definitions?

More specifically, if the feature is called constants, I would expect @const. If the syntax is @define, maybe they should be called definitions?

@ustccjw

This comment has been minimized.

Show comment
Hide comment
@ustccjw

ustccjw Sep 20, 2015

@geelen so, how to custom styles:try to extend the default style, then override some(this is common in component style).

BTW, May be you can take @export as a option.

ustccjw commented Sep 20, 2015

@geelen so, how to custom styles:try to extend the default style, then override some(this is common in component style).

BTW, May be you can take @export as a option.

@ryngonzalez

This comment has been minimized.

Show comment
Hide comment
@ryngonzalez

ryngonzalez Sep 20, 2015

Say I'm using cssnext, and I've got constants defined in a colors.css:

@define my-brand-color #aaa;

Could I re-use them in a css-variables definition?

@import my-brand-color from './colors.css';

:root {
  --main-color: my-brand-color;
}

Say I'm using cssnext, and I've got constants defined in a colors.css:

@define my-brand-color #aaa;

Could I re-use them in a css-variables definition?

@import my-brand-color from './colors.css';

:root {
  --main-color: my-brand-color;
}
@geelen

This comment has been minimized.

Show comment
Hide comment
@geelen

geelen Sep 21, 2015

Member

Ok, current proposal. Will start calling this Values instead of Constants, since I really don't like @const and @bclinkinbeard makes a good point. So, @value would replace @let in the original examples (instead of @define as I suggested earlier). The question is, @value also could replace @import, so you could have code that looked like this:

@value colors: "./colors.css";
@value primary, secondary from colors;
@value small as bp-small, large as bp-large from "./breakpoints.css";

So you can define a @value as either a local constant or a reference to another file. All @value statements are exported by default. So, above, the symbols that would be exported are colors primary secondary bp-small bp-large.

Oh and @sokra my point was that cssnext should run after CSS Modules on each individual file. So, once the linking process is finished, but before the files are injected into the DOM or passed on to style-loader. I have an example of that in my (closed) media query PR: #18

Member

geelen commented Sep 21, 2015

Ok, current proposal. Will start calling this Values instead of Constants, since I really don't like @const and @bclinkinbeard makes a good point. So, @value would replace @let in the original examples (instead of @define as I suggested earlier). The question is, @value also could replace @import, so you could have code that looked like this:

@value colors: "./colors.css";
@value primary, secondary from colors;
@value small as bp-small, large as bp-large from "./breakpoints.css";

So you can define a @value as either a local constant or a reference to another file. All @value statements are exported by default. So, above, the symbols that would be exported are colors primary secondary bp-small bp-large.

Oh and @sokra my point was that cssnext should run after CSS Modules on each individual file. So, once the linking process is finished, but before the files are injected into the DOM or passed on to style-loader. I have an example of that in my (closed) media query PR: #18

@donaldpipowitch

This comment has been minimized.

Show comment
Hide comment
@donaldpipowitch

donaldpipowitch Sep 21, 2015

Will start calling this Values instead of Constants ... so, @value would replace @let

Why don't you call it "values" and @let? Would be "similar" to JavaScript?

Will start calling this Values instead of Constants ... so, @value would replace @let

Why don't you call it "values" and @let? Would be "similar" to JavaScript?

@markdalgleish

This comment has been minimized.

Show comment
Hide comment
@markdalgleish

markdalgleish Sep 24, 2015

Member

@donaldpipowitch we want to have parity between the feature name and its syntax, so that it's easier to talk about and easier to learn.

Member

markdalgleish commented Sep 24, 2015

@donaldpipowitch we want to have parity between the feature name and its syntax, so that it's easier to talk about and easier to learn.

@donaldpipowitch

This comment has been minimized.

Show comment
Hide comment
@donaldpipowitch

donaldpipowitch Sep 24, 2015

So this feature is called "values" and the syntax is "@value"?
And I can read these values from JavaScript, too, right?

So this feature is called "values" and the syntax is "@value"?
And I can read these values from JavaScript, too, right?

@geelen

This comment has been minimized.

Show comment
Hide comment
@geelen

geelen Sep 24, 2015

Member

Yep, exactly!

Member

geelen commented Sep 24, 2015

Yep, exactly!

@serapath

This comment has been minimized.

Show comment
Hide comment
@serapath

serapath Sep 25, 2015

Best practice in javascript is to export a function or a constructor if you want.
You then can pass in arguments to initialize whatever is returned.

@value colors: "./colors.css";
@value primary, secondary from colors;
@value small as bp-small, large as bp-large from "./breakpoints.css";

is like

var colors = require("./colors.css")();
var primary = colors.primary;
var secondary = colors.secondary;
var bpSmall = require("./breakpoints.css")().large;
var bpSmall = require("./breakpoints.css")().small;

So for very "atomic" css components, like colors or breakpoints, nobody gives a sh**, but if you start building more highlevel components over time - the same as more highlevel components that combine many more basic components, its very very useful to be able to adapt it a bit through passing in arguments for defined parameters.

So what do you think about - or if there is a reason to not include something, how to otherwise satisfy this need?

  • What if someone creates a search bar component that comes with a search bar styling which is combined from breakpoints.css and colors.css and some more stuff - but for the new project, I need to adapt the styling ...how would i do that?

Best practice in javascript is to export a function or a constructor if you want.
You then can pass in arguments to initialize whatever is returned.

@value colors: "./colors.css";
@value primary, secondary from colors;
@value small as bp-small, large as bp-large from "./breakpoints.css";

is like

var colors = require("./colors.css")();
var primary = colors.primary;
var secondary = colors.secondary;
var bpSmall = require("./breakpoints.css")().large;
var bpSmall = require("./breakpoints.css")().small;

So for very "atomic" css components, like colors or breakpoints, nobody gives a sh**, but if you start building more highlevel components over time - the same as more highlevel components that combine many more basic components, its very very useful to be able to adapt it a bit through passing in arguments for defined parameters.

So what do you think about - or if there is a reason to not include something, how to otherwise satisfy this need?

  • What if someone creates a search bar component that comes with a search bar styling which is combined from breakpoints.css and colors.css and some more stuff - but for the new project, I need to adapt the styling ...how would i do that?

geelen added a commit that referenced this pull request Oct 21, 2015

@geelen geelen merged commit f35e116 into master Oct 21, 2015

2 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details

@geelen geelen deleted the feature/constants branch Oct 21, 2015

@skitterm

This comment has been minimized.

Show comment
Hide comment
@skitterm

skitterm Mar 18, 2016

Realize I'm 6 months late, but I like the idea of @value * from './colors.css'. It'd be great to not have to define each variable name to be used in the file.

Realize I'm 6 months late, but I like the idea of @value * from './colors.css'. It'd be great to not have to define each variable name to be used in the file.

@skitterm

This comment has been minimized.

Show comment
Hide comment
@skitterm

skitterm Mar 18, 2016

And (unless I missed it) it'd be GREAT to have a mention of values on the css-modules github readme. It's a great feature!

And (unless I missed it) it'd be GREAT to have a mention of values on the css-modules github readme. It's a great feature!

@sullenor sullenor referenced this pull request Mar 27, 2016

Closed

support values #1

@HugoGiraudel

This comment has been minimized.

Show comment
Hide comment
@HugoGiraudel

HugoGiraudel Apr 1, 2016

I didn’t read all the comments so please pardon me if this has been asked before, but what would happen when naming a variable (constant, sorry) after an identifier name or a color keyword. Like so:

@let red: #ea6153;

.text-primary {
  color: red;
}

Would it resolve to red or #ea6153? Some goes for any CSS identifier I guess.

I didn’t read all the comments so please pardon me if this has been asked before, but what would happen when naming a variable (constant, sorry) after an identifier name or a color keyword. Like so:

@let red: #ea6153;

.text-primary {
  color: red;
}

Would it resolve to red or #ea6153? Some goes for any CSS identifier I guess.

@dimaip

This comment has been minimized.

Show comment
Hide comment
@dimaip

dimaip Apr 20, 2016

@HugoGiraudel currently it gets overwritten. To me that's messy and annoying, so I would prefer to have $red instead, but that's too late I guess for such discussions.

dimaip commented Apr 20, 2016

@HugoGiraudel currently it gets overwritten. To me that's messy and annoying, so I would prefer to have $red instead, but that's too late I guess for such discussions.

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Apr 20, 2016

Member

@dimaip @value $red: #ea6153 should also work.

Member

sokra commented Apr 20, 2016

@dimaip @value $red: #ea6153 should also work.

@dimaip

This comment has been minimized.

Show comment
Hide comment
@dimaip

dimaip Apr 20, 2016

@sokra good point. Perhaps I should enforce it on our company styleguide.

dimaip commented Apr 20, 2016

@sokra good point. Perhaps I should enforce it on our company styleguide.

@kevinSuttle

This comment has been minimized.

Show comment
Hide comment
@kevinSuttle

kevinSuttle May 11, 2016

I've been kicking around a similar idea: pascalduez/postcss-map#76

I've been kicking around a similar idea: pascalduez/postcss-map#76

@gajus

This comment has been minimized.

Show comment
Hide comment
@gajus

gajus Jul 4, 2016

For me the lack of @export is a deal breaker. It defeats the purpose of explicit imports in the first place.

Consider a simple example:

/* ./colors.css */
@value primary: #BF4040;
@value secondary: #1F4F7F;
/* ./app.css */
@value primary, secondary from colors;
/* ./component.css */
@value primary, secondary from app;

I don't want ./component.css to have access to ./colors.css ◉︵◉

gajus commented Jul 4, 2016

For me the lack of @export is a deal breaker. It defeats the purpose of explicit imports in the first place.

Consider a simple example:

/* ./colors.css */
@value primary: #BF4040;
@value secondary: #1F4F7F;
/* ./app.css */
@value primary, secondary from colors;
/* ./component.css */
@value primary, secondary from app;

I don't want ./component.css to have access to ./colors.css ◉︵◉

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