Motivation

When people say that they dislike CSS it’s mostly because of the cascading. In the modern age of component based development we managed to fix scalability of our Front-End apps or Front-End part of our apps if that terminology suits you better. But CSS is more than less the same old thing if we approach it in the traditional way.

Luckily enough JavaScript is not the only part of FE which evolves with time and performance gains can and need to be implemented on UI / App / Network levels…

Obfuscated CSS class names == smaller bundle size == less amount of data to transfer over network.

If you use BEM (which is still awesome and very relevant, mainly because of modifier concept) you can imagine how long class names can be (most of the time longer and meaningful naming in programming can lead to much better readability). There are many use-cases where one HTML element need to have multiple CSS classess which in BEM can end up looking like this.

<button class=”button button-color-red button--active”>title</button>

In our use-case we managed to reduce size of the our CSS bundle by 28%

JS bundle is reduced by some % as well, much less than 28% but still less.

Solution

CSS modules solve the encapsulation problem in CSS. Which is the main cause of cascade related pain that FE devs experience. Global namespace in UI can be compared to the global scope in JS. I don’t need to stress out how important it is to avoid using global vars in any serious application…

Note: Since CSS modules do not care about how you organize your CSS any methodology such is mentioned BEM should still be applied.

So lets start with implementation!

Button.css

.button {

font-size: 20px;

color: black;

} .button--color-red {

color: red;

} .button--active {

color: green;

}

Button.js

import React from 'react';

import PropTypes from 'prop-types';

import classNames from 'classnames/bind'; import styles from './css/Button.scss';

const cx = classNames.bind(styles); const Button = ({ label, color, isActive }) => {

const cssClasses = cx({

'button': true,

'button--color-red': (color === 'primary'),

'button--active': isActive,

}); return (

<button className={cssClasses}>

{label}

</button>

);

}; Button.propTypes = {

label: PropTypes.string,

color: PropTypes.string,

isActive: PropTypes.bool,

}; export default Button;

webpack.config.js / loaders section

{

test: /\.css$/,

use: [

{

loader: 'style-loader'

},

{

loader: 'css-loader',

options: {

modules: true,

importLoaders: 1,

localIdentName: '[sha1:hash:hex:4]'

}

}

]

}

modules property tells Webpack that class names needs to be obfuscated. You can set it to false in dev build and class names will stay the same as in CSS file. That is very useful for development.

localIdentName property is configuration for the format of the class names after obfuscation. [sha1:hash:hex:4] — this configuration will output 4 letter class names encoded with sha1. If you think that 4 characters is too little for safe usage feel free to add more…

Who is using this approach?

Gmail

Well, nobody big… just Google and Facebook and…

Compatibility

Note that this approach is 100% SCSS / LESS compatible ❤️

Alternative

If you don’t like classnames approach, feel free to try react-css-modules. Both ways of solving the CSS class names obfuscation are legit.

Different opinions, or the Reddit: https://www.reddit.com/r/javascript/comments/7n3oi9/how_to_obfuscate_css_class_names_with_react_and/