Utility Classes and Utility-First CSS
A utility class does one small job, such as .text-center or .mt-4, and a few of them in a utilities layer handle one-off tweaks without new rules, while utility-first frameworks build whole pages from thousands of them.
Journeyman · CSS · Web Development · Updated
After this lesson you can
- Write small one-job utility classes on a spacing scale and put them in a utilities layer, so they win over component styles
- Decide when a utility class helps and when a component class keeps the HTML clearer
Key takeaways
- A utility class does one job, such as .text-center (center the text) or .mt-4 (a top margin, step 4 on a spacing scale).
- Put utilities in the last layer, @layer base, components, utilities;, so they win over component styles without !important.
- Utilities suit one-off tweaks and helpers such as .visually-hidden. For a part that repeats, a component class keeps the HTML short and the look in one place.
- Utility-first means styling mostly with utilities in the HTML. Frameworks such as Tailwind CSS grow from that idea, with thousands of utilities on one scale.
Maple Street Library is closed on Thursday, November 26, for Thanksgiving, and the events page needs a notice that says so: centered, with a little space above it. You could write a new class with two declarations for it. Then next month there's another notice, and a sign-up form that needs the same space above it, and a heading that should be centered too. Every site has small jobs like these, and a utility class is a class that does exactly one of them. You'll write a few on almost every project, and you'll read hundreds of them in codebases built with frameworks such as Tailwind CSS.
A class with one job
Think of a label maker. A "FRAGILE" label goes on any box in the house: a box doesn't need its own sticker design to say "handle with care". A utility class is that label: a small class with one job that you can put on any element.
.text-center {
text-align: center;
}
.text-center (read "text center") centers the text of whatever it's on, so the notice can be <p class="notice text-center">, and so can the page heading, without a new rule for either. Notice how the name works. A BEM name says what something is (event-card__title); a utility's name says what it does. You can tell what text-center does without opening the stylesheet.
Try it. Write a utility called .font-bold that makes text bold, and put it on one word in a sentence with a <span>.
A spacing scale
Clothing comes in sizes, S, M and L, instead of every shirt being cut to the inch. Spacing works better the same way: a few fixed steps that everyone on a site uses, so gaps line up from page to page. That set of steps is a spacing scale, and spacing utilities are the classes that apply it:
.mt-0 { margin-top: 0; }
.mt-2 { margin-top: 0.5rem; }
.mt-4 { margin-top: 1rem; }
.mt-8 { margin-top: 2rem; }
.mt-4 is read "m-t four": margin-top, step 4. Each step here is 0.25rem, so step 4 is 1rem. The same short letters make a family: mb is margin-bottom, pt padding-top, px padding left and right (the x-axis), py padding top and bottom.
These names are a convention, not part of CSS, and each project or framework sets its own scale. Bootstrap's .mt-4 is 1.5rem and Tailwind's is 1rem, so in someone else's codebase, check what a utility means before you trust its name.
The utilities layer
A utility only helps if it wins. Say the card title's rule sets text-align: left and you add text-center to one title. Both selectors score (0, 1, 0), so the one later in the file wins, and utilities written near the top lose. Putting utilities in their own cascade layer, the last one, settles it:
@layer base, components, utilities;
@layer components {
.event-card__title {
text-align: left;
}
}
@layer utilities {
.text-center {
text-align: center;
}
}
A later layer beats an earlier one whatever the selectors score, so class="event-card__title text-center" is centered, even against a stronger selector such as .events .event-card__title. Bootstrap, which is older than layers, gets the same result another way: every one of its utilities is marked !important. (Cascade Layers with @layer teaches layers in full.)
A helper that screen readers need
The events page has four Save my spot links. On screen, each sits in its event's card, so sighted visitors know which is which. A screen reader, which reads a page aloud, can list every link on a page, and hears "Save my spot" four times. The fix is a few extra words that are hidden on screen but still read aloud:
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
<a href="#save">Save my spot<span class="visually-hidden"> for Coding Club</span></a> shows "Save my spot" and is read "Save my spot for Coding Club". display: none wouldn't work here, because it hides the words from screen readers too. A helper like this is used all over a site and always does the same job, which is what a utility is for.
Where utilities help, and where they clutter
Utilities are so handy that you can style a whole component with them. Here is a library event card's date badge, styled only with utility classes:
<p class="inline-block px-3 py-1 rounded-md font-bold text-white bg-stone-900">Nov 7</p>
It works, and you can read each class. Now picture four cards, on three pages, each with seven classes on the badge, more on the tag, the title and the button. When the library wants rounder badges, someone edits every badge in every page. One .event-card__date rule would have been one change.
| Reach for a utility | Reach for a component class |
|---|---|
| A one-off tweak: center this notice | A part that repeats: every event card |
A helper with the same job everywhere: .visually-hidden |
A look that may change later: the card's border and corners |
| Space between components on one page | The parts inside a component |
Most sites use both: component classes for the things on the page, a small utilities layer for the gaps between them.
Try it. Look at the HTML of any page you use often (right-click, View page source). Find a class attribute with five or more names in it. Can you tell what each name does?
Utility-first: a whole page from utilities
Some teams turn the table around. Utility-first means styling mostly with utilities, right in the HTML, and making a component class only when a pattern really repeats. They like it because nobody has to invent names, the stylesheet doesn't grow with every new page, and a change to one element can't break another page.
Writing thousands of utilities by hand would take forever, so utility-first sites use a framework that has them ready, on one spacing and color scale. Tailwind CSS is the best known, and its classes look like the badge above: px-3, rounded-md, bg-stone-900. The repetition doesn't go away: Tailwind teams cut it down by building each component once, in a template or a JavaScript component, and reusing that. Bootstrap and Tailwind: What a Framework Gives You and What It Costs puts the same event card into Tailwind and compares.
Check yourself
2 questions to try on the lesson page.
So what
A handful of utilities in the last layer takes care of the small jobs every page has, without new rules or !important. Knowing where they help and where they clutter is what lets you read a utility-first codebase, and choose for your own.
Key terms
- Utility Class
- Spacing Utilities
- Utility-First
- Cascade layer