CSS in the age of components

technology
software app
Mandy Trilck

Mandy Trilck

CSS, the language that styles the web, has one characteristic that consistently generates debate: its global scope. In a traditional style sheet, styles apply across an entire website or application. Over the years, naming conventions such as BEM and SMACSS have been created to help contain the global scope chaos. These systems have sought to make a more modular, scalable technology out of CSS when inherently it is not.

As web development makes an increasingly firmer shift toward components and modular design, the focus on the global scope issue is intensifying. Before, separation of concerns dictated that CSS, HTML and JS files be kept separate. But frameworks like React and Vue tightly couple HTML and JS in the same files, dividing projects by components not languages. This has led to the question, how should styling fit into this structure?

New school of CSS

A myriad of styling libraries, style systems and build processes have appeared to answer this question. Here we will look at some of the main ones and what advantages they offer over traditional CSS.

style-library-logos
Modular style sheets

Sass Modules

Sass, the most popular extension language for CSS, has always had a degree of modularity, as it allows style sheets to be divided into several smaller ones. Many developers follow a common structure like the 7-1 pattern to further organize their projects. However, separate files are ultimately combined into one style sheet using the @import feature, risking naming conflicts.

In 2019, Sass made its next big step toward modularity by introducing modules. The @import feature has been replaced by @use and @forward. These new features explicitly define relationships between files in a project, removing naming conflicts and clarifying the origin of dependencies.

For example, @use gives a namespace to imported features:

@use 'buttons'; 

This brings in styles from the buttons file, which can then be accessed in the following way:

$btn-color: buttons.$color;

CSS Modules

CSS modules, started in 2015, is a build process that generates a global stylesheet but with unique class names scoped to each component.

In CSS Modules, .module.css and .js files are created for each component. The CSS can use any class names, even repeating ones in other files. This is because the CSS Modules compiler transforms the class names into unique ones, avoiding any possible naming conflicts.

Another bonus is that the unique naming still includes human readable words. This makes it easier for developers to find and maintain styles.

For example, if we have a file called box.css, a selector like this:

.text {
  color: blue;
}

Once compiled turns into something like:

.box_text_j3xk {
  color: blue;
} 

A unique selector with the file name, the class name and a random hash.

CSS-in-JS

CSS-in-JS is just that, CSS written in JavaScript files. This method puts the most emphasis on modularity, taking separate style sheets out of the equation and allowing styles to be directly collocated with components. It’s an approach that has had both strong support and criticism.

CSS-in-JS is handled in various ways depending on the system used. At its most basic, styles can be applied straight to DOM elements. More commonly, a CSS-in-JS library is employed to handle styling in a performant way and add capabilities such as theming and global styles. These libraries include two main types:

Styled Components and Emotion–these libraries allow you to create custom components in a CSS-like syntax via template literals. 

const StyledSection = styled.section`
  text-align: center;
  margin: 0 2em;
`

In the JSX, the <StyledSection> component can now be employed:

render(
  <StyledSection>
    <h1>Hello World!</h1>
  <StyledSection>
)

Component libraries such as Grommet and Rebass, which offer pre-fab components that are styled principally by accepting system properties.

In the case of Rebass, you could style a box component declared in the JSX in the following way:

<Box
  p={5}
  fontSize={4}
  width={[ 1, 1, 1/2 ]}
  color='white'
  bg='primary'
/>
Styled Components and Emotion are likely to be the most comfortable for CSS purists. Styles can be kept in the same file as the component or imported from a separate file, for a more traditional approach. For example, you could create a folder for a Button component that houses both an index.js file and style.js file.

One of the principal advantages of CSS-in-JS is the fluid way in which styles can be themed, passed in via props and changed based on state. 

In Sass and CSS modules, the workaround is to apply class names based on props. In Styled Components it looks something like this:

const Button = styled.button`
   background: ${props => props.primary ? "purple" : "white"};
   color: ${props => props.primary ? "white" : "purple"};
`
render (
   <Button primary />
)

Xstyled, a wrapper for Styled Components and Emotion, can be used for an extra clean theme syntax. For example, if we have a value set for “primary” in our theme.js file, we can write the following:

import styled from '@xstyled/styled-components'

const Button = styled.button`
   width: 200px;
   height: 100px;
   background-color: primary;
`
export default Button
The best styling choice for modern JS frameworks

For whatever reason, this question is still hotly debated. Sass is an excellent technology and organizations that have invested a significant amount of resources in implementing this technology often fail to see the benefit of switching to a new model. Obviously, with the introduction modules Sass has tackled some of the scoping issues that were making developers consider other solutions. For JS developers who were never in love with CSS to begin with, CSS-in-JS could likely seem much more “cool.”

A few truths exist that make Styled Components (or Emotion) a persuasive choice. Styled Components:

  • Use Javascript and compiler magic to achieve the same features that make Sass great, like nesting, variables, etc.
  • Are more readable than Sass for the average Javascript developer who is building components, and are still readable for UX-developers without much JS experience
  • Include automatic vendor prefixing

Are not just a niche technology–some big production projects are using styled components: Patreon, Target, Reddit, Autodesk, Atlaskit, Typeform, Vogue, and Coinbase, to name a few.

Conclusion

Styling technolgies are evolving rapidly with the Javascript ecosystem and becoming increasingly modular. With an overwhelming number of new technologies and techniques available, it can be easy to write them off until they become more standardized. Yet it’s clear the industry is embracing these new approaches, so we will continue to see them grow and make styling even more interesting in the future.

Know your types of headless CMS

The business risks of overlooking software documentation

The value of a startup idea

Share This