RSCSS — my CSS is no longer a mess

Miko
6 min readSep 10, 2016

--

I followed RSCSS standard for over a year now and wanted to share some of my experience with it.

I worked a site that had all their styles in a few big SCSS files: variables, base, dialogs, icons, common stuff, homepage, detail page, some other common stuff, profile page, etc. Whenever anyone wrote new styles they went to some of these files. And this went on like this for a few years.

Seeing this codebase, I started asking questions like:

  • can I remove this definition?
  • will my new definition not collide with the existing ones?
  • if I change style of this button, won’t this change anything else?
  • can I simplify these selectors?
  • can I change class names to make them consistent?

And the problem is, that as the project grows, these questions become harder and harder to answer. The best answer you can give is “maybe”, because anything in your huge CSS can change anything on your site. And since bugs cost real money to your company, the answer becomes “no, don’t change anything”. That’s how the CSS becomes unmaintainable. It’s a state where you just add new stuff with very specific selectors or unique class names, so that you’re sure you don’t break anything.

So, how to avoid this? No one wants to get there.

The common project structure

In the JavaScript world, one can write unit tests, have the code checked by some linters, do end-to-end tests with Selenium. With all that tools in place, you could safely deploy your app without even opening it in browser. But it’s not the case with CSS, because bugs in styles are different. Bugs in JavaScript are like “something doesn’t work”, which boils down to throwing exceptions, or not executing the right action, or using wrong data. All these situations can be detected and checked in unit tests. In CSS, bugs are usually like “it looks ugly”, “stuff overlaps”, “text is unreadable”. It takes a human to tell if there’s a bug or not. Well, there are tools for visual regression testing but they can’t tell if a change is a bug or a feature.

Since we can’t automatically test CSS, we need some other way to fight bugs. And the idea is that when we make our code simpler, it’s harder for the bugs to hide in it.

This means we need some convention, a set of rules or guidelines to make the CSS simpler. And RSCSS says that the CSS code should be organized component-wise. Just like in React, Polymer, or pretty much any GUI library. If we already have components in React, why not have components in CSS too?

That’s basically what RSCSS is about.

There are other approaches to CSS components too, most notably CSS Modules, SMACSS and BEM. I did not use them so I can’t tell you much about them.

Our components and RSCSS

So we started reorganizing our code. Or, better, reimplementing some parts of it. We wanted to make sure that we won’t go down the same rabbit hole again.

I started with the directory structure. It also took me some time to figure it out. I wanted to keep it as simple as possible, but I came to a conclusion that each component needs to be in a separate folder. It’s very practical. In each folder, the React component is in index.jsx and its styles are in styles.scss. If it needs anything more, like unit tests, images, mocks, usage examples or other documentation, it all goes to the same folder. Like this:

ui/
MyComponent/
index.jsx ← React component
style.scss ← RSCSS component
examples.md
test.jsx
mocks.js
background.png ← images and other stuff for this component

So each component that needs any styles, has its own stylesheet, containing the matching RSCSS component definition. This means that whenever I remove a component, I remove the entire folder and its styles are gone too. So far so good.

We changed one little detail: in RSCSS, the component names are separated with hyphens, and React components use CamelCase — we decided to use the CamelCase also in CSS to keep the names consistent.

In our codebase, each component also should have usage examples. They are then used to generate an awesome interactive styleguide based on react-styleguidist. It is so great that we actually often use it to develop the component. We create an empty react class, add a few usage examples (so we specify ways we’d like to use that new component, they become demos on the styleguide page), then we open the styleguide page, and see all the examples updating live as we implement the code. It’s pretty much like TDD, just with a styleguide instead of tests, since tests for CSS are hard. Styleguide-driven development is a thing.

Defining the component boundaries

That’s where we come to the tricky part. You need to say precisely where is the line between components, like, the parent and the child. This all boils down to Single Responsibility Principle — your component should do one thing. If it’s a container, it should lay out the children and not style anything inside. RSCSS actually defines most of it in detail and it’s a great help.

I give my special +1 for the rule that the component should never position itself. As I said, we have a styleguide with examples, and if, say, a HamburgerMenu would position itself with position: fixed (as it does in the app) we couldn’t reasonably showcase our menus in the styleguide. Same for dialogs and popups. With the reasonable component approach it became obvious that they should all be positioned within parent components, or in case of menus, within App. App is the only component that we don’t have a demo for — but fortunately it doesn’t do much. It just creates and positions the header, footer, and menus. And these are all separate components.

Sometimes the question of boundaries is tricky. For example, we have a box that uses a gradient to cover some part of the content. The gradient should blend nicely with the background color. And the background is usually white, but sometimes it’s grey. This grey background can come from various container components, and I needed some simple way for the box to determine if it’s on white or grey background. So we agreed on a common -shadow variant for all the grey boxes. The box with gradient now checks if it’s in a .-shadow and shows up with white or grey gradient. This is kinda breaking the RSCSS rules, but I find it practical. And I also believe it’s fine to sometimes break the rules, given it doesn’t happen too often. I’d say, once for 50 components is fine. :)

It’s not always easy to find the exact boundary.

Stuff outside components

Sometimes we also wanted to write some generic styles for something — let say, some generic class for HTML lists — but always later came to a conclusion that it’s better to make it a component. Currently all our CSS is in components, except 3 files: definitions (colors and some generic mixins like singleLineEllipsis), reset (box-sizing: border-box, resetting some default styles) and base (styles for html tags, e.g. colors of links — there are really few).

Finish line

RSCSS works because it goes in line with React components so naturally. Our styles aren’t “some additional stuff in a separate folder”, they are an integral part of each component. It just feels right this way. RSCSS and React component coexist within the same folder and their relationship is obvious to anyone.

Update (09.2016): Now there’s also a stylelint-rscss plugin for checking your styles automatically with stylelint! Be sure to add both to your project.

Feedback? Questions? Please leave a comment, I’ll try to answer all of them.

--

--