unc.css

A utility CSS library designed for simplicity, zero tooling, and easy extension.

Docs

Installation

No build step, no tooling. Add two <link> tags and you're done.

<link rel="stylesheet" href="unc.css">
<link rel="stylesheet" href="unc-extend.css">

Load unc-extend.css after unc.css so your overrides take effect.


Colors

Semantic color tokens with built-in state variants. Override any token in unc-extend.css to retheme the entire library.

primary
base
hover
focus
active
secondary
base
hover
focus
active
muted
base
hover
focus
active
surface
base
hover
focus
active
background
base
hover
focus
active
success
base
hover
focus
active
danger
base
hover
focus
active
warning
base
hover
focus
active
white
base
hover
focus
active
black
base
hover
focus
active
/* In :root — unc.css */
--color-primary:        #3b82f6;
--color-primary-hover:  #2563eb;
--color-primary-focus:  #1d4ed8;
--color-primary-active: #1e40af;

/* Override an existing color in unc-extend.css */
:root {
  --color-primary:        #e11d48;
  --color-primary-hover:  #be123c;
  --color-primary-focus:  #9f1239;
  --color-primary-active: #881337;
}

/* Add a custom color in unc-extend.css */
:root {
  --color-brand:        #f97316;
  --color-brand-hover:  #ea6c0a;
  --color-brand-focus:  #c2540a;
  --color-brand-active: #9a3e06;
}

.bg-brand   { background-color: var(--color-brand); }
.text-brand { color: var(--color-brand); }

.bg-brand-hover:hover     { background-color: var(--color-brand-hover); }
.bg-brand-focus:focus     { background-color: var(--color-brand-focus); }
.bg-brand-active:active   { background-color: var(--color-brand-active); }

Spacing

A 0–10 spacing scale used across margin, padding, and gap utilities.

--space-0
0
--space-1
0.25rem
--space-2
0.5rem
--space-3
0.75rem
--space-4
1rem
--space-5
1.25rem
--space-6
1.5rem
--space-7
1.75rem
--space-8
2rem
--space-9
2.25rem
--space-10
2.5rem
--space-0:  0;
--space-1:  0.25rem;   /*  4px */
--space-2:  0.5rem;    /*  8px */
--space-4:  1rem;      /* 16px */
--space-8:  2rem;      /* 32px */
--space-10: 2.5rem;    /* 40px */

Typography Tokens

Font Sizes

xs The quick brown fox
sm The quick brown fox
base The quick brown fox
lg The quick brown fox
xl The quick brown fox
2xl The quick brown fox
3xl The quick brown fox
4xl The quick brown fox
5xl The quick brown fox
6xl The quick brown fox
7xl The quick brown fox

Font Weights

normal Grumpy wizards
medium Grumpy wizards
semibold Grumpy wizards
bold Grumpy wizards
black Grumpy wizards
--text-xs:   0.75rem;    --font-normal:   400;
--text-sm:   0.875rem;   --font-medium:   500;
--text-base: 1rem;       --font-semibold: 600;
--text-lg:   1.125rem;   --font-bold:     700;
--text-xl:   1.25rem;
--text-2xl:  1.5rem;
--text-3xl:  1.875rem;
--text-4xl:  2.25rem;
--text-5xl:  3rem;
--text-6xl:  3.75rem;
--text-7xl:  4.5rem;

Radius

sm
md
lg
full
--radius-sm:   0.125rem;
--radius-md:   0.375rem;
--radius-lg:   0.5rem;
--radius-full: 9999px;

Shadows

sm
md
lg
xl
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);

Display

.block — takes full width
.inline-block .inline-block — sits side by side
.flex child 1
.flex child 2
.flex child 3
.grid child 1
.grid child 2
.grid child 3
<div class="block">...</div>
<span class="inline-block">...</span>
<div class="flex">...</div>
<div class="grid">...</div>
<div class="hidden">not rendered</div>

Position

.relative — parent
.absolute
<div class="relative">
  <div class="absolute top-0 right-0">pinned top-right</div>
</div>

Available: .static .relative .absolute .fixed .sticky

Inset helpers: .inset-0 .top-0 .right-0 .bottom-0 .left-0


Overflow

This content is clipped when it overflows the container boundary and won't expand it.
<div class="overflow-hidden">...</div>
<div class="overflow-auto">...</div>
<div class="overflow-x-auto">...</div>

Flex Direction

.flex .flex-row

1
2
3

.flex .flex-col

1
2
3
<div class="flex flex-row gap-4">...</div>
<div class="flex flex-col gap-2">...</div>

Flex Justify

.justify-start

A
B
C

.justify-center

A
B
C

.justify-end

A
B
C

.justify-between

A
B
C
<div class="flex justify-start gap-2">...</div>
<div class="flex justify-center gap-2">...</div>
<div class="flex justify-end gap-2">...</div>
<div class="flex justify-between">...</div>
<div class="flex justify-around">...</div>
<div class="flex justify-evenly">...</div>

Flex Align

.items-start

A
B
C

.items-center

A
B
C

.items-end

A
B
C

.items-stretch

A
B
C
<div class="flex items-start">...</div>
<div class="flex items-center">...</div>
<div class="flex items-end">...</div>
<div class="flex items-stretch">...</div>

Flex Grow & Shrink

.flex-none
.flex-1 — grows to fill
.flex-none
<div class="flex gap-2">
  <div class="flex-none">fixed width</div>
  <div class="flex-1">grows to fill remaining space</div>
  <div class="flex-none">fixed width</div>
</div>

Grid Columns

.grid .grid-cols-2

1
2

.grid .grid-cols-3

1
2
3

.grid .grid-cols-4

1
2
3
4
<div class="grid grid-cols-2 gap-4">...</div>
<div class="grid grid-cols-3 gap-4">...</div>
<div class="grid grid-cols-4 gap-4">...</div>

Column Spanning

.col-span-2
1
1
.col-span-full
1
.col-span-3
<div class="grid grid-cols-4 gap-4">
  <div class="col-span-2">spans 2</div>
  <div>1</div>
  <div>1</div>
  <div class="col-span-full">full width</div>
</div>

Gap

.gap-1

A
B
C

.gap-2

A
B
C

.gap-4

A
B
C

.gap-6

A
B
C

.gap-8

A
B
C
<div class="flex gap-2">...</div>
<div class="flex gap-4">...</div>
<div class="grid grid-cols-3 gap-6">...</div>
<div class="grid grid-cols-2 gap-x-4 gap-y-2">...</div>

Padding

.p-1

.p-2

.p-3

.p-4

.p-6

.p-8

<div class="p-4">padding all sides</div>
<div class="px-6 py-3">horizontal + vertical</div>
<div class="pt-4 pb-2">top + bottom individually</div>
<div class="pl-4">left only</div>

Margin

.mx-auto
.mb-1
.mb-4
next
<div class="mx-auto max-w-md">centered block</div>
<div class="mt-4 mb-8">vertical margin</div>
<div class="ml-auto">push right</div>

Width

.w-full

100% of parent

.w-auto

shrinks to content
<div class="w-full">...</div>
<div class="w-auto">...</div>
<div class="w-fit">...</div>
<div class="w-screen">...</div>

Max Width

max-w-xs
20rem / 320px
max-w-sm
24rem / 384px
max-w-md
28rem / 448px
max-w-lg
32rem / 512px
max-w-xl
36rem / 576px
max-w-2xl
42rem / 672px
max-w-4xl
56rem / 896px
<div class="max-w-md mx-auto">centered, max 28rem wide</div>
<div class="container">max 80rem, auto margins, padded</div>

Text Size

text-xs The quick brown fox jumps
text-sm The quick brown fox jumps
text-base The quick brown fox jumps
text-lg The quick brown fox jumps
text-xl The quick brown fox jumps
text-2xl The quick brown fox jumps
text-3xl The quick brown fox jumps
text-4xl The quick brown fox jumps
text-5xl The quick brown fox jumps
text-6xl The quick brown fox jumps
text-7xl The quick brown fox jumps
<p class="text-xs">Extra small</p>
<p class="text-sm">Small</p>
<p class="text-base">Base (default)</p>
<p class="text-lg">Large</p>
<p class="text-xl">X-Large</p>
<p class="text-2xl">2X-Large</p>
<p class="text-3xl">3X-Large</p>
<p class="text-4xl">4X-Large</p>
<p class="text-5xl">5X-Large</p>
<p class="text-6xl">6X-Large</p>
<p class="text-7xl">7X-Large</p>

Font Weight

font-normal Grumpy wizards make toxic brew
font-medium Grumpy wizards make toxic brew
font-semibold Grumpy wizards make toxic brew
font-bold Grumpy wizards make toxic brew
font-black Grumpy wizards make toxic brew
<p class="font-normal">Normal 400</p>
<p class="font-medium">Medium 500</p>
<p class="font-semibold">Semibold 600</p>
<p class="font-bold">Bold 700</p>
<p class="font-black">Black 900</p>

Text Alignment

text-left — The quick brown fox jumps over the lazy dog.
text-center — The quick brown fox jumps over the lazy dog.
text-right — The quick brown fox jumps over the lazy dog.
<p class="text-left">Left aligned</p>
<p class="text-center">Centered</p>
<p class="text-right">Right aligned</p>

Style & Transform

.italic Italic text
.uppercase uppercase text
.capitalize capitalized text
.underline Underlined text
.line-through Strikethrough text
.truncate This text will be truncated when too long
<p class="italic">Italic</p>
<p class="uppercase">uppercase</p>
<p class="capitalize">capitalize every word</p>
<p class="underline">underlined</p>
<p class="line-through">strikethrough</p>
<p class="truncate">truncated with ellipsis...</p>

Line Height

.leading-tight

The quick brown fox jumps over the lazy dog near the riverbank.

.leading-normal

The quick brown fox jumps over the lazy dog near the riverbank.

.leading-relaxed

The quick brown fox jumps over the lazy dog near the riverbank.

.leading-loose

The quick brown fox jumps over the lazy dog near the riverbank.

<p class="leading-tight">tight 1.25</p>
<p class="leading-normal">normal 1.5</p>
<p class="leading-relaxed">relaxed 1.625</p>
<p class="leading-loose">loose 2</p>

Text Color

text-primarytext-secondarytext-mutedtext-successtext-dangertext-warning text-black
<p class="text-primary">Primary text</p>
<p class="text-secondary">Secondary text</p>
<p class="text-muted">Muted text</p>
<p class="text-success">Success text</p>
<p class="text-danger">Error message</p>
<p class="text-warning">Warning message</p>

Background Color

bg-primary
bg-secondary
bg-muted
bg-surface
bg-success
bg-danger
bg-warning
<div class="bg-primary text-white">...</div>
<div class="bg-surface">...</div>
<div class="bg-success text-white">...</div>
<div class="bg-danger text-white">...</div>

Border Color

primary
secondary
success
danger
warning
muted
<div class="border border-primary">...</div>
<div class="border border-danger">...</div>
<div class="border-2 border-success">...</div>

Borders

.border
.border-t
.border-b
.border-l
.dashed
.dotted
.border-2
.border-4
<div class="border">all sides</div>
<div class="border-t">top only</div>
<div class="border border-dashed">dashed</div>
<div class="border border-2 border-primary">thick + colored</div>

Border Radius

.rounded-none
.rounded-sm
.rounded
.rounded-md
.rounded-lg
.rounded-full
<div class="rounded-sm">slightly rounded</div>
<div class="rounded-md">medium rounded</div>
<div class="rounded-lg">large rounded</div>
<div class="rounded-full">pill / circle</div>

Shadows

.shadow-none
.shadow-sm
.shadow
.shadow-md
.shadow-lg
.shadow-xl
<div class="shadow-sm rounded-md p-4">subtle shadow</div>
<div class="shadow-md rounded-md p-4">medium shadow</div>
<div class="shadow-lg rounded-md p-4">large shadow</div>
<div class="shadow-xl rounded-md p-4">extra large shadow</div>

Opacity

100
75
50
25
0
<div class="opacity-100">fully visible</div>
<div class="opacity-75">75%</div>
<div class="opacity-50">50%</div>
<div class="opacity-25">25%</div>
<div class="opacity-0">invisible</div>

Transitions

Smooth state changes. Combine with hover/focus/active variants.

<button class="bg-primary bg-primary-hover transition-colors">
  Smooth color change
</button>

<div class="shadow-sm shadow-md-hover transition">
  Smooth shadow change on hover
</div>

Available: .transition .transition-fast .transition-slow .transition-colors .transition-opacity .transition-transform


Cursor

.cursor-pointer
.cursor-default
.cursor-not-allowed
.cursor-wait
.cursor-text
.cursor-grab
<button class="cursor-pointer">clickable</button>
<span class="cursor-not-allowed opacity-50">disabled</span>

Hover Variants

Apply styles only on hover using the -hover suffix. Each color has a dedicated --color-*-hover variable so the shade is independently customizable.

border-primary-hover
text-primary-hover
<!-- Background changes on hover -->
<button class="bg-primary bg-primary-hover transition-colors">Button</button>

<!-- Border highlights on hover -->
<div class="border border-primary-hover transition-colors">Card</div>

<!-- Text color changes on hover -->
<a class="text-muted text-primary-hover transition-colors">Link</a>

<!-- Shadow lifts on hover -->
<div class="shadow-sm shadow-md-hover transition">Card</div>

<!-- Opacity dims on hover -->
<img class="opacity-100 opacity-75-hover transition-opacity">

Focus Variants

Apply styles on keyboard focus using the -focus suffix. Essential for accessible form inputs.

<input class="border outline-none-focus border-primary-focus transition-colors">

<input class="border border-danger-focus ring-danger-focus">

<!-- ring-focus adds a 2px outline using --color-primary-focus -->
<button class="ring-focus">Keyboard accessible button</button>

Active Variants

Apply styles while an element is being pressed using the -active suffix.

<!-- Full interactive state stack -->
<button class="
  bg-primary
  bg-primary-hover
  bg-primary-active
  text-white
  transition-colors
">
  Button
</button>

Responsive Variants

Breakpoint variants use a -{breakpoint} suffix and are mobile-first (min-width). Consistent with all other variant naming.

Breakpoints

-sm 640px+
-md 768px+
-lg 1024px+

Column 1
Column 2
...


Extending

Customize tokens or add new utilities in unc-extend.css — loaded after unc.css so everything cascades correctly.

/* unc-extend.css */

/* Override design tokens to retheme the whole library */
:root {
  --color-primary:        #e11d48;
  --color-primary-hover:  #be123c;
  --color-primary-focus:  #9f1239;
  --color-primary-active: #881337;
}

/* Add custom component classes built on top of tokens */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-5);
  background: var(--color-primary);
  color: #fff;
  font-weight: var(--font-medium);
  border-radius: var(--radius-md);
  border: none;
  cursor: pointer;
  transition: background var(--transition-fast);
}

.btn:hover  { background: var(--color-primary-hover); }
.btn:active { background: var(--color-primary-active); }

.btn-outline {
  background: transparent;
  color: var(--color-primary);
  border: 1px solid var(--color-primary);
}

.btn-outline:hover {
  background: var(--color-primary);
  color: #fff;
}