Journey to Enjoyable, Maintainable Styling with React, ITCSS, and CSS-in-JS

Knowing why humans do what they do fascinates me, and many times I learn much more from the path leading to a conclusion than I do from the conclusion itself. I’ve chosen to include my learning journey in this post in hopes that it may provide valuable context to the conclusion and resonate with your respective learning journeys.

Content

  1. Context
  2. Making Styling Better With better CSS
  3. Making Styling Better With Components
  4. Making Styling Better With JavaScript
  5. Current Approach With ITCSS and Aphrodite

Context

I lead a team actively developing for and maintaining a 15-month-old react application of non-trivial size. So while Ryan’s tweet remains mostly true,

not only has it been some time since we’ve felt the traditional pains of styling we tend to glean morbid amusement from…

but our current styling story is straight up enjoyable. Indulge me as I share how we got here.

Author Bias Calibrator

I’m a pixel guy, and a real sucker for quality aesthetics. Want me to choose your product over another and pay a premium for it? Make it look good. Primary reason I roll with standardjs for everything? I think my JS looks prettier without the eyesores known as semi-colons #correctopinion.

To boot, things like bootstrap (did you see the pun back there? 😳) are demonstrably out of the question for me on account of being a 1/4th hipster.

Styling evolutionary journey 👀.

So despite the path to CSS enlightenment basically being a giant thorn-bush maze set up by someone in charge of organizing the Tri-Wizard Tournament, I channel my inner masochist and press forward like there is a Dragonite augmenting reality at the finish.

Let’s enter the maze.

Making Styling better with better CSS

Do you remember when you were first learning CSS? Early CSS me is rather adorable, but with time and effort I figured out how in the world the box model worked and that `position: absolute;` all the things was a bad idea. From that point on, making my pixels do what I wanted was a relatively straightforward CSS-Tricks search away.

What was an absolute unstraightforward (totally a word) nightmare though? Keeping markup and their accompanying stylesheets sane. This was the case for me even considering at the time I was neither working on very complex UX nor sharing a codebase with anyone.

Behold a snapshot of literal CSS I once was quite proud of spawning:

Before long, I was yearning for my code to be as pretty as my pixels.

The Oracles

So I consulted CSS oracles the likes of Nicolas Gallagher (suitcss), Nicole Sullivan (OOCSS), Jonathan Snook (SMACSS), Brad Frost (Atomic Design), Lea Verou (CSS Secrets), Mark Otto (bootstrap), and mrmrs (tachyons) to name several.

I experimented a lot. My favorite experiment was probably Glen Maddern’s “Attribute Modules” approach:

I had our team use this exclusively on an earlier Angular app and loved it. Markup remind you of anything?

I drew upon the Oracles’ collective body of CSS wisdom and experience to inch towards CSS nirvana. I learned a Pokemon Go server-size load from them, plucking out best practices like BEM naming convention or tools like SASS as I went.

CSS Wizardry & ITCSS

Of the oracles I consulted, Harry Roberts (also appropriately known as csswizardry), proved the most influential. By using his masterly crafted inuitcss framework, I became subliminally familiar with his system for organizing CSS known as the ITCSS Architecture.

Never heard of ITCSS? Don’t feel bad. Admittedly, recognition and resources don’t have a lot of visibility. Notwithstanding, ITCSS emerged as the simple and elegant methodology I was missing to introduce sanity to my stylesheets, and has proven to be my secret styling weapon.

What is ITCSS?

Harry explains best.

ITCSS — which stands for Inverted Triangle CSS — is a fully managed CSS architecture. It’s not a framework or library; there’s nothing to download or install.
It’s a collection of principles and metrics by which developers should group and order their CSS in order to keep it scalable, terse, logical, and manageable.
— Harry Roberts, Manage large-scale web projects with new CSS architecture ITCSS

The layered methodology was born to address two categories of imperfection when building large scale apps:

  1. Shortcomings inherent in CSS the language
  2. Shortcomings inherent in human developers

ITCSS is designed to:

  • Create a sane environment that is accessible to lots of people
  • Tame and manage source order and the cascade (CSS specific)
  • Create a place for every (new and old) style to live
  • Reduce waste and redundancy
  • End “Specificity Wars” (CSS specific)

ITCSS does this by inviting us to think in terms of specificity starting from far-reaching, app-wide styling to granular, single-element effected styling. Hence the “Inverted Triangle.”

What it ends up looking like:

Despite largely being designed to address CSS the language weaknesses, we’ll see later how the ITCSS methodology transcends nicely when we start removing CSS from the styling equation.

For brevity, I’ll end my “Intro to ITCSS” and direct you to one of those “inconspicuous” resources I recently discovered: Intro to ITCSS for Web Developers.

🤗

Harry Roberts and the oracles brought me a little closer to CSS nirvana. Where there use to be haphazard rhyme and reason strewn across a single stylesheet, I was greeted by carefully constructed methodology, convention, and tooling. Yet, at the other end of the whirlwind oracle consumption, I couldn’t help but feel like CSS deserved it’s own bachelor’s degree.

Making Styling Better With Components

Fundamentally I think there are problems beyond the scope of solutions that CSS Specialists can come up with.

The Nicolas Gallagher Confession

It was Christmas vacation 2014, and I was taking advantage of the reprieve from the family “we must be doing something at all times or we’re wasting valuable vacation time” pressure by watching a presentation given by another heavy influence, Nicolas Gallagher. The talk took place at dotCSS the month prior and is entitled Thinking Beyond “Scalable CSS.”

Sharing his own learning journey, Nicolas proceeded to simultaneously trigger imposter syndrome and induce me with FOMO. Within the first few minutes he admitted:

I remember feeling anxious about… the things I championed on my blog… [and] how the decisions I make might negatively impact the lives of the people… who read the stuff that I wrote about.

OH. Oh good 😳. THAT’S ME!

Wait but why? While Nicolas articulately details his reasoning in his presentation (seriously watch the first 3 minutes. They’re gold.), the following soundbite captures the spirit of his confession nicely:

We’ve often overdosed on CSS focused solutions and the creation of complicated systems that we expect other engineers who don’t specialize in CSS to understand… Including teams of great engineers.

Well great. What do you propose we do now Mr. Gallagher?

The work that we’re [now] doing [at Twitter] is starting to see the UI module… as the primary unit of scale. The foundational building block of applications.

He explained, in the abstract, how they were using these discrete component things with well defined APIs to manage complexity and encapsulate styles. Unfortunately he never bothered to explain how they were able to do that.

Examples of Twitter’s component organization from Nicolas’s presentation.

He also mentioned something about building a dependency tree of all these components that magically rolled them all up along with their styles using something called “Webpack.” Well that sounded fancy, but considering I was barely getting the hang of grunt and wasn’t Twitter engineer smart, it also sounded well beyond me.

By the end, my mind was left buzzing with new ideas and possibilities, but with no clear technologies I could adopt to help me. I did my best to apply the principles and concepts surrounding “components” to an Angular application I was architecting at the time, but ultimately it felt incredibly lackluster in relation to the utopia Nicolas described.

The New Girl

Have you ever determined to end a long-time relationship with someone (you really liked) minutes into first interacting with someone new? I have. Well… only if you count the first time I played with React after Angular and I had been seeing each other pretty seriously for a little over a year.

My introduction to React took place a couple months after Nicolas had exposed my mind to thinking of components as the “primary unit of scale,” which in retrospect may very well be why I was sold so quickly. So despite the paradoxical sadness of leaving Angular behind, I only wish React and I had met sooner.

The developer experience for styling a large codebase went from 👌 to awesome largely by doing no more than adopting React + Webpack.

CSS + Components === ❤

Many of CSS’s lingering pain points melted away by organizing styles with their accompanying components. For example, you can easily avoid global namespace clashing by applying BEM naming convention using the component name as the “Block.”

Shortly after adopting Webpack we began using CSS Modules to move this component/style relationship from implicit to explicit:

We also dropped SASS in favor of cssnext, but if I’m being honest, switching to these technologies did just as much for the look at my cutting edge tech stack ego as they did to objectively improve our developer experience.

Components as the primary unit of scale are the real MVPs here.

Making Styling better with JavaScript

¿¡CSS in JS!?

Applause please for Christopher “vjuex” Chedeau for officially rocking the CSS boat with his seminal “React: CSS in JS” 👏👏👏. I enjoy picturing Christopher taking a bat to the beehive that can on occasion bee 👀 the web development community. Chris gave visibility to this new frontier of styling while simultaneously sending off a fleet of developer explorers to go do great things.

The prospect of styling with JavaScript was exciting. Why? Glad I asked for you. Here are a few reasons:

  • Context Switching: As vast as an improvement organizing CSS with their accompanying components was… styling still required switching back and forth not only from different files but also from two very different languages and syntaxes. This carries with it an under appreciated amount of mental overhead.
  • Co-Location is Love: What can I say? JSX spoiled me. While avoiding file context switching is, I believe, objectively superior, there is so much about having everything in one file that feels so subjectively nice.
  • JavaScript!!!: JavaScript is far more expressive than CSS (or any other “precompiled” CSS language for that matter. Not sure this needs much explaining. I laugh when I consider the mental strain I would go through to try and pull off in CSS what could be so simply and easily accomplished with a basic function or data structure in JS.
  • Publishing Styled Components: I want zero things to do with trying to wrangle a 3rd party stylesheet in to my codebase just to use a component. Not worth it. I don’t have to hassle with that if your component is styled with JS.

Within months, “inline-styles” took on viability. Pioneers like Michael Chan (check out his React Europe talk on the topic) and technologies like Radium aided in giving birth to the “inline-style” revolution.

For the uninitiated, here are what inline-styles look like:

Input
Output in DOM

Inline-styles are so handy for quick and simple styling when the context-switch isn’t worth it, but I never reached a point where I believed I could use them as a comprehensive solution. The various implementations came with unfortunate tradeoffs when trying to deal with challenges like vendor prefixing, media queries, or pseudo styling (:hover). Purely inline-style solutions ultimately felt too incomplete and/or over-engineered to prefer over CSS Modules.

New Girl Part Duex: The Goddess Of Beauty

As almost all good things in my developer life, Aphrodite low-key showed up in my Twitter feed (one of the reasons I consider Twitter to be invaluable).

Here she is:

Input
Output in DOM.

Note the differences in output between inline-styles and Aphrodite. There are several significant ones I’ll leave you to find. The one I’ll focus on is that you’re seeing the styles extracted into a stylesheet (placed by Aphrodite in the <head/>) rather than inlined into the element. Rather than try to re-engineer CSS using JS DOM apis like `onMouseOver,` Aphrodite uses JS as the medium by which a CSS stylesheet is created.

Aphrodite comes with all the benefits of styling with JS without many of the tradeoffs accompanying inline-styles. The turn-around time for learning about Aphrodite and then Aphrodite making its way to our production codebase (aphrodite is 6kb gzipped) was about 48 hours. Among the top reasons for that was it was easy. I didn’t have to do any rewriting or abandon legacy methods to accommodate this new mode of styling.

new feature -> npm i -S aphrodite -> import -> profit

A Couple Tradeoffs To Note:

1. CSS selectors seem pretty handy sometimes.

2. Styling by tagname or with things like “*” not supported

Can’t do this with Aphrodite

Current Approach With ITCSS and Aphrodite

I believe we ask the wrong question when we are asking which technology to use for styling our applications. Often the debate is framed as CSS vs. CSS Modules vs. inline-styles vs. components vs Aphrodite. I believe a better question is which technology is best suited for the layer of the application I’m trying to style?

What’s ITCSS doing here?

You may recall that I said ITCSS was designed to address shortcomings in CSS the language. So if those problems are no longer issues by primarily using JS instead why are we using ITCSS? ITCSS transcends quite nicely into CSS-in-JS oriented styling for two reasons:

  1. ITCSS helps answer for us which technology is best suited for the layer of the application we’re trying to style. Instead of thinking in terms of technology, ITCSS helps us think in terms of styling layers. We’ll see that the candidates shine differently in different parts the “inverted triangle.”
  2. ITCSS was also designed with developers in mind. Of the methodology goals mentioned earlier, ITCSS still helps us to:
  • Create a sane environment that is accessible to lots of people
  • Create a place for everything to live (new and old)
  • Reduce waste and redundancy

Overview

Current implementation details

  • ITCSS: Organization / Architecture
  • Aphrodite: 99% of view / component styling
  • CSSNext + CSSModules: Global / Reset / Escape-hatch styling
  • React: Encapsulate reusable styles via components
  • Tooling — Webpack, Babel, postcss

Customized “Inverted Triangle”

If you compare my “IT” with the standard one you’ll notice `Tools` got moved below `Generic` and `Elements` for reasons I explain in that section.

One thing to note is that the ITCSS methodology is a flexible one that can be suited to your preferences. A particular “default” layer doesn’t work for you? Move it around or throw it out. Your particular product requires a lot of theming? Add a `Themes` layer where it makes sense. Think a layer’s name sucks? Change it.

Assumed File Structure

For a frame of reference we will assume this feature-centric project organization approach and the following folder structure.

The example code snippets will include the absolute path in which I would place them within this folder structure.

Settings

  • Globally-available settings.
  • Config switches.
  • Brand colors, etc.

Here is where I place values I want to remain consistent throughout an application. Instead of thinking in hex values, pixel units, and media query syntax, I can think in descriptive variable names. `Settings` is my single location control panel for making application-wide changes.

`Settings` in JavaScript:

Using settings: App/components/SomeComponent

`Settings` in CSS:

A note about using `settings` in CSS:

Maintaining two separate settings files, one for JS (`settings.js`) and one for CSS (`settings.css`), runs counter to one of the virtues of the concept of settings: having a single source of truth. You now have two files that easily can get out of sync without discipline. This pain point can be solved by investing some time into a `post-css` plugin that allow the CSS to pull its variables from the JS settings file.

Generic

  • Ground zero styles
  • Low-specificity, far-reaching, app-wide
  • Resets, Normalize.css, etc.

I use `generic` styling primarily for CSS resets and cross-browser style normalization. CSS is our starting quarterback here not only because it’s perfectly suited to do far-reaching styles, but also because it’s our only quarterback. These styles are applied via tagnames and pseudo-elements whose targeting is not supported by Aphrodite.

App/style/css/generic

I let smarter humans do the thinking on this and borrow most of these. I carry nearly the same `generic` styling over to every project.

Elements

  • HTML Elements.
  • H1-H6, basic links, lists, etc.
  • More opinionated / “stylistic” than `generic`.
  • Last layer we see type selectors (e.g. a {}, blockquote {}).
  • Use CSS or React depending on case.

The difference between `elements` and `generic` for me is that `elements` styling is more stylistically opinionated. While I would generally carry `generic` styling over from project to project, I would refrain from doing that with most `elements`styling. The other thing to note here is whether or not to use CSS or JS to apply `elements` style is in a bit of a grey area for me.

App/styles/css/elements
App/shared/el.Btn

^ Why not just use CSS?

button {
border: none;
outline: none;
}

You could but…

  • The relationship is implicit
  • May be too far-reaching / powerful: Effects every button including 3rd party

Those are a couple of the tradeoffs I weigh when deciding how to apply `elements` style.

Applying Generic and Element Styles

App/style/css/index.css
App/index.js

With a webpack (or any other module bundler really) setup, simply importing the CSS file to a top level component file will cause the CSS to be bundled into a single stylesheet for you to include in your index.html.

Tools

  • Globally-available helper functions

`Tools` is a layer where I really ask myself why styling with JS hasn’t been a thing long before now. CSS (SASS, et al) is not the place to be writing logic. This is why I moved `tools` down from the default “inverted triangle” to below where any CSS should be used. If you’re requiring logic of your CSS you’re gonna have a bad time in my experience. For example, the following codepen illustrates an instance where JS based styling tools would have saved me significant time and CSS bloat.

My CSS Bulbasaur (hover over him!) would have greatly benefited from JS based tooling. Inspired by Species In Pieces by Bryan James.

Granted, my real job doesn’t require many CSS Pokemon from me, so much of the time I can get by with simple styling `tools` that feel much better in JS land.

App/style/tools

Objects

  • OOCSS.
  • Design patterns.
  • Layout.
  • No cosmetics.
  • Agnostically named (e.g. list, block, media).

I find that when I’m styling new features I have two distinct mindsets:

  1. Ok let’s get the layout / UI structure to spec.
  2. Ok let’s get the cosmetics (color, font-size, border, transition, pointer, etc.) up to spec.

After taking note of that enough times, I’ve come to believe structural styling and cosmetic styling are two different beasts. You do structural styling long enough and you’ll notice that they tend to fall into common patterns. This observation is kind of what led to the birth of OOCSS. The famous case study is how The Media Object Save[d] Hundreds Of Lines Of Code at Facebook. You can read the case study for more details (it’s short), but the basic idea is that you can extract the styling for rendering an image to the left of an undefined length of content to be reused.

Let’s see how we could use a Media `object` component to help us to render this `PokemonListing` component.

Components

  • Designed pieces of UI
  • Aphrodite’s bread & butter

The `components` layer is the one layer that will be truly unique across applications and is where I spend the majority of my styling time. Many of these other layers can potentially be `git cloned`when starting a new project or `npm installed` on demand, but the burden of a component’s existence will largely remain on you. Aphrodite is almost my exclusive go-to when styling components.

I also like to classify my components using Brad Frost’s Atomic Design which borrows from chemistry to describe an interface’s ability to be broken down into fundamental building blocks. `Button,` and `Input` atoms bond together to form a `Search` molecule. Pair that `Search` molecule with a `NavBar` molecule and we got ourselves a `Header` organism. Keep this organism thing up and we got a view.

Atomic Design
App/shared/atm.Btn
App/shared/mol.Search

The further classification helps my team and I to take time to think more critically about the design of our components and ask: “How does this fit into the larger design system? Can this feature be broken down further into reusable atomic parts?”

Some of you may find the further classification of components to be overkill and to you I say right on 👍. Do what feels right to you and works for you and your team.

Trumps

  • Helpers, utilities
  • Component lego blocks
  • Styling applied to singular elements

The `Trumps`layer may be better renamed to something along the lines of `Utility Atom` because it no longer is required to serve the purpose it use to. You see, the name was appropriate before because a `trump` style used fear and bullying via `!important` to apply the style it wanted with egotistical inconsideration of the lower-specificity styles’ wishes.

Specificity Wars are no longer a thing with CSS-in-JS so the need to “Trump” or override styles is also no longer a thing.

What is nifty from the example above though is the ability quickly and conveniently use `pt` to apply top padding. The `Trumps` layer is one of my favorites for this reason. Let’s see how we can apply this principle with with CSS-in-JS using the Search molecule example from the `components` section.

This layer is where `inline-styles` really shine as seen in a naive implementation of `react-txt`:

App/shared/atm.Txt

Conclusion

Suggestions or feedback?

The original motivation of this post was for it to serve as a living document to onboard new developers to our approach to application styling. While the scope creeped a bit, I intend it to remain a living document that incorporates new learnings and progression. I fully expect much of that learning to come from you. Leave a comment or hit me up on the twitters.

Know someone this could help?

I hope my learning journey will provide value to yours and stimulate ideas for how to up your styling game. If you found this helpful, using your influence to pass it on will be appreciated by more than just myself! Leave a recommend, share on Slack, or share on Twitter.

Show your support

Clapping shows how much you appreciated Mikey Murphy’s story.