Today I want to tell you about my open source project: mlut. This is an Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity.
Table of Contents
-
Main features
- π Strong naming convention
- π¨ Almost arbitrary by design
- β Great ergonomics
- π¨ Easiest utils generation
- 𧩠Handy extension
- π And something else...
- How I came to it
- Weak parts and plans
- Wrap up
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, onlybackground-image
β Tachyons:
-
.br-0
=>border-right-width: 0
, but.br1
=>border-radius:.125rem
-
.normal
: line-height, font-weight or letter-spacing? -
.b
: bottom, border ordisplay: block
? Nope, it isfont-weight:bold
!
β mlut:
-
.Jc-c
=>justify-content: center
,.Js-c
=>justify-self: center
-
.Bdr
=>border-right: 1px solid
,.Bdrd1
=>border-radius: 1px
One algorithm for all. If you know CSS, you almost know mlut.
Almost arbitrary by design
-
values:
.Ml-1/7
=>margin-left: -14.3%
-
states:
Bgc-red200_h,f
=>.Bgc-red200_h\,f:hover, .Bgc-red200_h\,f:focus {...}
-
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:
<!-- 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.
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
@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
@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
@use 'mlut' with (
$utils: (
'Paddings': (150),
)
);
// result CSS
.P150 {
padding: 150px;
}
.Pt150 {
padding-top: 150px;
}
.Pr150 {
padding-right: 150px;
}
// etc.
Top-level apply
@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
@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 or for one utility.
How I came to it
Now, I'll tell you a little story.
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
- no CLI - planned first thing
- no JIT-mode - also planned. The backend for it is already implemented as a top-level apply
- 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. 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. Also, you can share this tread on Twitter. All this will help a lot to promote the project!
Top comments (5)
Really great work Valik, although, i have a few thoughts floating through my mind right now, and I'd be honest, the first question is "what does mlut mean"?π like is it an abbreviation for something, if not, what made you name it that? Basic curiosity here. Second, I don't know, the project is great and all, but it just feels like an overly complicated abbreviation of the CSS properties and values, and i feel like using it for a large project might get very dreadful. As the code doesn't seem to be quite self explanatory when using it, making the whole code look so much like congested gibberish, like taking a look at this piece of mlut code you provided:
This would probably be like a nightmare when implemented on 200 lines of code or more. I love the idea of abbreviations and all, but I think this is a little too vague at first glance, and would require quite a few brain cells to decode, wasting the developers time even moreπ€·ββοΈ. I would have suggested not making everysingle thing abbreviated and still keep some words for better understanding, but then it would just be like tailwind.
Thanks for the feedback! mlut is short for My Little UI Toolkit) And about the abbreviated classes I answered below, see previous comments
Reading this article on mlut, I find it much easier to read tailwindcss classes than the acronymized classes in mlut / tachyons. Unless the autocomplete/ intellisense is very strong so that when I type say 'justify-content', there's also autocomplete for 'Jc-c', I think the mental hurdle makes this css framework unviable for dev teams.
Thanks for the feedback! Yes, abbreviated classes have a threshold and not everyone will like them. But if you know them, they become very pleasant and convenient to work with! And learning them is much easier than you think, because they are all made according to a clear algorithm. Knowing the algorithm and the CSS property, you can easily compose the name of the class in your head, without having to learn it by heart!
I gotta agree with Estee.
I mean, this is a beautiful approach, if you're Wolverine. Not so much if you're Cyclops and you need to see for your whole team. That's pretty much the reason why Tailwind has stuck with devs in the late years.