CSS Modules: the correct code split
There is a lot of talk going on in the JavaScript Frontend Community about using CSSinJS. One example for this are styled-components.
A use of them is explained over at https://www.toptal.com/javascript/styled-components-library .
In this Article I want to name an alternative and talk about some benefits.
What are CSS modules?
According to the css-modules github repo:
A CSS Module is a CSS file in which all class names and animation names are scoped locally by default.
For use in React or Vue f.e. this would mean:
All of the styles inside of a CSS Module will not affect anything else than the Component on which they are imported in.
Using CSS modules
Lets try this out with a a bit of React.
First we write a Box Component like this:
import React from 'react';
import styles from './Box.css';
const Box = () => <div />;
export default Box;
And apply some styles to it:
import React from 'react';
import styles from './Box.css';
const Box = () => <div className={styles.box} />;
export default Box;
Notice how we just import some CSS file into our JavaScript. This is where the magic happens.
In this case the CSS modularization happens through the webpack css-loader.
This is the Box.css
file that gets imported.
.box {
width: 400px;
height: 300px;
border-bottom: solid brown 4px;
border-right: solid brown 4px;
border-left: solid brown 4px;
}
we can check out the browser to see what the result looks like.
Notice the class name? This is how CSS Modules achieve the local scoping. The imported class will be added on the correct Components and in the process their names will be changed and a unique hash added.
This will prevent any collisions with rules of other components.
No collision
Lets try this out in the browser.
Here are 2 components that use the same class name in their CSS:
Banana Component
import React from 'react';
import styles from './Banana.css';
const Banana = () => (
<div className={styles.container}>
<p className={styles.text}>Banana</p>
</div>
);
export default Banana;
.container {
display: flex;
justify-content: center;
align-items: center;
border: solid 1px yellow;
}
.text {
color: yellow;
}
Apple Component
import React from 'react';
import styles from './Apple.css';
const Apple = () => (
<div className={styles.container}>
<p className={styles.text}>Apple</p>
</div>
);
export default Apple;
.container {
display: flex;
justify-content: center;
align-items: center;
border: solid 1px green;
}
.text {
color: green;
}
Both of the components use the same classes inside of them. If we would write normal CSS this should lead to collisions, meaning that one set of rules would overwrite the other.
But checking the website again we can see that everything is normal.
Take note of the hashed class names again.
All collisions are avoided by making the class names unique. Similar to techniques such as BEM, just in an automated way.
Conclusion
This was a very brief introduction to CSS Modules but should give a good understanding of what they do and how they work.
Some of the features are similar to techniques such as styled-components, but by being just CSS files we can benefit from some advantages.
Lets dive into the Pros and Cons to wrap it up:
Pros
- Designers do not need to learn new ways of writing CSS in JS. Instead they can easily make changes to the correct CSS files. This way of styling, combined with mental models such a atomic design, can increase communication between Developers and Designers and development speed_._
- Separation of Concerns: We hear this all the time in Web Development and it was regarded as best practice for a long time. Given JSXs popularity one might argue that this is not true anymore, but we should still aim for it.
- Tools and Preprocessors such as PostCss can be easily integrated to allow CSS Imports, Custom Properties etc.
Cons
- The build task might be complicated to set up at first
- Global styles have to be wrapped in a special :global block. Where would such a block belong?
- The power of JavaScript is not available inside the CSS files
Cover Image is from https://unsplash.com/photos/8EzNkvLQosk