Coder Social home page Coder Social logo

css-modules's Introduction

CSS Modules Logo

CSS Modules

A CSS Module is a CSS file where all class names and animation names are scoped locally by default. All URLs (url(...)) and @imports are in module request format (./xxx and ../xxx means relative, xxx and xxx/yyy means in modules folder, i.e. in node_modules).

CSS Modules compile to a low-level interchange format called ICSS (or Interoperable CSS) but are written like normal CSS files:

/* style.css */
.className {
  color: green;
}

When importing a CSS Module from a JavaScript Module, it exports an object with all mappings from local names to global names.

import styles from './style.css';

element.innerHTML = '<div class="' + styles.className + '">';

Table of Contents

Why CSS Modules?

  • Local Scope Prevents Clashes: CSS Modules use local scope to avoid style conflicts across different project parts, allowing component-scoped styling.
  • Clear Style Dependencies: Importing styles into their respective components clarifies which styles impact which areas, enhancing code readability and maintenance.
  • Solves Global Scope Problems: CSS Modules prevent the common issue of styles in one file affecting the entire project by localizing styles to specific components.
  • Boosts Reusability and Modularity: CSS Modules allow the same class names in different modules, promoting modular, reusable styling.

css-modules's People

Contributors

ahmadawais avatar codejet avatar ezugudor avatar fibo avatar geelen avatar gpkc avatar josephrexme avatar joshgillies avatar joshwnj avatar juanca avatar krishnadevz avatar leerob avatar madyankin avatar markdalgleish avatar mhujer avatar moox avatar oliverjash avatar peteruithoven avatar sokra avatar summerisgone avatar svenheden avatar svnm avatar trysound avatar wu0792 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  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

css-modules's Issues

Question: Inconsistent rule global/local

I am using a grid that was written in sass and trying to use it but not sure if I am using css-module correctly. I am getting the following error:

Inconsistent rule global/local result in rule '.l-wrap:before, :global .wrap:before, .l-wrap:after, :global .wrap:after' (multiple selectors must result in the same mode for the rule)

I know it is hard to tell without knowing the grid, but this is how I am using it:

@import "~grid/grid";
:global {
  .wrap { @include l-wrap }
}

I would like to make the .wrap class globally accessible. It works if I don't include the global.

Below is the relevant line in the webpack config:

{ test: /\.scss$/, loader: ExtractTextPlugin.extract('style-loader', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass') }

Would appreciate any pointers.

Nesting class definitions to reduce repeating "composes" rules

So I read this article talking about CSS modules and in step 2 it shows this piece of CSS:

.common {
  /* all the common styles you want */
}
.normal {
  composes: common;
  /* anything that only applies to Normal */
}
.disabled {
  composes: common;
  /* anything that only applies to Disabled */
}
.error {
  composes: common;
  /* anything that only applies to Error */
}
.inProgress {
  composes: common;
  /* anything that only applies to In Progress */
}

And the repetition of composes: common instantly jumped out to me. From working in Less (or really, any of the popular alternatives), you could do this kind of "common and flavors" kind of styling like so:

.common {
  /* all the common styles you want */
  &.normal { /* the & makes this translate to .common.normal, just in case you weren't aware */
    /* anything that only applies to Normal */
  }
  &.disabled {
    /* anything that only applies to Disabled */
  }
  &.error {
    /* anything that only applies to Error */
  }
  &.inProgress {
    /* anything that only applies to In Progress */
  }
}

And bam, you're not repeating the composes: common for the common stuff anymore.

I couldn't find any reference to if this was possible with CSS modules, which is why I'm opening this issue about it.

It should be clear where to file an issue

The project is split between many different repos. Yet, at this stage many of the issues are feature specific so it's not clear where they should be filed.

I think the READMEs should point to one place to file the issues. The best solution, would be to have a clear spec or list of supported features. That way, that repo could have issues and PRs for updating the spec.

Ideally, an update to the spec could list the degree of support. So for example, a new un-implemented feature would be mentioned in the spec as in-progress. And a completed feature, would be mentioned in the spec as implemented.

Debugging tips

Hey there,

I'm using css-modules right now with webpack and css-loader and style-loader and the one big pain point we're having is it's hard to go from looking at a browser to finding the class definition. The mangled names make it hard to backtrace where the css is coming from. Are you familiar with a "sourcemaps" mode or a debug mode that includes the original name in the mangled name? Any pointers here would be great!

Importing into CSS Module

I'm wondering what method people are using for importing data into their CSS Modules. composes is great for extending/composing styles but what about data such as color variables or measurement defaults?

I had a look at the ICSS spec and the :import syntax (https://github.com/css-modules/icss#import) but it doesn't look suited to for this use case.

Are there any patterns/techniques other people are using for this?

What is the recommended way of adding multiple conditional classes to a component?

I have a <Capsule /> component that requires at least the .base class. There are two other classes that extend the .base class:

.base {
    background-color: white;
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07);
    box-sizing: border-box;
    color: rgb(114, 110, 101);
    font-size: 11px;
    margin-top: 24px;
    min-height: 54px;
    padding: 20px;
    position: relative;
}
.clickable {
    composes: base;
    cursor: pointer;
}
.withIcon {
    composes: base;
    padding-left: 62px;
}

Depending on where the <Capsule /> is rendered, the .clickable and .withIcon classes aren't always needed. There are occasions when both .clickable and .withIcon will be needed.

I know that I could create another class:

.clickableWithIcon {
    composes: clickable;
    composes: withIcon;
}

But that just seems silly to me. I can't account for every combination, and there will likely be more. What would be the recommended way of doing what classNames pulls off with global classes in React?

Best Approach / Example For Use In MeteorJs

Hi, I had noticed that you have some example projects built, and was wondering if one for Meteor is a possibility. The meteor community is great, and I think with the many advantages of Meteor that CSS Modules, along with a Spacebars(Handlebars) integration it would be a great fit. Thanks for any help.

support composes inside pseudo-element

I have some CSS looks like this:

.button {
  composes: button from './component/button.css';

  color: #fff;
}

.icon {
  /* style to add an icon before a button*/
  position: absolute;
  top: 50%;
  width: 20px;
  height: 20px;
  line-height: 20px;
  margin-top: -10px;
  font-size: 14px;
}

.button::before {
  composes: icon;

  /* some custom option */
  left: 30px;
  content: 'T';
}

But got an error saying Module build failed: Error: composes is only allowed when selector is single :local class name not in ":local(.button)::before"

composes seems only work for normal selector without pseudo. Is there a way to support using composes inside a pseudo-element?

More details of the error message:

./~/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./~/postcss-loader!./src/pages/Regional/regional.css
Module build failed: Error: composes is only allowed when selector is single :local class name not in ":local(.distractName)::before"
    at /Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss-modules-scope/lib/index.js:22:13
    at Array.map (native)
    at getSingleLocalNamesForComposes (/Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss-modules-scope/lib/index.js:20:26)
    at /Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss-modules-scope/lib/index.js:106:26
    at /Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:131:34
    at /Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:102:26
    at Rule.each (/Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:89:22)
    at Rule.eachInside (/Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:101:21)
    at Rule.eachDecl (/Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:129:25)
    at /Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss-modules-scope/lib/index.js:105:12
    at /Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:141:30
    at /Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:102:26
    at Root.each (/Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:89:22)
    at Root.eachInside (/Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:101:21)
    at Root.eachRule (/Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss/lib/container.js:139:21)
    at /Users/fraserxu/code/work/CVR-candidate-module/node_modules/css-loader/node_modules/postcss-modules-scope/lib/index.js:101:9
 @ ./src/pages/Regional/regional.css 4:14-206 13:2-17:4 14:20-212

How to pass variable to common CSS classes

I recently adopted css-modules

.boxShadow {
    -moz-box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .05);
    -webkit-box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .05);
    -webkit-tap-highlight-color: rgba(169, 3, 41, .5);
}

this boxShadow class I have defined in common style.css. I am reusing composes at several places.
at some places, I want to use -3px instead of -2px. and Instead of rgba(0, 0, 0, .05) I want to use a separate color.
Currently I am creating multiple version of .boxShodow like .boxShadowBlueStyle, .boxShadowRedStyle.

composes with absolute path

    composes: redBackground from "../../../../css/common/style.css";

I am using react-css-module.
this path is working file but If I change the location of file, I need to recalculate path again. It is possible to give absolute path ??
Life will be easy.

raw selectors

I really love the idea - it's the way how we should all write CSS from now! The thing is... there's a lot of existing unmodular CSS libraries and some of the frameworks even use tagnames in selectors.

Is somehow possible to import raw selectors? If I understand this correctly it's limited to classnames. This is all cool and great as long as we are writing all the CSS from scratch which is little unrealistic. It would be very welcomed feature if we could import raw selectors in any kind of "hacky" way because this would allow us to use modules right now - it does transpiling anyway so it should be possible, right?

Or how about supporting this via some kind of plugin so it would be optional & discouraged but possible for people who knows what they're doing?

Composes should work with `import` semantics

ES6 introduces the idea of structured imports as a way of sharing re-usable code. It would be great if css-modules had import and composes flag supported it. Here's an example of what I mean

before:

.element {
  composes: large from "./typography.css";
  composes: dark-text from "./colors.css";
}

after:

import $typography from "typography";
import $colors from "colors";

.element {
  composes: $typography.large;
  composes: $colors.dark-text;
}

Benefits

  • consistent with ES6 semantics
  • modules are imported once on top
  • styles are referenced the same in JS land and CSS land (submitStyles.normal) is similar to (colors.darkBlue)

Proposed change

I'm not sure if postcss-modules-extract-imports can be changed here or if there should be a second postcss preprocessor, that does a transform. I'm interested in the postcss plugin semantics, so if you provide some guidelines I'd like to see if i can jump in and try to implement this.

Semantics

List of supported import semantics

import name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import name , { member [ , [...] ] } from "module-name";
import "module-name";

While the list is pretty long I could see many of them being relavant

import $colors from "colors";
import { $dark-blue } from "colors";
import { $dark-blue as $darkBlue } from "colors";
import { $dark-blue, $dark-red } from "colors";
import $colors , { $dark-blue, $dark-red } from "colors";

Usage in a library

We want to extract react components we use in multiple projects into a 'common' private npm module. and we would like to use css-modules to have local, 'encapsulated' class names on those extracted components.

We also would like consumers of this common package not to depend on css-modules.

We wonder if the right way to do this would be exposing a webpack-bundled version; with the styles extracted by extract-text-plugin. But: a) it seems weird to expose a bundled js in this "library context" and b) we would like to only include the css of the components we actually use, not all.

Do you have any pointers if this can be accomplished?

Provide documentation for :import and :export

ICSS spec defines two methods :import and :export.

I am trying to use them with webpack style-loader, e.g.

default.css

.squareShape {
    width: 10px;
    height: 10px;
}

custom.css

:import('./default.css') {
    defaultSquare: squareShape;
}

.test {
    composes: defaultSquare;
    color: #f00;
}

This produces:

.default__squareShape___2yjy0 {
    width: 10px;
    height: 10px;
}
.custom__test___2tYf3 {
    color: #f00;
}

am I doing something wrong?

The documentation is lacking and I am not getting an error.

Preprocessor Compatibility?

This project is very innovative, and at the right direction too! But correct me if I'm wrong, things like this:

.normal {
  composes: common;
  composes: primary from "../shared/colors.css";
}

Would break the very strict Sass compiler, no?

String usage

Some of React fans said, that most amazing thing in JSX is that all code (HTML template and JS) is in one file.

Maybe we should do some syntax like this for CSS Modules:

import react from 'react';
import css   from `css-modules/string`;

let style = css`
  .link {
  }
  .link:hover {
  }
  @media (min-width: 500px) { .link {} }
`;

export default class Link exted React.Component {
    render() {
        <div class={style.link}>
        </div>
    }
}

Main question, how we can extract this styles from JS file too put them to CSS bundle.

Variables express different semantics than class composition

There's been a lot of discussion surrounding the exclusion of variables in css-modules, and there are some good arguments suggesting that composable classes render them obsolete. However, I'd like to elaborate on a case for variables made here.

Suppose that I have a primary brand color. Sometimes it's used as a text color, or a background, or a border color, or in a gradient. The only way to do this with (pure) CSS Modules is to make multiple separate classes which each reference that color (with clever naming as suggested by @geelen), and are then composed as needed:

.primary {
  color: blue;
}
.on-primary {
  background-color: blue;
}
.surrounded-by-primary {
  border-color: blue;
}
// etc.

.myClass {
  composes: on-primary
}

This is verbose (both in declaration and in composes usage); if the color changes, I have to change all of the references, which leaves a lot of room for error; if I use the color in a new property, I have to introduce an additional reference. It's not unreasonable for a project to have several such colors, which each require this set of classes.

More importantly, it seems like the semantics here are wrong. Composition is not the semantic idea I'm trying to declaratively express. What I actually am expressing is the use of a constant value in different contexts:

.myClass {
  border-color: $color.primary;
}

Even if you find the "X", "on-X", etc. renaming more readable, you still have to declare it for every X, missing the point that X is a variable.

In short, class composition provides a way to reuse property-value pairings, but not a way to reuse values across properties, which I think is fundamentally different (and useful). Thoughts?

(I realize that I can use a preprocessor for variables/mixins, and I respect the goal of keeping CSS Modules bloat free, but it would be really nice if it provided a complete minimal solution where using a preprocessor doesn't feel necessary. This seems like a big enough hole that I can't imagine using CSS Modules alone on any reasonably-sized project.)

P.S. Thanks a ton for your work on this spec!

Motivation for camelCase naming

For local class names camelCase naming is recommended, but not enforced.

What was the motivation behind the camelCase naming recommendation? Perhaps we could add it to the README, it's not very obvious to me.

css className conflict

Just set up a repo https://github.com/chenxsan/css-module-class-conflict to demo this problem, I had these css codes

.title {
  composes: small from './border.css';
  composes: small from './borderRadius.css';
}

in app.css, expected the exported class name to be border__small__xxxxx borderRadius__small__xxxxx, but i got this:

screen shot 2015-09-08 at 16 19 59

I got two borderRadius__small__xxxxx, the first small was overwritten by the second small.

Is this an expected behavior?

Passing local classes to unknown children

E.g.

Knowing the children

Like my comment here. This is great, we know the children, and can specify the button class and be done with it.

render() {
    return (
        <div className={ classes }>
            <h1 className={ styles.text }>{ this.props.label }</h1>
            <Button href={ this.props.button.href } className={ styles.button }>{ this.props.button.label }</Button>
        </div>
    );
}

Not knowing the children

  • Children could be a button, but it could also be a dropdown etc ( styles.dropdown , styles.button )
  • They're not really 'states' of these components, as it's particular to the parent. E.g. adjusting some layout particular that only happens in this parent component.

So how could I go about solving this?

render() {
    return (
        <div className={ classes }>
            <h1 className={ styles.text }>{ this.props.label }</h1>
            { this.props.children }
        </div>
    );
}

Parameterization of css modules & media queries?

Goal

  • I'm trying to always write components which contain all the html/css/js they need.

Status Quo

  • In javascript I can export a function and pass in options, e.g.
// DEFINITION [componentX.js]
module.exports = function (componentX) {
  var color1 = componentX.color1;
  var border1 = componentX.border1;
  // ...
};

// USAGE (e.g. [componentY.js])
var componentX = require('componentX')({color1:'#f00', border1:'1px solid black'};
// ...
  • But in css I CANNOT pass arguments to an @import statement.
/* DEFINITION [componentX.css]
/* ??? how would that even look like ??? */

/* USAGE (e.g. [componentY.css]) */
@import 'componentX' {  /* doesnt work! */
  color1: #f00;
  border1: 1px solid black;
}

(My) Status Quo

  • Currently, I'm using atomify
  • It allows the package.json to contain:
  "main": "index.js",
  "style": "index.css",

...and it watches those and all dependencies and processes them like:

  • all javascript require('...')s
  • all css @import ...s
  • all html/templates which get required and inlined as a string into javascript
  • all assets used in any html/template or css
    ...and "onChange" updates a bundle.js and bundle.css file which live updates in the browser via browsersync

Problem

  • atomify allow me to write
:root {
  --ComponentName-variableName1:  value;
  --ComponentName-variableName2:  value;
  --ComponentName-variableName3:  value;
  /* ... */
  --SubComponentName-variableName1: var(--ComponentName--variableNameX1);
  --SubComponentName-variableName2: var(--ComponentName--variableNameX2);
  /* ... */
}
  • My components define their "css input" through an INTERFACE as a set of
  • --ComponentName-variableNameX: value;
  • If I re-use a component as a "sub-component", I can customize/overwrite the defaults specified in the sub-component itself (see above)

My questions:

  • What if my "css variables" change in response to media queries matching?
  • How would I approach the above and media queries with css-modules?

The following doesn't work when using atomify

:root {
  --Theme-font-size1             : 6.5vw;
  --Theme-font-size2             : 3vw;
  --Theme-font-size3             : 2.3vw;
  --Theme-borderwidth            : 4vw;
  /* Sub Components */

  --Markdownbox-font-size1             : var(--Theme-font-size1);
  --Markdownbox-font-size2             : var(--Theme-font-size2);
  --Markdownbox-font-size3             : var(--Theme-font-size3);
  --Markdownbox-borderwidth            : var(--Theme-borderwidth);
}
@media all and (min-width: 0px) and (max-width: 450px) {
  :root {
    --Theme-font-size1             : 6.5vw;
    --Theme-font-size2             : 3vw;
    --Theme-font-size3             : 2.3vw;
    --Theme-borderwidth            : 4vw;
  }
}
@media all and (min-width: 450px) and (max-width: 600px) {
  :root {
    --Theme-font-size1             : 6.5vw;
    --Theme-font-size2             : 3vw;
    --Theme-font-size3             : 2.3vw;
    --Theme-borderwidth            : 4vw;
  }
}

Convert selector names to camel case

Are there any reasons to not do this by default? This would fit existing CSS written with hyphens and underscores. Also in JavaScript dot notation feels better: s['box-js_blue'] vs s.boxJsBlue.

The Purpose Of `CSS Modules`

JSS

Develop a convention for ensuring globally-unique selectors

=> JSS is generating CSS-Class-Prefixes

atomify-css

=> In package.json, define a "style":... property, that points to the entry css file of a component

Final Thought

Maybe it's worth communicating with the authors of those packages to brainstorm about a convention. If JSS generated prefixes would be combined with a standard way of export like in atomify-css, a convention could be agreed upon and implemented and spread :-)

How to use composition in elements without className?

@geelen I'm following your suggestion and creating a healthy issue to discuss this.

What do you recommend for the follow scenario:

.docs h3 { 
  composes: color;
}

.page h3 { 
  composes: color;
}

I'm re-writing the page/docs for Minigrid and I'm using markdown-loader for generate content for both. I can use my own markdownLoader to parse the text, add the classNames and give it back to the webpack. For this simple case it works fine, however my concern is when the project grows this could become problematic. I'd like to be able to achieve this without have to overwrite the loader and parse the content.

Thoughts?

Thanks 🍺

Add Examples, maybe a spec

The blog post shares lots of examples that are not in the documentation:

http://glenmaddern.com/articles/css-modules

It'd be great if the documentation outlined a full list of supported features. It'd be better if there were a formal way of expressing the functionality.


I'm not sure if the place for this is in another markdown file or more examples...

composes is the wrong word

"The composes keyword says that .normal includes all the styles from .common"
Great, except you have the meaning of the word reversed.
In the context above it actually means ".normal is part of .common", which is clearly not the intent.
If you wanted it to mean that ".normal includes all the styles from .common" then perhaps .normal should be "composedOf: common" or "comprises: common"

follow-up at: https://news.ycombinator.com/item?id=10084954

Node support

Hi
css-modules is a very good idea.
I really understand that it is working like a charm with combination with webpack. But a lot of us are using the React like an isomorphic application. That means we are rendering whole page on the server with pure nodejs and babel(es6 support). The problem is that I am not able to simply use "import styles from .css" because there is no webpack in the middle.
Do you have any idea how to use this great idea with node/io on the server side?
Somehow like babel/register. If we will have this it will be like holy grail for css :)

Nesting local classes in separate module

Drawing from Bootstrap, i have Button and ButtonGroup components (React variety). Each has it's own CSS module. What i'd like to do is nest the Button component class in the ButtonGroup so that its styling changes. At the moment

/* button.css */
.button { ... }

/* buttongroup.css */
.buttonGroup > .button { .... }

transforms to something like:

.button---3h-GD { ... }
.buttonGroup---3qigr > .button---3t-2h { ... }

The nested button class has no reference to the button module so ends up with a difference class name, hence the styling for that component doesn't change when contained within a ButtonGroup.

I've been trying to figure out if the following can/should be done with composes or, rethinking how the component works (e.g. the ButtonGroup component could apply a new class to each child rather than using nested selectors.). Maybe what i'm trying to do is against what is being achieved with CSS modules but if so, what do you see as the suitable alternative to achieving the same behaviour?

"universal" usage?

I'm looking for some help to figure out the best way to use css-modules in a "universal" (server and client rendered) environment. Life is good on the client, but on the server, things get tricky.

Using React and css-modulesify, things I've considered:

  1. using browserify to compile React components on the server, using the css-modulesify plugin, and then evaling the result. I've not gotten this work yet, but I dislike any solution that involves eval and it's slow to go through the whole browserify pipeline.
  2. using a babel plugin to parse css require calls in the same way css-modulesify works. Would this work?
  3. just monkey patching require to do the same thing.

Has anyone tried this yet?

Discussion: How do css-modules compare to scoped styles + extending custom elements?

In the Polymer (and other web component implementations), global styles are avoided through a clever and IMHO, elegant use of combining styles scoped to a custom element by default, and extending these "noop" elements to include these styles in other places.

I see a few advantages to this approach:

  • It doesn't require JavaScript to generate classes. Currently, and correct me if I'm wrong, css-modules plays really well if you're entire markup is generated in JS, and classes are imported at runtime from style.css.js. With web components, you can be declarative in a template source with your intended classes, making source a bit easier to grok.
  • Scoped styles and web component inheritance seem a bit more "native to the web", whereas ICSS seems to be a de facto specification. Obviously, being de facto is not an indication of the effectiveness or potential success of a tool, but I'm more interested in understanding if ICSS and css-modules is complimentary or divergent from future web features.

Let me know if this isn't the appropriate avenue for this discussion, I'd be happy to post this in the appropriate place.

Add compile-time error if duplicate properties are composed

As the readme notes, if there are duplicate properties from compositions the order of application is undefined. In addition, the silent overriding of properties would seem to introduce hard problems of debugging if multiple identical properties are composed together even if they happened to be in the right order. Adding a compile-time error, or an option to enable a compile-time error, when multiple identical properties are composed would seem to help to alleviate these problems.

Import order when composing multiple classes

Imagine:

// a.css
.a { color: #aaa; }
// b.css
.b { color: #bbb; }
// ab.css
.ab {
    composes: a from './a.css';
    composes: b from './b.css';
}
// ba.css
.ba {
    composes: b from './b.css';
    composes: a from './a.css';
}
# ab.js
import ab from './ab.css';

render() {
    return <div class={ab.ab}>AB</div>;
}
# ba.js
import ba from './ba.css';

render() {
    return <div class={ba.ba}>BA</div>;
}

You'd expect AB to always be #bbb (because b gets imported last), and BA to always be #aaa for the same reason. If you look at both JS files independently, that is. However, since you depend on import order (which can be affected by other imports happening anywhere in the same codebase), you lose control over the inheritance.

This is fine-ish when you know your codebase and can be sure that CSS is always imported in the right order, but the moment someone imports b.css before you get the chance to import a.css first, you lose the expected result.

With preprocessors and things like @extends you don't get this issue because imports just flow linear and deciding what CSS comes first is a lot more explicit. Their documentation explicitly says that the order of inheritance is purely defined by when selectors occur in the CSS.

There's a way to fix this, but it means adding specificity tricks, and adding selectors to the imported CSS selector in the output.

Using the examples above, it'd lead to this (no class name mangling for clarity, together in a gist):

.a, .a.ab-a-specific, .a.ba-a-specific.ba-a-specific-specific { color: #aaa; }
.b, .b.ab-b-specific.ab-b-specific-specific, .b.ba-b-specific { color: #bbb; }
<div class="ab a ab-a-specific b ab-b-specific ab-b-specific-specific">AB</div>
<div class="ba b ba-b-specific a ba-a-specific ba-a-specific-specific">BA</div>

The good things: it works, repetition gzips well. The bad thing: it's ugly, a challenge to implement.

In projects with lots of composing this could lead to huge selectors, since you're basically replacing all inheritance-by-inclusion-order with explicit specificity. Luckily it's only necessary once you start dealing with composing from multiple classes in a single new class, so maybe it's still something to consider? It would vastly increase complexity of the code, since any class would cause new selectors to be added to all classes it composes from and all their parents too, all the way up the tree.

The other option is probably just making no guarantees about import/override order when dealing with composing from multiple classes. Which is also not ideal and basically means it's an unreliable feature.

Maybe I'm thinking too far here, but I think it's something to look into, at least.

Recommended way to "extend" native HTML elements

Hope I don't act as stupid by doing so but I repost here the question above asked by another user as we are invited by repo maintainer at end of the now closed (for non question itself related reasons) issue thread.
( #32)


"I've been experimenting with css-modules and came across an issue to which I found no sensible solution for.

I would like to know how I can create variables with css-modules and re-use them across my CSS components. I am aware that the workflow with css-modules is a little different than with Sass/Less, but take this as an example:

The sass way

// variables
$size-small: 0.8em;
$color-faded: #eee;

// rules
small {
  font-size: $size-small;
}

footer p {
  color: $color-faded;
}

css-modules way... well, what I tried anyway

// typography.css
.small {
  font-size: 0.8em;
}

// colors.css
.faded {
  color: #eee;
}

// rules
small {
  composes: small from 'typography.css';
}

footer p {
  composes: faded from 'colors.css';
}

But we cannot use composes in native HTML elements.

What am I missing here?
Maybe I am approaching this the wrong way?

If the solution is to add a class to every element, then... goodbye css-modules πŸ‘‹

Any advice, recommendation or insults will be very helpful.

πŸ‘Š"

Recommended way to "extend" native HTML elements

Hello,

I've been experimenting with css-modules and came across an issue to which I found no sensible solution for.

I would like to know how I can create variables with css-modules and re-use them across my CSS components. I am aware that the workflow with css-modules is a little different than with Sass/Less, but take this as an example:

The sass way*

// variables
$size-small: 0.8em;
$color-faded: #eee;

// rules
small {
  font-size: $size-small;
}

footer p {
  color: $color-faded;
}

css-modules way... well, what I tried anyway

// typography.css
.small {
  font-size: 0.8em;
}

// colors.css
.faded {
  color: #eee;
}

// rules
small {
  composes: small from 'typography.css';
}

footer p {
  composes: faded from 'colors.css';
}

But we cannot use composes in native HTML elements.

What am I missing here?
Maybe I am approaching this the wrong way?

If the solution is to add a class to every element, then... goodbye css-modules πŸ‘‹

Any advice, recommendation or insults will be very helpful.

πŸ‘Š

Composes with global class name

Composes is really useful, but when I work with a shared css, sometimes, I need to compose with a global class name, but currently it is not allowed.

There is two variants:
1.- Compose with an global external class name, e.g.: from a shared css library.
2.- Compose with a global local class name. It is less useful, It currently doesn't work too, but actually I don't need this kind of functionality.

Thanks for all.

Best Practices structuring composable classes?

Hi

Are there currently best practices around how to structure composable classes without those becoming a huge pile + mess?

I am looking for:

  • when/where to cut and dice
  • how to bundle
  • how to name
  • how to structure directories
  • where to accept duplication / where not
  • what to avoid
    • eg there is a strong movement against variables
      • how does the alternative pattern look like (in reality - eg if you have the color used for 20 things)
  • etc

Just to make sure… ;)
"The beauty is you can do everything as you like" is not a useful answer atm. ;)
No doubt we will still adapt to own needs, but i would love to hear if there are already lessons learned by others.

Thanks a ton in advance!

Dependency and import order - how to handle circular dependencies with composes

Hi!

I've been exploring CSS modules and came across an issue/quirk. Because of how composes works now, I think there might be arise some issues with large/complex codebases, maybe?

Currently, when .specific composes from .general, CSS modules simply adds both classes to the element .specific and relies on the order the CSS files were imported in the browser to make sure everything overrides correctly. This works fine as long as everything is simple and the hierarchy only flows in one direction in all cases.

But, how do you handle circular dependency in that case? Just like circular dependencies in Javascript modules, which means, simply fail? I suppose that's not that much of a problem, again, as long as everything in the hierarchy flows downwards. Am I right in thinking this?

Apologies

I'd like to apologise for my behaviour when raising #32.

I expressed my frustration in a rather aggressive way but in no way I meant to disrespect the project or the authors.

I love the idea of css-modules, being primarily a presentation developer, I always try out whatever is new in the CSS world.

I guess that with the vast amount of new frameworks coming out every day, it's hard to keep up, and I felt cheated when such a basic behaviour wasn't documented clearly. Regardless, I shouldn't have expressed this in the way that I did.

So on that note, @geelen, @nkbt, @henriquea and anyone whom I may have offended, please accept my apologies.

πŸ™

Document why composes only works with class selectors

This issue (#33) is a really great explanation of the issue, but this needs to be summarised and made really visible to people coming to CSS Modules afresh. I think it makes sense to be a part of a FAQ or "Guide to CSS Modules" that would live on the project homepage, when we get one of those!

Alias for a filename?

When I see this example:

.article {
  composes: flex vertical centered from "./layout.css";
}

.masthead {
  composes: paragraph-margin-below from "./layout.css";
  /* ... */
}

.body {
  composes: max720 paragraph-margin-below from "./layout.css";
}

the question arises - what if I change file location or a name? I would have to walk over all composes rules and replace the filepath with a new one. Maybe it's worth introducing file aliases in the beginning of the CSS file. This solves:

  • easier refactoring
  • all imports are easily observed just by looking at the file heading
  • may lead to less typing ;)

Simple example may be (mimics es6 import syntax):

@require * as layout from "./layout.css";

.article {
  composes: flex vertical centered from layout;
}

.masthead {
  composes: paragraph-margin-below from layout;
  /* ... */
}

.body {
  composes: max720 paragraph-margin-below from layout;
}

it can also allow doing this:

@require flex from "./layout.css";

.article {
  composes: flex;
}

import className from fileName

Let's say I have a file in an npm module as such:

/* Card.css in the npm module `cards`*/
.card {
  background: white;
}

In another project, I want to target .card from cards.

/* Thing.css */
.row {
  /* some random grid stuff */
  .card from "cards" {
    grid-width: 1/3;
  }
}

I've seen :import from ICSS but have hanged my local setup (webpack, etc) trying to figure out how I can import an identifier from a different file.

Is this css-modules territory or should I look at other ways of importing the identifiers?

Idea: quarantine mode

This is for @markdalgleish after chatting last night

You said something like "any CSS file should be able to be treated as local" by not allowing any global selectors to leak out, or translating all h1s to .tag__h1 like in your demo. And then we talked about globals in terms of dead-code elimination. And we've argued about whether globals should just fall through using local-by-default. For the record, here's where we are right now:

/* this falls through, but we want to raise a warning in the linter */
body {
  background: papayawhip;
}

/* this is how you are supposed to be doing globals */
:global(h1) {
  font-size: 900px;
}

/* this should maaaaaaybe throw a warning? */
.header a {
  color: peru;
}

/* this should probably not throw a warning cause it's not really leaking a global */
.footer > a {
  color: palegoldenrod;
}

But let's consider someone else's code, like bootstrap. It starts with normalise, then sets default styles on a bunch of bare tags. Which makes it easy to get started with, but breaks the whole isolation idea we're talking about. So here's something I just thought of:

:global(h1) {
  composes: global(h1) from "bootstrap.css";
}

So, composes doesn't make any sense for a global, since it normally just exports multiple class names. But, if we were doing dead-code elimination, this could be an instruction to say don't delete rules about h1 in bootstrap.css.

So then we'd need a way to say don't delete any of file X, but maybe that could just be done with:

@import "reset.css";

or in JS

import styles from "reset.css";
styles.acceptAllGlobals();

Anyway, it's all churning around in my head so I wanted to try to write it down. But basically, if you compose someone elses CSS, it would be badass to be able to guarantee you were only getting the styles you were asking for.

Isomorphic support

We're writing an isomorphic app and would love to use CSS Modules but the import of styles doesn't really work server side. Is there any plan for this or an idea on how to solve this?

browserify

Is this possible with browserify? Would love an example if it is.

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.