Doro Onome A software developer and technical writer with a passion for open source.

New features in UnoCSS: A Tailwind CSS alternative

4 min read 1390

New Features in UnoCSS: A Tailwind CSS Alternative

UnoCSS is a fully customizable Atomic CSS engine inspired by Windi CSS, Tailwind CSS, and Twind. UnoCSS is not a CSS framework, but it is an engine that you can use to create one. It provides a common superset of the popular utility-first CSS frameworks like Tailwind CSS, Windi CSS, and Bootstrap.

UnoCSS is becoming one of the most talked-about styling tools because of several encouraging features it has introduced to CSS. For example, UnoCSS is flexible, has no core utilities, and its functionalities are made available through several presets.

In this tutorial, we’ll go through some of these new features, learning how to apply them in our application. To follow along with this tutorial, you’ll need the following:

  • A good text editor
  • A sound understanding of CSS and its frameworks

Let’s get started!

Getting started with UnoCSS

To install UnoCSS via Vite, run the command below:

npm i -D unocss

For insight into the other packages you can use to install UnoCSS in your application, check out this GitHub repo.

Then, import UnoCSS with the code below:

// vite.config.ts
import Unocss from 'unocss/vite'
export default {
  plugins: [
    Unocss({ /* options */ })
  ]
}

Finally, add uno.css in your main entry:

// main.ts
import 'uno.css'

Now that we’ve installed UnoCSS, let’s check out the new features it brings to the table, installing each in our demo project.

UnoCSS default and custom presets

With presets, you can create your own custom framework inside of UnoCSS. You can also combine your custom rules and variants into presets to share with others.

@unocss/preset-uno is the default preset. It is a superset of the common utility-first CSS frameworks like Tailwind CSS, WindiCSS, and Bootstrap. The different utilities from these popular frameworks are all legal to use in UnoCSS:

We made a custom demo for .
No really. Click here to check it out.

.ml-3 { margin-left: 0.75rem; } // TailwindCSS
.ms-2 { margin-inline-start: 0.5rem; } // Bootstrap
.mt-10px { margin-top: 10px; } // WindiCSS
.ma4 { margin: 1rem; } // Tachyons

Other presets include:

To set presets in your application, use the code below:

// vite.config.ts
import Unocss from 'unocss/vite'
import { presetUno, presetAttributify } from 'unocss'

export default {
  plugins: [
    Unocss({
      presets: [
        presetAttributify({ /* preset options */}),
        presetUno(),
        // ...custom presets
      ]
    })
  ]
}

If you indicate the preset you want to use, the default preset will be ignored. You can also disable the default preset by setting presets to an empty array:

// vite.config.ts
import Unocss from 'unocss/vite'

export default {
  plugins: [
    Unocss({
      presets: [], // disable default preset
      rules: [
        // your custom rules
      ]
    })
  ]
} 

Users now control CSS Scoping

UnoCSS allows users to control CSS resetting, adjusting the framework they use on top of UnoCSS to fit their requirements and opening up the possibility of CSS scoping.

For instance, there is a scoped-vue mode on the Vite Plugin, which generates scoped styles for individual components. You can now successfully move the scoped styles as a component library without clashing with the user’s CSS. See the representation below:

<template>
  <div class="m-2 rounded"><slot></div>
<template>
<!-- the following will be inject in the bundler -->
<style scoped>
.m-2{margin:0.5rem;}
.rounded{border-radius:0.25rem;}
</style>  

UnoCSS is fully customizable

Unlike other utility-based CSS frameworks, UnoCSS is fully customizable in any application. It takes preset logic from other frameworks like Tailwind CSS, but designers can alter specific attributes in the preset code.

Let’s say that when styling your application, you want to add an element margin of 0.25 rem. Instead of writing the traditional margin: 0.25rem, you can represent it with m-1:

rules: [
  ['m-1', { margin: '0.25rem' }]
]

Now, if you want to give any element on your web page a margin of 25 px, you can just use m-1.

UnoCSS Attributify Mode

The Attribufy Mode is an amazing new feature in UnoCSS that allows you to organize and group your utilities with attributes or classes. It keeps the regular Tailwind CSS syntax but enables you to use Tailwind CSS utilities with classes and attributes. Say you’re styling a button on your webpage with utilities from Tailwind CSS:

<button id="start-btn" class="bg-pink-700 px-9 py-3 text-white text-2xl rounded-lg hover:bg-pink-400">Start</button>

The code for the button can become lengthy, making it difficult to keep up with. However, UnoCSS Attributify Mode lets you easily convert these utilities to attributes:

<button 
id="start-btn" 
bg="pink-700 hover:pink-400"
p="x-9 y-3"
text="white 2xl"
border="rounded-lg"
>
Start
</button>
```
UnoCSS also provides support for attributes that do not have a particular value. For instance, you can now express 
```
<div class="flex justify-center gap-4" />
```
as:
```
<div flex justify-center gap-4 />

Using Attributify Mode in this manner paves the way for cleaner, more organized code.

UnoCSS uses pure CSS icons

UnoCSS uses icons made completely for CSS instead of JavaScript, making it much easier to use icons in your application. Install the UnoCSS icons preset from Iconify with the command below:

npm i -D unocss @unocss/preset-icons @iconify/json

After installing this preset, you’ll find a folder called @iconify/json, which is the folder that saves the icon data from Iconify. You can import it in your vite.config.js as follows:

import { defineConfig } from 'vite'
import Unocss from 'unocss'
import UnocssIcons from '@unocss/preset-icons'
export default defineConfig({
  plugins: [
    Unocss({
      // when `presets` is specified, the default preset will be disabled
      // so you could only use the pure CSS icons in addition to your
      // existing app without polluting other CSS 
      presets: [
        UnocssIcons({
          // options
          prefix: 'i-',
          extraProperties: {
            display: 'inline-block'
          }
        }),
        // presetUno() - if you want to use other atomic CSS as well
      ],
    }),
  ],
})

You can also install individual icon sets. For instance, you can install @iconify-json/carbon for Carbon icons or @iconify-json/mdi for Material Design Icons.

UnoCSS uses custom variants

Variants allow you to specify when a utility should be activated, for example, you can use the screen size, the system theme, or any pseudo-selector like :checked or :hover.

You can use :seperator to specify variants and combine them when needed in the following manner:

md:bg-black-500 sm:hover:bg-grey-300 dark:bg-white

Let’s say you want to use the :hover variant from TailwindCSS. You could do so as follows:

variants: [
  // hover:
  (matcher) => {
    if (!matcher.startsWith('hover:'))
      return matcher
    return {
      // slice `hover:` prefix and passed to the next variants and rules
      matcher: matcher.slice(6),
      selector: s => `${s}:hover`,
    }
  }
],
rules: [
  [/^m-(\d)$/, ([, d]) => ({ margin: `${d / 4}rem` })],
]

In the code above, match controls when the variant is enabled. If the CSS selector generated is a string, it will be used to match this algorithm. selector provides the option of customizing the return value.

For example, if we match for hover:m-2, it will be taken from users and sent to all variants for matching. It then returns the result m-2, which will be used for another round of matching variants. If no more variants are matched, m-2 then goes to match the rules, generating .m-2 { margin: 0.5rem; }.

Lastly, apply the transformed variants to the generated CSS by attaching :hover to the selector hook. The result is the preceding CSS:

.hover\:m-2:hover { margin: 0.5rem; }

m-2 can only be effective when the user hovers their mouse over the element.

UnoCSS performance

Given the flexibility of UnoCSS, it’s reasonable to wonder whether it performs more effectively than other CSS frameworks. UnoCSS developers wrote a simple benchmark to compare the performances and obtained the following result:

10/21/2021, 2:17:45 PM
1656 utilities | x50 runs
none                            8.75 ms /    0.00 ms 
unocss       v0.0.0            13.72 ms /    4.97 ms (x1.00)
windicss     v3.1.9           980.41 ms /  971.66 ms (x195.36)
tailwindcss  v3.0.0-alpha.1  1258.54 ms / 1249.79 ms (x251.28)

This result interprets that UnoCSS can be up to 200 times faster than Tailwind’s JIT and Windi CSS. Approximately zero overhead means that you can easily integrate UnoCSS into your pre-existing application and make it work with other frameworks without any performance loss.

Conclusion

Despite its newness, UnoCSS’s reputation is growing quickly in the developer community for its simplicity, flexibility, and reliability. With UnoCSS, you can build frameworks like TailwindCSS, WindiCSS, Tachyons, and your custom class library. In this article, we covered the fundamentals of getting started with UnoCSS, reviewing its benefits and basic configurations. If you have any questions, be sure to leave a comment below!

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — .

Doro Onome A software developer and technical writer with a passion for open source.

Leave a Reply