@leafac/css

Radically Straightforward CSS

Usage no npm install needed!

<script type="module">
  import leafacCss from 'https://cdn.skypack.dev/@leafac/css';
</script>

README

This documentation is a work-in-progress. The library itself is ready for consumption for early adopters.

@leafac/css

Radically Straightforward CSS

Source Package Continuous Integration

Support

Installation

$ npm install @leafac/css

Example

import html from "@leafac/html";
import { css, extractInlineStyles } from ".";

console.log(
  extractInlineStyles(html`
    <!DOCTYPE html>
    <html lang="en">
      <head></head>
      <body>
        <p
          style="${css`
            background-color: var(--color--red--500);
            &:hover {
              background-color: var(--color--red--300);
            }

            @media (max-width: 599px) {
              margin: 1rem;
            }
          `}"
        >
          Leandro Facchinetti
        </p>
      </body>
    </html>
  `)
);

Produces:

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      /* ... A PREAMBLE WITH A CSS RESET, A DESIGN SYSTEM, AND SO FORTH ... */

      /* INLINE STYLES */

      .style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw {
        background-color: var(--color--red--500);
      }

      .style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw:hover {
        background-color: var(--color--red--300);
      }

      @media (max-width: 599px) {
        .style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw.style--1s69iw {
          margin: 1rem;
        }
      }
    </style>
  </head>
  <body>
    <p class="style--1s69iw">Leandro Facchinetti</p>
  </body>
</html>
What’s up with the Repeated Selectors?

It’s a hack to give the selector a specificity high enough that it won’t be overwritten by most other styles.

What’s [@leafac/html](https://npm.im/@leafac/html)?

That’s my other package for Radically Straightforward HTML, which is just HTML templates embedded in JavaScript using tagged template literals.

What’s in the Box? (Why I Love Tailwind Css; Why I Have Never Actually Used It; And How I’m Proposing to Replace It with 10 Lines of Code.)

A Radically Straightforward Approach to CSS

In the beginning, styles lived inline in the HTML. That was good because it was the simplest thing that could work, but it had its limitations: design inconsistencies, verbosity, and so forth.

We solved this by pulling styles into a stylesheet and connecting them to the HTML via selectors, classes, ids, and so forth. That was good because it led to more consistent designs, relatively less code, and some reusable components, for example, those in the most popular components library, Bootstrap. But it had its limitations: the HTML and its corresponding styles were far away, which can make things more difficult to understand and modify; and you often had to spend time being creative to come up with class names that didn’t describe much of anything, and existed only to connect the HTML to its corresponding styles.

People have come to realize that both approaches have their place. We start with a global stylesheet including things like fonts, colors, sizes, and so forth; and we complete the job with inline styles. We avoid extracting things into reusable components until they really do need to be reused in other places.

This is the driving principle behind the popularity of tools like Tailwind CSS. Unlike Bootstrap, Tailwind isn’t a collection of components—it’s a framework at a lower level. It’s closer to an approach for how to reason about styles. I love how straightforward, productive, and scalable this approach feels. And I’m not alone. But Tailwind has its limitations.

Why Not Use Tailwind CSS?

Because it’s a new language to learn. The good-old width: 8rem turns into m-32; and text-align: center turns into text-center; and so forth. While it’s true that you can become proficient in this new language relatively quickly, you still have to keep translating things in your head the entire time you’re using Tailwind. Every time you read CSS documentation, or a tutorial showing how to do something, you have to translate.

Because the Tailwind CSS build system is weird. For the longest time Tailwind worked by producing every single utility class you could possibly want to use; then pruning everything you didn’t end up using, which is most things. This feels backwards, and it isn’t super-fast either. In the most recent releases Tailwind introduced a just-in-time compiler that alleviates some of these concerns. Both the pruning and the just-in-time compiler work by inspecting your HTML to detect which utility classes you used.

But What to Use Instead of Tailwind? Inline Styles with Modest Superpowers

The Tailwind approach is similar in spirit to inline styles, but it improves upon inline styles in the following ways:

Designing with constraints: Using a design system is an awesome idea and improved my game as a developer venturing into design more than anything else I’ve ever tried. But we could have the design system as any kind of sets of variables, most notably CSS custom properties (variables), but Sass variables or anything else would also work.

Responsive design; hover, focus, and other states: That’s when the modest superpowers of inline styles come in. While it’s true that inline styles can’t have media queries or :hover, :focus, and so forth, what if instead of introducing a new language of class names like md:... and hover:..., we just preprocessed the inline styles to give them these abilities? It’s easy with nesting:

<body>
  <p
    style="
      background-color: red;

      @media (max-width: 599px) {
        margin: 1rem;
      }

      &:hover {
        background-color: blue;
      }
    "
  >
    Leandro Facchinetti
  </p>
</body>

Becomes:

<head>
  <style>
    .style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2 {
      background-color: red;
    }

    @media (max-width: 599px) {
      .style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2 {
        margin: 1rem;
      }
    }

    .style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2.style--zvyll2:hover {
      background-color: blue;
    }
  </style>
</head>
<body>
  <p class="style--zvyll2">Leandro Facchinetti</p>
</body>

BOOM: The first time you read this you already understood it. Nesting is super-natural at this point to most people writing CSS. It’s supported by all pre-processors and it’s on track to become a standard in CSS.

@leafac/css is a preprocessor that does exactly this. But more importantly, @leafac/css is an architectural statement that this is how we should be writing our styles.