Neko Neko2
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

  • Easy to set up and use.
  • Immutable styles that speak for themselves (by good naming convention).

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

  • Easy to use.
  • Stylesheets generated during the build process are fully optimized with no unused styles.
  • Much more flexible & spontaneous (… just like inline style).

Purposes

Atomic CSS keeps things simple

  • Classes are immutable. They only do one thing.
  • Naming is straight forward. It’s easy to tell what a class does at a glance.
  • Using a utility class in an HTML file is unambiguous - we know what we are changing, without concern of breaking something, somewhere else.
  • Easy to pick-up without diving too deep into actual stylesheets.

Atomic CSS keeps things consistent

  • Unit-based so styles are consistent & scalable. Let’s look into how Tailwind setup their default styles again:
    • m-4 -> margin: 1rem, m-8 -> margin: 2rem -> 1 unit ~ 0.25rem. With this, when we see m-40, we can easily deduce that it’s 10rem.
  • Designs that follow an atomic system will be easier for developers to implement.
    • An offset of 1 or 2 pixels while dragging components around in Figma might be neglectible, but applying those styles to the app will bloat it with “magic numbers” that feel random & irrelevant.
    • With designers & developers agreeing on a common styling system, developers still know what they have to use when encountering “magic numbers” in the design. They can see a padding: 63px and know the designers actually meant padding: 64px (divisible by 4).

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:

  • If you need to change a lot of styles for a particular component inside of a media query.
  • If you want to change multiple styles conditionally during run-time, based on a component’s state.

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


Mentioned in

No mentions found

Unable to load mentions

Subscribe to Dwarves Memo

Receive the latest updates directly to your inbox.

An Introduction to Atomic CSS
mashiro5951
Mint this entry as an NFT to add it to your collection.
Loading...