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:
Let’s get started!
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.
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:
.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 ] }) ] }
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>
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
.
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 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.
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.
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.
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!
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.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. 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 and mobile apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.