mlut - a new word in the Utility-First CSS approach
Tags: css, tailwindcss, webdev, showdev
Published: 2023-07-02 18:54:16

Today I want to tell you about my open source project: [mlut](https://github.com/mr150/mlut). This is an Atomic CSS toolkit with [Sass](https://sass-lang.com/) and ergonomics for creating styles of any complexity.

## Table of Contents
- [Main features](#main-features)
  * 🔠 [Strong naming convention](#strong-naming-convention)
  * 🎨 [Almost arbitrary by design](#almost-arbitrary-by-design)
  * ✋ [Great ergonomics](#great-ergonomics)
  * 🔨 [Easiest utils generation](#easiest-utils-generation)
  * 🧩 [Handy extension](#handy-extension)
  * 👀 [And something else...](#and-something-else)
- [How I came to it](#how-i-came-to-it)
- [Weak parts and plans](#weak-parts-and-plans)
- [Wrap up](#wrap-up)

![GIF animation with usage example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/slytb8vecnhhentzyaeq.gif)

## Main features

### Strong naming convention
❌ **Tailwindcss**:
- `.justify-*`: content, items or self?
- `.flex` => `display: flex`, but `.flex-auto` => `flex: 1 1 auto;`
- `.bg-none` - reset all background? Nope, only `background-image`

❌ **Tachyons**:
- `.br-0` => `border-right-width: 0`, but `.br1` => `border-radius:.125rem`
- `.normal`: line-height, font-weight or letter-spacing?
- `.b`: bottom, border or `display: block`? Nope, it is `font-weight:bold`!

✅ **mlut**:
- `.Jc-c` => `justify-content: center`, `.Js-c` => `justify-self: center`
- `.Bdr` => `border-right: 1px solid`, `.Bdrd1` => `border-radius: 1px`

[One algorithm](https://mr150.github.io/mlut/section-concepts.html#kssref-concepts-naming) for all. If you know CSS, you almost know mlut.

### Almost arbitrary by design
- [values](https://mr150.github.io/mlut/section-concepts.html#kssref-concepts-values): `.Ml-1/7` => `margin-left: -14.3%`
- [states](https://mr150.github.io/mlut/section-concepts.html#kssref-concepts-states): `Bgc-red200_h,f` => `.Bgc-red200_h\,f:hover, .Bgc-red200_h\,f:focus {...}`
- [at-rules](https://mr150.github.io/mlut/section-concepts.html#kssref-concepts-at_rules): `@:p-c,w>=80r_D-f` => `@media (pointer: coarse), (min-width: 90rem) {...}`

You no need to special arbitrary syntax.

### Great ergonomics
Shorter class names:
```html
<!-- Example from https://www.shopify.com/ -->

<!-- Tailwindcss -->
<div class="hidden md:block md:col-span-6 md:col-start-7 lg:col-span-5 lg:col-start-8 pb-6 relative md:max-h-[130vh] reduced-motion:translate-y-0 will-change-transform duration-1000 ease-in-out transition-all reduced-motion:opacity-100">...</div>

<!-- mlut -->
<div class="D-n md_D md_Gc-s1 md_Gcs7 lg_Gc-s5 lg_Gcs8 Pb6u Ps md_Mxh130vh Tf @:pfrm_-Try0 Wlc-tf Tsd1s Tstf-eio Ts-all @:pfrm_O1">...</div>
```
Convenient syntax for complex values, states and at-rules.<br> It is like Vim for CSS.
#### ❌ Tailwindcss:
- `[@media(any-hover:hover){&:hover}]:opacity-100`
- `text-[color:var(--my-var,#333)]`
- `supports-[margin:1svw]:ml-[1svw]`

#### ✅ mlut:
- `@:ah_O1_h` => `@media (any-hover){ .\@\:ah_O1_h:hover{ opacity: 1 }}`
- `C-$myVar?#333` => `color: var(--ml-myVar, #333)`
- `@s_Ml1svw` => `@supports (margin-left: 1svw) { .\@s_Ml1svw { margin-left: 1svw } }`

### Easiest utils generation

JIT mode planned but here is what we have now:

#### Range [syntaxes](https://mr150.github.io/mlut/section-how_to.html#kssref-how_to-mk_utils-range)

```scss
@use 'mlut' with (
  $utils: (
    'Bdw': ([2u, 4],),
  )
);

// result CSS
.Bdw2u {
  border-width: 0.5rem;
}

.Bdw3u {
  border-width: 0.75rem;
}

.Bdw4u {
  border-width: 1rem;
}
```

#### Components syntax

```scss
@use 'mlut' with (
  $utils: (
    'D': ('xl _ib_ b af'),
  )
);

// result CSS
.D-ib {
  display: inline-block;
}

.D-ib_b::before {
  display: inline-block;
}

.D-ib_af::after {
  display: inline-block;
}

@media (min-width: 1200px) {
  .xl_D-ib {
    display: inline-block;
  }
}
```

#### Groups

```scss
@use 'mlut' with (
  $utils: (
    'Paddings': (150),
  )
);

// result CSS
.P150 {
  padding: 150px;
}

.Pt150 {
  padding-top: 150px;
}

.Pr150 {
  padding-right: 150px;
}

// etc.
```

#### Top-level apply

```scss
@include ml.apply(
  '^0:+_-MyPad1.5;3u -Gdl-r,#0f0;30p,#00f;80p,red'
);

// result CSS
.-Ctx0 + .\^0\:\+_-MyPad1\.5\;3u {
  --ml-myPad: 1.5rem 0.75rem;
}

.-Gdl-r\,\#0f0\;30p\,\#00f\;80p\,red {
  background-image: linear-gradient(to right, #0f0 30%, #00f 80%, red);
}
```

### Handy extension
Add utilities, states and custom at-rules with few lines of code
```scss
@use 'mlut' as ml with (
  // add utilities
  $utils-data: (
    'utils': (
      'registry': (
        'Mil': margin-inline,
        'Ir': (
          'properties': image-rendering,
          'keywords': (
            'p': pixelated,
          ),
        ),
      ),
    ),
  ),

  // add states
  $utils-config: (
    'states': (
      'custom': (
        'are': '[aria-expanded=“true”]',
      ),
    ),
  ),
);

@include ml.apply('Mil-15_-are Ir-p');

// result CSS
.Mil-15_-are[aria-expanded=“true”] {
  margin-inline: -15px;
}

.Ir-p {
  image-rendering: pixelated;
}
```

### And something else...
- ⚡️ Written in Sass and includes all its benefits
- 🔧 **Fully customizable**: change tokens, utilities names and any settings
- ✨ **Easy to integrate** in existing project. No name collisions with your CSS in the most projects. Increasing specificity in [one line](https://mr150.github.io/mlut/section-settings.html#kssref-settings-utils-other-up_specificity) or for [one](https://mr150.github.io/mlut/section-concepts.html#kssref-concepts-states-special-tu) utility.

## How I came to it

Now, I'll tell you a little story. <br>
The first developments were back in 2018: I started making it for myself and the team. Tailwind was in its infancy then, and other analogs did not suit me. At some point, I decided to make it a full-fledged open source. Used it myself, sometimes with the team. Had a few releases, but no time to promote it after that.

At one time I surpassed Tailwind in features (and even now we almost on par, without JIT), but alas, I missed my chance to get hype. Maybe the relevance of the project has lost a bit, but I think it's not worth leaving it in the drawer.

And if I overcome the following weaknesses, mlut can fight with the top analogues and in some ways will be better than them!

## Weak parts and plans
1. no CLI - planned first thing
2. no JIT-mode - also planned. The backend for it is already implemented as a top-level apply
3. as a consequence: for the production build, in addition to Sass, 1-2 other packages are recommended

## Wrap up

You can find instructions on how to get started with mlut and other details in the [documentation](https://mr150.github.io/mlut/). Perhaps in the future I will write separate technical articles on working with mlut. Let me know if you would be interested)

Thank you for reading my story! I would be very grateful for any feedback on the project. If you like it, please put a star on the [Github](https://github.com/mr150/mlut). Also, you can share [this](https://twitter.com/mr150_/status/1654194960369963020) tread on Twitter. All this will help a lot to promote the project!