Security News
JSR Working Group Kicks Off with Ambitious Roadmap and Plans for Open Governance
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.
UnoCSS is an atomic-CSS engine that provides a highly customizable and performant way to style your web applications. It allows you to write utility-first CSS directly in your HTML or JavaScript, and it generates the necessary CSS on-demand.
Utility-First CSS
UnoCSS allows you to use utility classes directly in your HTML to style elements. In this example, the text is centered and colored red using utility classes.
<div class="text-center text-red-500">Hello, UnoCSS!</div>
On-Demand Generation
UnoCSS generates the necessary CSS only for the classes you use, making it highly efficient. This example demonstrates how to create a styled button using utility classes.
import 'uno.css';
const button = document.createElement('button');
button.className = 'bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded';
document.body.appendChild(button);
Customizable
UnoCSS is highly customizable. You can define your own theme and utility classes. This example shows how to configure a custom theme with specific colors.
import { defineConfig } from 'unocss';
export default defineConfig({
theme: {
colors: {
primary: '#3490dc',
secondary: '#ffed4a',
danger: '#e3342f',
},
},
});
Tailwind CSS is a utility-first CSS framework that provides a set of predefined classes to build custom designs directly in your HTML. It is similar to UnoCSS in its utility-first approach but is more established and has a larger community.
Twind is a small, fast, and fully-featured utility-first CSS-in-JS solution. It provides a similar utility-first approach as UnoCSS but integrates directly with JavaScript, making it a good choice for React and other JS frameworks.
The instant on-demand Atomic CSS engine.
💡 I highly recommend reading this blog post -
Reimagine Atomic CSS
for the story behind
Inspired by Windi CSS, Tailwind CSS, Twind but:
11/5/2021, 4:26:57 AM
1656 utilities | x50 runs (min build time)
none 8.30 ms / delta. 0.00 ms
unocss v0.4.15 13.58 ms / delta. 5.28 ms (x1.00)
windicss v3.2.1 989.57 ms / delta. 981.27 ms (x185.94)
tailwindcss v3.0.0-alpha.1 1290.96 ms / delta. 1282.66 ms (x243.05)
UnoCSS is designed NOT to be/have:
@apply
) - but you can use shortcuts.🧪 This package is trying to explore the possibilities of what an atomic CSS framework can be. Not production-ready, yet. Expect breaking changes and overhaul redesigns.
npm i -D unocss
// vite.config.ts
import Unocss from 'unocss/vite'
export default {
plugins: [
Unocss({ /* options */ })
]
}
Add uno.css
to your main entry:
// main.ts
import 'uno.css'
That's it, have fun.
See all packages.
UnoCSS is an atomic-CSS engine instead of a framework. Everything is designed with flexibility and performance in mind. In UnoCSS, there are no core utilities; all functionalities are provided via presets.
By default, UnoCSS applies the default preset. Which provides a common superset of the popular utilities-first framework, including Tailwind CSS, Windi CSS, Bootstrap, Tachyons, etc.
For example, both ml-3
(Tailwind), ms-2
(Bootstrap), ma4
(Tachyons), mt-10px
(Windi CSS) are valid.
.ma4 { margin: 1rem; }
.ml-3 { margin-left: 0.75rem; }
.ms-2 { margin-inline-start: 0.5rem; }
.mt-10px { margin-top: 10px; }
Learn more about the default preset.
Presets are the heart of UnoCSS that lets you make your own custom framework in minutes.
To set presets to your project:
// vite.config.ts
import Unocss from 'unocss/vite'
import { presetUno, presetAttributify } from 'unocss'
export default {
plugins: [
Unocss({
presets: [
presetAttributify({ /* preset options */}),
presetUno(),
// ...custom presets
]
})
]
}
When the presets
option is specified, the default preset will be ignored.
To disable the default preset, you can set 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
]
})
]
}
Writing custom rules for UnoCSS is super easy. For example:
rules: [
['m-1', { margin: '0.25rem' }]
]
You will have the following CSS generated whenever m-1
is detected in users' codebase:
.m-1 { margin: 0.25rem; }
To make it smarter, change the matcher to a RegExp and the body to a function:
rules: [
[/^m-(\d+)$/, ([, d]) => ({ margin: `${d / 4}rem` })],
[/^p-(\d+)$/, (match) => ({ padding: `${match[1] / 4}rem` })],
]
The first argument of the body function is the match result, you can destructure it to get the matched groups.
For example, with the following usage:
<div class="m-100">
<button class="m-3">
<icon class="p-5" />
My Button
</button>
</div>
the corresponding CSS will be generated:
.m-100 { margin: 25rem; }
.m-3 { margin: 0.75rem; }
.p-5 { padding: 1.25rem; }
Congratulations! Now you got your own powerful atomic CSS utilities, enjoy!
When you really need some advanced rules that can't be covered by the combination of Dynamic Rules and Variants, you also provide a way to give you full controls of generating the CSS.
By returning a string
from the dynamic rule's body function, it will be directly passed to the generated CSS. That also means you would need to take care of things like CSS escaping, variants applying, CSS constructing, and so on.
import Unocss, { escape as e } from 'unocss'
Unocss({
rules: [
[/^custom-(.+)$/, ([, name], { rawSelector, currentSelector, variantHandlers, theme }) => {
// discard mismatched rules
if (name.includes('something'))
return
// if you want, you can disable the variants for this rule
if (variantHandlers.length)
return
// return a string instead of an object
return `
.${e(rawSelector)} {
font-size: ${theme.fontSize.sm};
}
/* you can have multiple rules */
.${e(rawSelector)}::after {
content: 'after';
}
.foo > .${e(rawSelector)} {
color: red;
}
/* or media queries */
@media (min-width: ${theme.breakpoints.sm}) {
.${e(rawSelector)} {
font-size: ${theme.fontSize.sm};
}
}
`
}]
]
})
You might need to read some code to take the full power of it.
UnoCSS keeps the order of the rules you defined to the generated CSS. Later ones come with higher priority.
UnoCSS provides the shortcuts functionality that is similar to Windi CSS's
shortcuts: {
// shortcuts to multiple utilities
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
'btn-green': 'text-white bg-green-500 hover:bg-green-700',
// single utility alias
'red': 'text-red-100'
}
In addition to the plain mapping, UnoCSS also allows you to define dynamic shortcuts.
Similar to Rules, a dynamic shortcut is the combination of a matcher RegExp and a handler function.
shortcuts: [
// you could still have object style
{
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
},
// dynamic shortcuts
[/^btn-(.*)$/, ([, c]) => `bg-${c}-400 text-${c}-100 py-2 px-4 rounded-lg`],
]
With this, we could use btn-green
and btn-red
to generate the following CSS:
.btn-green {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
--un-bg-opacity: 1;
background-color: rgba(74, 222, 128, var(--un-bg-opacity));
border-radius: 0.5rem;
--un-text-opacity: 1;
color: rgba(220, 252, 231, var(--un-text-opacity));
}
.btn-red {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
--un-bg-opacity: 1;
background-color: rgba(248, 113, 113, var(--un-bg-opacity));
border-radius: 0.5rem;
--un-text-opacity: 1;
color: rgba(254, 226, 226, var(--un-text-opacity));
}
By default, UnoCSS will merge CSS rules with the same body to minimize the CSS size.
For example, <div class="m-2 hover:m2">
will generate
.hover\:m2:hover, .m-2 { margin: 0.5rem; }
instead of two separate rules:
.hover\:m2:hover { margin: 0.5rem; }
.m-2 { margin: 0.5rem; }
UnoCSS does not provide style resetting or preflight by default for maximum flexibility and does not populate your global CSS. If you use UnoCSS along with other CSS frameworks, they probably already do the resetting for you. If you use UnoCSS alone, you can use resetting libraries like Normalize.css.
We also provide a small collection for you to grab them quickly:
npm i @unocss/reset
// main.js
// pick one of the following
// normalize.css
import '@unocss/reset/normalize.css'
// reset.css by Eric Meyer https://meyerweb.com/eric/tools/css/reset/index.html
import '@unocss/reset/eric-meyer.css'
// preflights from tailwind
import '@unocss/reset/tailwind.css'
Learn more at @unocss/reset.
Variants allows you to apply some variations to your existing rules. For example, to implement the hover:
variant from Tailwind:
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` })],
]
match
controls when the variant is enabled. If the return value is a string, it will be used as the selector for matching the rules.selector
provides the availability of customizing the generated CSS selector.Let's have a tour of what happened when matching for hover:m-2
:
hover:m-2
is extracted from users usageshover:m-2
send to all variants for matchinghover:m-2
is matched by our variant and returns m-2
m-2
will be used for the next round of variants matchingm-2
will then goes to match the rules.m-2 { margin: 0.5rem; }
:hover
to the selector
hookAs a result, the following CSS will be generated:
.hover\:m-2:hover { margin: 0.5rem; }
With this, we could have m-2
applied only when users hover over the element.
The variant system is very powerful and can't be covered fully in this guide, you can check the default preset's implementation to see more advanced usages.
UnoCSS also supports the theming system that you might be familiar with in Tailwind / Windi. At the user level, you can specify the theme
property in your config and it will be deep merged to the default theme.
theme: {
colors: {
'very-cool': '#0000ff',
},
breakpoints: {
xs: '320px',
sm: '640px',
}
}
To consume the theme in rules:
rules: [
[/^text-(.*)$/, ([, c], { theme }) => {
if (theme.colors[c])
return { color: theme.colors[c] }
}]
]
The orders of CSS will affect their priorities. While we will retain the order of rules, sometimes you may want to group some utilities to have more explicit control of their orders.
Unlike Tailwind, which offers fixed 3 layers (base
, components
, utilities
), UnoCSS allows you to define your own layers as you want. To set the layer, you can pass the metadata as the third item of your rules:
rules: [
[/^m-(\d)$/, ([, d]) => ({ margin: `${d / 4}rem` }), { layer: 'utilities' }],
// when you omit the layer, it will be `default`
['btn', { padding: '4px' }]
]
This will make it generates:
/* layer: default */
.btn { padding: 4px; }
/* layer: utilities */
.m-2 { margin: 0.5rem; }
You can control the order of layers by:
layers: {
components: -1,
default: 1,
utilities: 2,
'my-layer': 3,
}
Layers without specified order will be sorted alphabetically.
When you want to have your custom CSS between layers, you can update your entry module:
// 'uno:[layer-name].css'
import 'uno:components.css'
// layers that are not 'components' and 'utilities' will fallback to here
import 'uno.css'
// your own CSS
import './my-custom.css'
// "utilities" layer will have the highest priority
import 'uno:utilities.css'
UnoCSS also provides the ability to preprocess and transform extracted utilities before processing to the matcher. For example, the following example allows you to add a global prefix to all utilities:
preprocess(matcher) {
return matcher.startsWith('prefix-')
? matcher.slice(7)
: undefined // ignore
}
From v0.7.0, our Vite plugin now ships with a dev inspector (@unocss/inspector) for you to view, play and analyse your custom rules and setup. Visit http://localhost:3000/__unocss
in your Vite dev server to see it.
See @unocss/runtime
🚧 This part is still under experiment. You might want to read the code to see how it works currently.
in alphabet order
MIT License © 2021 Anthony Fu
FAQs
The instant on-demand Atomic CSS engine.
The npm package unocss receives a total of 170,091 weekly downloads. As such, unocss popularity was classified as popular.
We found that unocss demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.
Security News
Research
An advanced npm supply chain attack is leveraging Ethereum smart contracts for decentralized, persistent malware control, evading traditional defenses.
Security News
Research
Attackers are impersonating Sindre Sorhus on npm with a fake 'chalk-node' package containing a malicious backdoor to compromise developers' projects.