Dwarves
Memo
Type ESC to close search bar

An Introduction to Atomic CSS

Definition

A definition to Atomic CSS:

Atomic CSS is the approach to CSS architecture that favors small, single-purpose classes with names based on visual function.

Some might also call it Functional CSS, or CSS utilities. Basically, you can say an Atomic CSS framework is a collection of the CSS like these:

.m-0 {
  margin: 0;
}

.text-red {
  color: red;
}

We have quite a few utilities-first CSS framework like Tailwind CSSWindi CSS and Tachyons, etc. And there are also some UI libraries that come with some CSS utilities as the complement to the framework, for example Bootstrap and Chakra UI.

Variations

Static

Similar to how we write normal CSS, we define a unit-based design system for spacing, color, typography, etc. Take a look at these default utility classes from Tailwind:

# 1 unit ~ 0.25rem .m-4 {
  margin: 1rem;
}

.m-8 {
  margin: 2rem;
}

Advantages

Programmatic

This style involves using a build tool to automatically generate styles based on what it finds in the HTML.

For example, given this:

<div class="Bgc(#0280ae) C(#fff) P(20px)">Lorem ipsum</div>

The following CSS would be generated:

.Bgc\(#0280ae\) {
  background-color: #0280ae;
}
.C\(#fff\) {
  color: #fff;
}
.P\(20px\) {
  padding: 20px;
}

Another example would be Tailwind’s JIT mode:

<div className="bg-[#FFF] font-[24px]">...</div>

Advantages

Purposes

Atomic CSS keeps things simple

Atomic CSS keeps things consistent

Atomic CSS is not inline styles

Inline styles have long been deemed a bad practice, and many people dislike Atomic CSS because they think it shares the same suffer with inline styles.

Here’s an example:

What if we want to change everything with a .black class to be navy instead?

An easy solution would be finding all instances of .black with our Text Editor and replace them manually. However, it’s a tedious deed, and exactly what is frowned upon by the community. People value reusability.

But we do have reusability with Atomic CSS (along with many other things).

Reusability

Reusability of Atomic CSS comes from the way we use them. With libraries such as React, it’s easy to define a reusable component, with all the styles bundled inside. Now changing the color of a widely-used button is a one-line operation:

export const CommonButton = () => {
  return (
    <button type="button" className="bg-primary">
      Button
    </button>
  )
}

Combining with suitable tools, we can make it even more flexibile:

import { css } from '@linaria/core'

const reusableButtonClassName = css`
  @apply p-2 rounded bg-white font-base border-secondary;
  line-height: 1;

  @screen md {
    @apply font-xl;
  }
`

const reusableActiveButtonClassName = css`
  @apply border-primary;
`

export const CommonButton = ({ isActive }) => {
  return (
    <button type="button" className={['reusableButtonClassName', isActive && 'reusableActiveButtonClassName']}>
      Button
    </button>
  )
}

As you can see, we are utilizing the strength of both Atomic CSS and css-in-js.

Abstraction

With atomic classes, it is possible to create abstractions that would be impossible with inline styles.

<p style="font-family: helvetica; color: rgb(20, 20, 20)">Inline styles suck.</p>
<p class="helvetica rgb202020">Badly written CSS isn't very different.</p>
<p class="sans-serif color-dark">Utility classes allow for abstraction.</p>

The first two examples shown above would require a manual find-and-replace in order to update styling were the design to change. The styles in the third example can be adjusted in a single place within a stylesheet.

Tooling

Sass, Less, PostCSS, Autoprefixer… The CSS community has created a lot of useful tools that weren’t available for inline styles.

Brevity

Rather than writing out verbose inline styles, atomic classes can be terse abbreviations of declarations. It’s less typing: mt-0 vs margin-top: 0flex vs display: flex, etc.

Specificity

Inline styles have the 2nd highest level of specificity (only less than !important) .The lower specificity of atomic classes compared to inline styles is a good thing. It allows more versatility.

Possibilities

Utility classes can do things inline styles can’t.

Inline styles do not support media queries, pseudo selectors, @supports, or CSS animations. Perhaps you have a single hover effect you want to apply to disparate elements rather than to only one component.

.circle {
  border-radius: 50%;
}

.hover-radius-0:hover {
  border-radius: 0;
}

Simple reusable media query rules can also be turned into a utility class. Its common to use a classname prefix for small, medium and large screen sizes. Here is an example of a flexbox class that will only apply on medium and large screen sizes:

@media (min-width: 600px) {
  .md-flex {
    display: flex;
  }
}

Atomic CSS is not all or nothing

There’s no doubt CSS utilities can cover a lot of common use-cases, but it’s not all we need. There are plenty of cases where utility classes aren’t the best option:

Refer back to this section for a sample scenario. Utility classes can coexist with other approaches. It’s just a good idea to define base styles and sane defaults globally.

References