Our journey into React best practices and design patterns has now reached the point where we want to make our components look beautiful. To do that, we will go through all the reasons why regular CSS may not be the best approach for styling components, and we will check out various alternative solutions.
Starting with inline styles, then Radium, CSS Modules, and Styled Components, this chapter will guide you into the magical world of CSS in JavaScript.
The topic is very hot and highly controversial, so this chapter requires an open mind in order to be understood and followed.
In this chapter, we will cover the following:
Common problems with regular CSS at scale
What it means to use inline styles in React and the downsides How the Radium library can help fix issues of inline styles
How to set up a project from scratch using Webpack and CSS Modules
Features of CSS Modules and why they represent a great solution to avoid global CSS
Styled Components, a new library that offers a modern approach to styling React components
CSS in JS
In the community, everyone agrees that a revolution took place in the styling of React components in November 2014, when Christopher Chedeau gave a talk at the NationJS conference.
Also known as Vjeux on the Internet, Christopher works at Facebook and contributes to React. In his talk, he went through all the problems related to CSS at scale that they were facing at Facebook.
It is worth understanding all of them, because some are pretty common and they will help us introduce concepts such as inline styles and locally scoped class names.
The following slide, taken from the presentation, lists the main issues with CSS:
The first well-known problem of CSS is that all the selectors are global. No matter how we organize our styles, using namespaces or a BEM-like methodology, in the end, we are always polluting the global namespace, which we all know is wrong. It is not only wrong on principle, but it also leads to many errors in big codebases, and it makes maintainability very hard in the long term. Working with big teams, it is non-trivial to know if a particular class or element has already been styled, and most of the time we tend to add more classes instead of reusing existing ones.
The second problem with CSS regards the definition of the dependencies. It is very hard, in fact, to clearly state that a particular component depends on a specific CSS and that the CSS has to be loaded for the style to be applied. Since styles are global, any style from any file can be applied to any element, and losing control is very easy.
Frontend developers tend to use pre-processors to be able to split their CSS into sub- modules, but in the end a big, global CSS bundle is generated for the browser. Since CSS codebases tend to become huge quickly, we lose control over them, and the third problem is to do with dead code elimination. It is not easy to quickly identify which styles belong to which component, and this makes deleting code incredibly hard. In fact, due to the cascading nature of CSS, removing a selector or a rule can result in an unintended result within the browser.
Another pain of working with CSS concerns the minification of the selectors and the class names, both in the CSS and in the JavaScript application. It could seem an easy task, but it is not, especially when classes are applied on the fly or concatenated in the client.
Not being able to minify and optimize class names is pretty bad for performance, and it can make a huge difference to the size of the CSS.
Another pretty common operation that is non-trivial with regular CSS is sharing constants between the styles and the client application. We often need to know the height of a header, for example, to recalculate the position of other elements that depend on it.
Usually, we read the value in the client using the JavaScript APIs, but the optimal solution would be to share constants and avoid doing expensive calculations at runtime. This represents the fifth problem that Vjeux and the other developers at Facebook tried to solve. The sixth issue concerns the non-deterministic resolution of CSS. In fact, in CSS, the order matters and if the CSS is loaded on-demand, the order is not guaranteed which leads to the wrong styles being applied to the elements.
Suppose, for example, that we want to optimize the way we request CSS, loading the CSS related to a particular page only when the users navigate to it. If the CSS related to this last page has some rules that also apply to the elements of different pages, the fact that it has been loaded last could affect the styling of the rest of the app. For example, if the user goes back to the previous page, they might see a page with a UI that is slightly different than the first time they visited it.
It is incredibly hard to control all the various combinations of styles, rules, and navigation paths, but again, being able to load the CSS when needed could have a critical impact on the performance of a web application.
Last but not least, the seventh problem of CSS, according to Christopher Chedeau, is related to isolation. In CSS, in fact, it is almost impossible to achieve a proper isolation between files or components. Selectors are global, and they can easily be overwritten. It is tricky to predict the final style of an element just by knowing the class names applied to it, because styles are not isolated and other rules in other parts of the application can affect unrelated elements.
I strongly recommend everyone check out this talk if you want to know more about the topic, because even if it sounds a bit strong and controversial, it is very inspiring and it forces you to approach the styling topic with an open mind:
https://vimeo.com/116209150
The conclusion of the talk is that to solve all the problems with CSS at scale at Facebook, they ended up using inline styles.
In the following section, we will look at what it means to use inline styles with React and the benefits and downsides of it.