April 7, 2019
The Utilitarian CSS Methodology
We have been writing CSS in the wrong way for a long time. It is time to move forward. The Utilitarian CSS Methodology, or UCSS, reduces the size of CSS files, improves loading, rendering, and painting speed, and makes projects easier to maintain and understand. This article explains why traditional CSS architectures tend to grow into large, fragile systems, and why a utility-first approach can solve many of these problems.
When I started writing CSS in 1996, it felt like a huge step forward. For the first time, the presentation of an HTML document could be defined in a separate file. A single change could affect an entire website. For developers, this was a major improvement. Before that, changing a design often meant editing hundreds or thousands of HTML files by hand. CSS promised to remove that pain.
But there was a problem. At that time, Internet Explorer 3 was the first commercial browser with CSS support, but that support was still incomplete. Many users still used Netscape, and people did not switch browsers as quickly as they do today. So developers still had to rely heavily on HTML for layout and presentation until browser support improved.
There was another important issue: we did not have the tools we have today. We did not have modern content management systems, components, includes, partials, or templating systems. Developers used frames to reuse parts of a page. It was ugly and limited, but it was what we had.
Today, many of those problems are almost gone. Browser support is much better. Connection speeds are much faster. Compatibility issues are smaller than they used to be. We have powerful tools, frameworks, build systems, and component-based architectures.
But we also created new problems.
We Created a Monster
To understand how CSS became so difficult to manage, we need to look at the history of web development. I usually describe it in four stages.
1. The Dawn of HTML: 1995–2001
The first stage was the Dawn of HTML. During this period, layouts were built with tables. Not simple tables. Tables inside tables, inside more tables. Developers abused the table element because there was no better way to create complex layouts. We also had very slow connections, heavy images, transparent GIF, strange design trends, and homepages that could take 15 to 20 seconds to load. If you were overseas, it could take even longer. At the same time, Macromedia Flash started to grow. Flash appeared in 1997, and Flash 3 arrived by the end of 2000. Still, CSS was not widely used. Only a small group of developers interested in web standards were using it seriously. Most websites were still built with tables.
2. The Empire of Flash: 2001–2007
The second stage was the Empire of Flash. From around 2001 to late 2007, CSS and HTML struggled to become the main way to build rich websites. Flash dominated the market because it made animations, interactions, and complex visual experiences much easier. Flash was proprietary, but it solved real problems at the time. Many developers and managers saw it as the future of the web. That changed with the release of the iPhone in 2007, and especially with Steve Jobs’ decision not to support Flash on Apple mobile devices. From that moment, web standards started moving in a new direction. There was no way back.
3. The Rise of HTML5: 2008–2012
Around 2008, everything changed again. Smartphones, tablets, and the decline of Flash forced teams to rethink how they built websites. HTML, CSS, and JavaScript became the main stack for rich user interfaces. Developers started using CSS more heavily, but often without control. CSS files grew quickly. Projects needed to support different browsers, devices, and screen sizes. Developers created more and more classes to cover every possible case.
This chaos pushed larger companies and communities to define CSS methodologies. We started to see approaches like:
- OOCSS — Object-Oriented CSS
- ACSS — Atomic CSS
- BEM — Block, Element, Modifier
- SMACSS — Scalable and Modular Architecture for CSS
These methodologies helped developers organize their work. They made CSS more structured and easier to reason about. But they did not really solve the size problem. In many cases, they made CSS files bigger:
4. The Dominion of Methodologies and Frameworks: 2012 onward
Around the end of 2012, we entered the fourth stage: the Dominion of Methodologies and Frameworks. In this period, almost every developer used either a CSS framework or a CSS methodology. This created two common problems.
The first problem comes from frameworks. Many teams import large CSS frameworks even when they only need a small part of them. Then they add more CSS on top to override the default styles. As a result, the final CSS file contains the framework, the unused framework code, and the custom overrides.
The second problem comes from methodologies. Developers often split components into too many blocks, elements, modifiers, and variants. Over time, the number of components and modifiers grows. The system becomes harder to understand. The project accumulates redundant code. This is not always a problem of developer skill. The methodology itself encourages developers to create more components, more modifiers, and more exceptions. This era gave developers tools to work more comfortably. But comfort is not the same as performance.
Why CSS File Size Matters
To understand the impact of CSS size, I looked for projects that had existed since the early days of the web. Most websites from the 1990s disappeared after a few years. Newspapers were the perfect group to analyze because many of them have been online for decades.
The trend was clear: CSS files kept growing year after year. There were some highs and lows, but the general direction was the same. The size increased significantly, and the pattern repeated across different newspapers.
This happened for several reasons.
First, developers moved more and more UI logic into CSS. They expected CSS components to cover all the needs of the website. But as the business grew, the CSS file grew too.
Second, developers stopped thinking about browser wars and started adopting methodologies and frameworks such as BEM, OOCSS, YUI, Bootstrap, and Foundation. These tools added more base code to each project. Many methodologies are verbose, preprocessors make repetition easy, and frameworks introduce constraints that often lead to technical debt.
Third, there was an explosion of UI libraries. Libraries like YUI and jQuery UI allowed developers to quickly add calendars, widgets, and other components. But they also increased the size of CSS files.
By the end of 2018, the same pattern was still visible. The main issue was that teams had moved too much responsibility into CSS architecture. Instead of reducing CSS, many teams kept expanding it. Large CSS files became a kind of historical record of every past decision, every redesign, and every workaround. They became hard to change because changing them required too much refactoring.
For example, in the CSS file of MARCA, one of the most-read newspapers in Spain, the same properties appeared thousands of times:
| display | color | height | font-size | display | padding | margin |
|---|---|---|---|---|---|---|
| 2029 | 1464 | 1416 | 1308 | 1249 | 942 | 902 |
This is a clear warning sign.
The problem is not only network transfer. With modern connections, downloading a large file may not look like a serious problem. The real problem is the amount of CSS that has to be created, parsed, maintained, and reused. When I say “created,” I do not mean developers manually write color: #ff0000 thousands of times. In many cases, the repetition comes from preprocessors, mixins, extensions, and framework abstractions.
Most projects end up facing the same dilemma:
- Reuse existing classes and risk unexpected conflicts.
- Create new classes to avoid conflicts and increase technical debt.
In practice, many developers choose the second option. They create more classes, more architecture, and more rules because they believe this will make the system safer. But over time, this makes the system heavier and harder to change.
If you want to redesign a large site like MARCA, you may need to refactor thousands of lines of CSS and then update every related component in the CMS. That type of project becomes enormous. In many cases, it is never fully completed. The backpack is too heavy.
This is the problem I wanted to solve with the Utilitarian CSS Methodology.
The Utilitarian CSS Methodology
UCSS is designed to be useful, not decorative.
The Utilitarian CSS Methodology is a functional approach to writing, scaling, and maintaining CSS. It is not a completely new idea. Some people call similar ideas functional CSS or immutable CSS.
The core idea is simple: instead of creating large component classes, we create small utility classes that represent one CSS property and one value.
For example:
.font-weight--bold {
font-weight: bold;
}
.display--block {
display: block;
}
Each utility class has a clear purpose. It does one thing. In theory, every CSS property could be represented in the final CSS file. In practice, we only generate the properties and values that the project actually needs. This gives us strict control over the size of the CSS file.
Let’s compare two approaches.
Traditional component-based CSS
<div class="hero hero--homepage">
<h1 class="hero__title hero__title--accent">Our wonderful startup idea</h1>
<img src="/images/image.png" alt="" class="hero__image hero__image--centered" />
</div>
UCSS
<div class="background-color--1 padding--32 text-align--center">
<h1 class="font-size--64 color--2 margin-bottom--32">Our wonderful startup idea</h1>
<img src="/images/image.png" class="display--block margin--auto" alt="" />
</div>
In the first example, the classes are descriptive, but they describe the component, not the actual CSS behavior. We can guess what .hero or .hero--homepage does, but we do not know for sure. We also do not know whether those classes are overwritten somewhere else.
The information is hidden.
In the second example, the behavior is visible. The class names tell us exactly what is happening. The CSS is explicit.
This matters because component-based CSS often creates problems as a project grows. A class starts with a clear purpose, but later the project needs a similar variant. Then another variant. Then a special case. Then an exception.
For example, a project may start with a .nav class and a few modifiers such as .nav--main, .nav--aside, or .nav--categories. Later, the team needs navigation patterns that no longer fit those modifiers. Developers then create new classes with different names, such as .buttons, .options, or other synonyms. They do this because overwriting 100% of the original navigation rules does not make sense. They also avoid reusing existing classes because a future change could break other parts of the site. So they create new classes from scratch. Again and again.
This is how CSS grows into technical debt. With UCSS, the behavior is separated into small reusable instructions. Changes happen in the component or template, not inside a growing CSS architecture. Developers can adjust the HTML or JavaScript module without editing the CSS file.
There are no hidden dependencies, no inheritance problems, and fewer overwritten rules. That is utilitarianism applied to CSS.
Why Not Just Use Inline CSS?
A common question is: if UCSS is so explicit, why not use inline CSS?
Inline CSS can be useful in some cases, but it has important limitations:
- It is harder to build responsive designs.
- It does not support selectors and pseudo-selectors properly.
- It can force the use of
!importantwhen combined with external CSS. - It becomes difficult to read and maintain after a few properties.
- It cannot be preprocessed or post-processed in the same way.
- It can be harder to modify safely with JavaScript or other languages.
- Vendor prefixes are more difficult to manage.
- Mixing inline CSS with external CSS files can complicate the architecture.
UCSS gives you the best of both worlds: the explicit nature of inline styles and the flexibility of CSS classes.
For example:
<div class="sm-display--none md-display--grid c-warning">
<h3>This is a warning</h3>
<p class="color--2">Your profile needs to be updated.</p>
</div>
In this example, sm-display--none applies to small screens, and md-display--grid overrides it on larger screens.
The class c-warning is different. The c- prefix identifies it as a custom class. Custom classes are used when pure UCSS is not enough, usually for behaviors such as hover states or interactions.
For example:
.c-warning:hover {
background: map-get($colors, 1);
}
This makes the custom behavior easy to find and easy to maintain. It lives in one custom file and has a clear purpose.
This approach gives several benefits:
- Better performance because values are defined directly in CSS.
- Less risk of breaking other parts of the project.
- No need for
!importantin most cases. - No class name conflicts over time.
- Only the necessary properties are used.
- Less repeated code.
- No need to keep expanding the CSS architecture.
- Faster development of JavaScript or HTML components.
- Less maintenance.
- Smaller CSS files and faster loading.
- Better support for legacy code because the same utility classes can be reused across many modules.
Utility classes are not new. But UCSS is not just a list of helper classes. It is a strict way of translating CSS properties into a controlled class system. The goal is to reduce the amount of CSS required for styling and let developers focus on the real components: JavaScript modules, templates, backend-generated views, or any other system that produces HTML. UCSS can be adopted partially. It can live inside an existing codebase. It can also work together with components such as forms, buttons, and custom interactive elements. There are other projects with a similar philosophy, such as Basscss, Tachyons, and Tailwind CSS. They also use utility classes to simplify development and help teams build interfaces faster.
Performance
Every network request that sits on the critical rendering path can delay the first render of a page. In a normal navigation, the main resource is the HTML document. The browser parses that HTML and discovers the critical subresources it needs, including stylesheets, scripts, fonts, and images. Because external stylesheets are render-blocking by default, small amounts of critical CSS placed directly in the head can make the first render faster than waiting for a separate CSS file.
However, inline CSS does not always scale. It increases the size of the HTML document and cannot be cached independently from the page. In many projects, external CSS files are still the right choice. When those files are used, caching becomes important. Without fast delivery and good caching, the browser may delay painting while it downloads and parses render-blocking CSS and builds the CSSOM.
This is why CSS delivery matters. The goal is not always to inline everything. The goal is to keep critical CSS small, deliver it early, and avoid making the browser download and parse CSS that is not needed for the initial view.
UCSS can make CSS delivery faster because the generated files are usually small. In many cases, the critical part of a UCSS file can be small enough to place directly in the head of the document. When served as an external file, a well-configured UCSS file is still usually much smaller than a conventional CSS architecture.
In the projects I tested, most UCSS files were less than 15 KB uncompressed.
Another important topic is browser resource processing. The browser must understand the HTML, CSS, JavaScript, images, fonts, and other resources sent by the server. This work is often measured in milliseconds, but it can still become expensive.
Large CSS files with many selectors and repeated properties can slow this process down. This is not because BEM or any other methodology is automatically slow. The problem appears when a project produces thousands of rules, deep selector chains, repeated declarations, and many unused styles. As mentioned earlier, some real-world CSS files can exceed 9,000 lines or more.
That extra CSS must be loaded, parsed, and applied.
In my tests, the UCSS version was significantly faster to process than the traditional compiled CSS file I compared it against. For example, after loading the compiled CSS resources of MARCA 100 times, the difference was clear:
| CSS file | Processing speed |
|---|---|
| Compiled Marca.com CSS | 84.3 ms |
| Compiled UCSS | 8.4 ms |
Rendering time is also important.
After the browser builds the DOM and CSSOM, it can construct the render tree, run layout, and paint the page. Many factors affect this process: JavaScript, web fonts, CSS effects, box shadows, filters, background images, complex selectors, pseudo-selectors, and the total number of resources.
UCSS can perform well because it is explicit and keeps the active rule set small. There are usually fewer rules in play, fewer overrides, less accidental inheritance, and fewer conflicts to resolve. In tests with projects of different complexity, I saw rendering improvements from an average of 175 ms to around 17 ms. These numbers should be read as results from my test cases, not as a universal guarantee. That is a huge difference.
In some lab tests, pages styled with UCSS were almost as fast as unstyled pages. In some cases, the difference was surprisingly small because browsers also apply their own default stylesheets. The result is simple: less critical CSS usually means less work for the browser before the first render.
The Framework
UCSS also has a framework. It is written in SCSS, so it can be adopted in many types of projects, including projects that already use PostCSS.
The main features are:
- Configurable normalizer.
- Configurable set of properties.
- Configurable variables for colors, scales, and values.
- Support for most CSS 1, CSS 2, and CSS 3 properties.
One thing that has always bothered me is the default use of normalizers. Many teams install a normalizer and never remove the parts they do not need. As a result, every project starts with several kilobytes of CSS that may never be used.
The UCSS framework includes a configurable normalizer. It follows normalizer rules, but each section can be enabled only when needed.
To use it, you open config_normalizer.scss and activate the required sections by setting their variables to true.
No unnecessary kilobytes. No hidden cost.
The most important part of the framework is the property configuration file. To produce the closest thing to perfect CSS, you must generate only the properties your project needs.
By default, all properties are disabled. For example, if you want to use color classes, you enable the color property in config_css.scss. Then the preprocessor generates the related classes using the values defined in your variables file. If you later stop using that property, you can disable it again. The idea is simple: generate only the necessary classes. No more, no less.
For example, this website was built entirely with the UCSS framework. The final compressed CSS size was 1,142 bytes. That is small enough to place directly in the head of each document. This removes the extra stylesheet request for that page, although the CSS still has to be parsed by the browser. In that test, the CSS processing time dropped from 55 ms to 5 ms.
Once you know which CSS property you need, such as display or word-break, you configure the values for that property.
For example, in _vars.scss, the display values may look like this:
$displays: (
// none,
block,
// inline,
// inline-block,
// flex,
grid
);
In this example, block and grid are enabled. Other values are commented out.
The framework will generate:
.display--block {
display: block;
}
.display--grid {
display: grid;
}
If you need flex, you remove the comment from flex, and the next build generates:
.display--flex {
display: flex;
}
This is the main idea of the framework. You activate only the values you need. You can also define your own values for colors, spacing scales, margins, padding, and other properties. The framework does not output nice forms, headers, cards, buttons, or hero sections by default. You build those yourself using the utility classes.
That is the point.
You do not need to fight a preset design. You do not need to override dozens of rules. If the system is configured with discipline, you get more control, smaller CSS, and a codebase that is easier to maintain.
Where We Are Now
Creating a methodology like this requires data. A lot of data.
During the last six months, I have used UCSS in client projects and in controlled examples. I compared real CSS files with UCSS equivalents to measure size, loading time, processing time, and rendering time.
The results were strong enough to continue developing the methodology.
I would like more developers to try UCSS in real projects. The more examples we have, the better we can understand its limits and improve the framework.
So far, I have not found many serious problems with the approach. But every methodology needs real usage, real feedback, and real pressure from production projects.
If you are using UCSS in a project, let me know.
The goal is simple: write less CSS, make it more explicit, reduce technical debt, and let developers focus on building products instead of maintaining a growing CSS monster.