# CSS Modules

## Summary


CSS was invented to style web pages. A typical web page contains many elements or components such as menus, buttons, input boxes, and so on. Styles defined in a CSS file are accessible to the entire web page in which that file is included. In other words, all style definitions have global scope. What if we want some styles to be visible only to one component of the page?

CSS was defined to style documents, not UI components. The lack of modularity in CSS language makes it hard to maintain complex or legacy code. Developers are afraid to make code changes since it's easy to break something when CSS definitions are global. 

CSS Modules solves these problems by limiting the scope to components. CSS Modules is not an official standard. It's a community-led effort popularized by the ReactJS ecosystem.

## Discussion

### What are the problems that CSS Modules solve?

The problem of **global scope** is solved by CSS Modules since class names are local to the component. The same class name can be used in another component with different styling. Even though CSS as a standard has only global scope for names, CSS Modules leverages on tooling. Tools convert local names to globally unique names. 

Deeply nested CSS selectors result in what we call **high specificity**. This impacts performance. With CSS Modules, names are globally unique and locally specific. Hence, flat selectors are more than sufficient. Because CSS styles are now encapsulated within components, code becomes more **maintainable**. Code can be refactored. Dead code can be removed. 


### What are the essential features of CSS Modules?

CSS Modules has the following features: 

    + **Local Scope**: Class names and animation names are locally scoped by default.
    + **Global Scope**: Using `:global` switch, developer can choose to reuse some styles globally.
    + **Composition**: A selector can extend styles from another, thus promoting reuse of styles within local scope. Composition can't be used for global scope. A selector can be composed from a selector in global scope or selectors in other files.
    + **Naming**: Names should be in camelCase. Though traditional CSS naming convention is to use kebab-case, hyphens can cause problems when accessed within JavaScript. The use of camelCase simplifies the syntax.
    + **Integration**: CSS Modules should have tooling support to compile CSS to a low-level format called *Interoperable CSS (ICSS)*. It should also work nicely with CSS processors (Less, Sass, PostCSS), bundlers (Webpack) and JS frameworks (Angular, React).

### Could you explain how CSS Modules work?

CSS as a language doesn't support local scopes. All names have global scope. To overcome this limitation, developers use tools to automatically transform local names to globally unique names. These names are generated by the CSS Modules compiler. The compiler also generates a JS object to map old names to new names. Therefore, developers can continue to use local names in their component code. 

For example, let's take a UI component called "Cat". Its styles are in file "Cat.css" where `.meow` is defined. It's possible that the same class is used in another component, let's say, "WildCat". To avoid this name conflict, CSS Modules compiler makes each name unique. 

CSS Modules is flexible. It doesn't impose a specific naming convention. In our example, the new class name is `.cat_meow_j3xk`, where the module name is used as a prefix and a hash value is used as a suffix. The mapping from old to new names goes into a JS object. 


### What tools and plugins help with implementing CSS Modules?

Webpack's *css-modules* or PostCSS's *postcss-modules* can be used to implement CSS Modules. PostCSS can be used along with task runners such as Gulp or Grunt. PostCSS is really using JS plugins to transform CSS. 

To tell Webpack how to load CSS files, there are *css-loader* and *style-loader*. These may be enough to use CSS Modules with Angular, TypeScript and Bootstrap. 

With Browserify, the plugin to use is *css-modulesify*. For use in Rails, there's *cssm-rails*. With JSPM, there's *jspm-loader-css-modules*. 

CSS Modules can be used within JS frameworks. For React, there's *react-css-modules* or *babel-plugin-react-css-modules*. CSS preprocessors such as SCSS can be used along with CSS Modules using *sass-loader*. Gatsby is another example where CSS Modules can be used. 

To catch problems early, there's eslint-plugin-css-modules.


### Are there alternatives to using CSS Modules?

Historically, CSS started as a single file for an entire app. Thanks to tooling such as Webpack's *css-loader*, it became possible to use one stylesheet file per component. Each component's folder contained its CSS and JS files. However, styles still had global scope. 

Global scope was partially solved by OOCSS, SMACSS, BEM, etc. **Block-Element-Modifier (BEM)** brought some modularity to CSS via a naming convention. It solved CSS specificity problem. However, class names were long and had to be named by developers. With CSS Modules, naming is taken care of by the build tools. During coding, developers use simpler and intuitive names. We can customize class names, including the use of BEM-style naming if desired. 

**CSS in JS** embeds CSS directly in a JS file. The CSS model is at component level rather than at document level. For example, in *JSS*, styling is defined as JS objects. In another library called *styled-components*, tagged template literals are used. Michele Bertoli has a curated comparison list of many CSS-in-JS techniques.


### Isn't W3C standardizing CSS Modules?

No. CSS Modules is not a standard. It doesn't change the CSS specifications in any way. CSS definitions retain global scope but CSS Modules makes them "behave locally" by renaming them with unique names, which are then referenced by their components in HTML or JS. This is possible because of tooling support. 

Beginners may confuse CSS Modules with another concept called *CSS3 modules*. In June 2011, CSS2.1 became a W3C Recommendation. However, this process took 13 long years, mainly because the specification was a monolith. When work started on CSS3, it was therefore decided to split the specifications into separate modules. Each module can take its own path of standardization. These modules are not related to CSS Modules. 

A related concept is the use of *namespaces* in CSS. These refer to XML namespaces and how these can be used within CSS selectors. HTML `style` element has the `scoped` attribute for local scoping but this is now deprecated. 


### What are some criticisms of CSS Modules?

It's been said that CSS Modules does nothing more than automate class naming so as to avoid name collisions. Developers can still do wrong things without CSS Modules warning them about it. It's not clear if typo errors will be caught at compile time or runtime. You can't share constants across CSS and JS files. **TypeStyle** is one approach that solves some of these issues. It mimics CSS Modules pattern using JS objects. 

Back in 2016, one developer commented that CSS Modules is not ready for prime time. He mentions some limitations of using `@value` and `composes`. He states that using pseudo-selectors can be unreliable. 

The use of camelCase that's not typical of CSS naming convention is seen as a limitation. While some frameworks may have plugins to solve some of these issues (such as *babel-plugin-react-css-modules*) it may prove difficult to make CSS Modules work with others. 

## Milestones

2011

Facebook releases a JavaScript library called **ReactJS**. The design approach is modular, with a web page being built from a hierarchy of UI components. Two years later the project is open sourced. 

Apr  
2012

Version 0.1.0 of **css-loader** for Webpack is released on NPM repository. This gives control over how CSS is loaded into a project. This becomes useful when CSS is used directly within a UI component implemented in JS. 

2014

Christopher Chedeau, a frontend developer at Facebook, lists a number of problems with CSS at scale. He states that while JS recommends avoiding global variables, CSS still uses global names. Facebook initially solves many of the issues by extending CSS and later by using **inline styles**. Styles are specified as JS objects within UI components. Mixing content and styling might seem like a bad approach but every component encapsulates its own styling without relying on global variables. The common name for this approach is **CSS in JS**. 

Apr  
2015

Webpack's css-loader starts supporting local scope with the use of `:local` switch. A month later some folks implement a module for PostCSS called **postcss-local-scope**, so that CSS styles are local by default even without using the switch. Only globals need to be explicitly specified with the `:global` switch. 

May  
2015

The PostCSS module postcss-local-scope gets integrated into css-loader of Webpack. Meanwhile, initial commit of **CSS Modules** happens on GitHub. 

Jun  
2015

The low-level file format that enables CSS Modules is specified separately as **Interoperable CSS (ICSS)**. This becomes the common format for module systems. The specifications is meant for loader implementers, not end users. Meanwhile, ICSS is implemented in loaders including css-loader (webpack), browersify, and jspm.