first

There’s a CSS scheme out there called Atomic CSS, if you’ve ever used it; Some people find it absurd and fall back into their BEM style.

Some people will love it.

I am the latter.

An extreme, complex Atomic CSS would look something like this:

<button class=" px-lg py-sm radius-sm m-md pc:m-lg bg-blue-600 hover:bg-blue-500 active:bg-blue-400 shadow hover:shadow-lg transform hover:move-y--px active:move-y-px c-white cursor-pointer transition-500"
>
  Touch Me
</button>
Copy the code

I believe that the normal front-end friends see this chunk of class, will be very headache, and at first glance it is no different from the book, immediately replaced by the following code:

<button class="im-a-button">Touch Me</button>
Copy the code

It’s so simple. It’s so much better.

But that doesn’t solve the problem completely, because we still need to add the following CSS code to make it equivalent to the headache:

/* First we need to design a unit specification and color specification for our project */
:root {
    --px: 1px;
    --sm: 2px;
    --md: 8px;
    --lg: 16px;
    --blue-600: #6677ff;
    --blue-500: #4455ff;
    --blue-400: #3355ee;
    --shadow-color: # 000000;
    --shadow-opacity: 0.15;
    --white: #fff;
    --ease: cubic-bezier(0.23.1.0.32.1);
}

.im-a-button {
    /* All units use CSS-values to better unify the overall style and size, and to make it easier to adjust the style of the entire project */
    padding: var(--sm) var(--lg) var(--sm) var(--lg);
    border-radius: var(--sm);
    margin: var(--md);
    background: var(--blue-600);
    box-shadow: 0 1px 3px 0 rgba(var(--shadow-color), var(--shadow-opacity)), 0 1px 2px 0 rgba(var(--shadow-color), calc(var(--shadow-opacity) / 2));
    /* White also uses CSS values to better do dark mode */
    color: var(--white);
    transition: all 500ms var(--ease);
    will-change: transform;
}

@media (min-width: 640px) {
    .im-a-button {
        margin: var(--lg);
    }
    
    /* Hover on mobile will cause the hover style to not be released after the touch response. For better experience, it is recommended to hover only on desktop
    .im-a-button:hover {
        background: var(--blue-500);
        box-shadow: 0 10px 15px -3px rgba(var(--shadow-color), var(--shadow-opacity)), 0 4px 6px -2px rgba(var(--shadow-color), calc(var(--shadow-opacity) / 2));
        tramsform: translateY(calc(0px - var(--px)));
        margin: var(--2xl); }}.im-a-button:active {
    background: var(--blue-400);
    box-shadow: 0 10px 15px -3px rgba(var(--shadow-color), var(--shadow-opacity)), 0 4px 6px -2px rgba(var(--shadow-color), calc(var(--shadow-opacity) / 2));
    tramsform: translateY(var(--px));
}  

Copy the code

When we look at this CSS code block, we come back to our real scenario:

  • The amount of CSS code increases linearly, so not only do we have to write a lot of CSS code, we also need to unpack the CSS of the project to improve the load time of the first screen
  • CSS is designed and regulated up front, and requires some training/education for each participant
  • Reading large chunks of CSS is not a great experience, and a single element CSS style containing media queries, pseudo-classes, and animations can’t even be displayed on a single screen
  • CSS values are great, but if they are used throughout the project, it will affect the overall CSS reading experience and CSS file size
  • Writing CSS requires a lot of names, more variable names than our entire project, and in order to reduce CSS contamination, we also need to introduce CSS-Modules or BEM, which adds further mental burden

Now let’s revisit this piece of Atomic CSS style code:

<button class=" px-lg py-sm radius-sm m-md pc:m-lg bg-blue-600 hover:bg-blue-500 active:bg-blue-400 shadow hover:shadow-lg transform hover:move-y--px active:move-y-px c-white cursor-pointer transition-500"
>
  Touch Me
</button>
Copy the code

We can see that the reading experience of Atomic CSS is pretty good (50 steps are worth 100 steps), and we can probably guess what most of the above classes mean by now.

So if we have a very well-regulated, well-designed style library with logical Atomic CSS style, we can write our interfaces very efficiently and solve the common problems we just mentioned.

This is why the author fell in love with the Atomic CSS style. A good set of Atomic CSS is the VIM of CSS.

happy

  • With theAtomic CSSAfter that, we don’t have to worry about a bunch of BEM names anymore
  • We can use very short, descriptive classes to describe our UI directly, which is a big improvement in the efficiency of drawing interfaces.
  • We can easily modify the style of the entire project
  • All that remains of our project are Javascript/Typescript files
  • Because of the uniform specification, we can even directly copy other projectsAtomic CSSIn the style ofclassName

pain

The most popular Atomic CSS on the market is the Tailwind CSS.

If you do a search on Nuggets, YouTube, there are a lot of supporters, and I’m one of them.

But as we use it for a long time, we gradually discover a core pain point: how can we determine the boundary of the number of atomic classes?

Atomic CSS is essentially a set of predefined CSS styles, but how many styles can be predefined enough that you don’t need to write 95% of your regular CSS code? This basically enumerates the possible combinations that we can use, even though the specification limits require about 2.5MB of CSS code, even though 99% of the Atomic CSS will never be used, and this code is so large that it is impossible to use this kind of solution directly.

A solution to this problem is to use Purgecss to clean up unused CSS, which allows us to rematch our business code at compile time, keeping only the Atomic CSS we used, and only using about 10-50KB of CSS code.

This comes at a cost. We need to pay attention to the way classes are written. If we use variables to create classnames dynamically, Purgecss will not be able to find the CSS we used at compile time through the re.

And because usually we don’t fit in the development environment to do this action, or we each make a more write a component have to compile a can see effect, but if we only do this action during the compilation of production code is risky, if there is a regular not matching to the object, may lead to unpredictable production bugs, such as a module cannot be present.

Flavorcss, however, avoids the problem of how to determine the boundary of the number of Atomic classes. Flavorcss compiles most of the Atomic classes step by step at runtime, and the whole compilation and insertion process is segmented so that users do not feel.

Flavorcss is zero-configuration out of the box, we just need to introduce:

<script src="https://unpkg.com/[email protected]/umd/index.js"></script>
Copy the code

Or:

yarn add flavorcss
Copy the code
import 'flavorcss'
Copy the code

Flavorcss dynamically creates Atomic CSS during page rendering.

pause

As for other issues, Tailwind CSS author has written a thinking post on the Atomic CSS style.

Adamwathan. Me/CSS – the utility…

Let me briefly answer some of the more common questions

  • Why don’t we just write inline styles?
    • Media queries and pseudo-classes cannot be written directly because of the inline style
  • How does CSS-in-JS compare to this scheme?
    • Css-in-js does not help us design the size and color specifications by default, nor does it significantly reduce the total amount of code, migrating CSS to JS in order to provide more control. Their purposes are different.
  • How the performance
    • Reduces the overhead of loading a lot of CSS for the first time and increases the overhead of dynamically adding atomic classes at runtime
    • There is no perceived overhead for adding atomic classes at runtime, and the experience can be found on the website.

Flavorcss

The following is the official documentation for Flavorcss, which has all the style descriptions and can be dynamically edited to make it easier to understand all the specifications. Flavorcss promises that the existing API will not change.

flavor.writeflowy.com/