minid.net: Diego Lafuente’s personal blog

April 7, 2019

The Utilitarian CSS Methodology

Summary:

We have been programming CSS incorrectly for a long time. It's time to move forward. By using the Utilitarian CSS Methodology (UCSS), the size of the CSS files is drastically reduced, and the loading, rendering, and painting speed of websites are significantly increased. The projects also gain ease of maintenance and become easier to understand.

When I started writing CSS in 1996, I was truly excited: the entire presentation of an HTML document could be defined on a separate sheet and, consequently, every change I wanted to make reverberated everywhere on the website I was maintaining. This, as it sounds, was a great deal for us developers. Not having to edit thousands of HTML files by hand, always repeating the same changes, was a blessing. But… we had a problem: back then, IE 3 was the first browser to support the fully CSS 1 standard, so the rest of the population were still using Netscape and, as you may suspect, people didn't switch browsers at all like we do today. So, we developers had to stick to HTML editing until the majority of people switched or upgraded browsers. That was the reality around 1996.

It is also true that, even if we only had to rely on HTML, our biggest pain came from not having awesome content managers or includes or partials features, where you can create pieces of HTML and reuse them everywhere. Those who have not yet been taken by the grim reaper should know that long ago developers used frames to do all this job. It was a very archaic and ugly way to develop, but it was the only thing we had. Today, all these things are a kind of urban legend. We no longer have connection speed issues, lack of CSS support, or serious compatibility issues between browsers. Almost everything we mention is quite – but not completely – solved. However, even with all this awesomeness, we have created several other kinds of problems.

We have created a monster

To understand how we have arrived at this monstrous point of programming CSS, we must first understand the path we have traveled thus far. I have always liked to refer to the 4 stages of web development to demonstrate the drastic changes we have made in only 25 years of its existence.

The first stage comprises from 1995 to 2001, which I call the "Dawn of HTML". Lots of problems derived from this particular period because doing layouts required the abuse of the TABLE element like you can't even imagine. Really, you can't. Among other things, we also had the worst network connections ever, the crazy design styles of that time, the abuse of images —especially transparent GIFs— and other silly Internet trends that made loading an entire homepage a sort of family event. It took an average of 15-20 seconds for each page to load, even more if you were located overseas.

Despite all these issues, during this period, we witnessed the rise of Macromedia Flash in 1997 and Flash 3 by the end of 2000. However, even with all those crazy things, CSS wasn't a big thing, and only a few daring developers who started to blog about Web Standards used it. Most of the web projects were done using tables over tables over tables.

In 2001, we entered the second era of web development, which I call "The Empire of Flash." It lasted approximately from 2001 to late 2007, and during this time, CSS and HTML did not find their place in the hearts of developers or managers. Instead, they had to fight against the Flash empire, a proprietary technology of Macromedia that allowed creating rich websites with animations and interactions. It took seven years to overthrow the Flash monopoly, and it wasn't until the release of the iPhone in 2007 and, especially, the decision of Steve Jobs to kill Flash in 2009 that development standards took off towards a new direction with no possible return.

In 2008, things began to change dramatically again. The emergence of smartphones, tablets, and the death of Flash by Apple forced developers and managers to change their strategies. This third period I call "The Rise of HTML 5." Developers started using CSS in an intensive and uncontrolled way, creating thousands of classes to define everything. If we add the fact that it was necessary to develop methods for several browsers, the size of CSS files began to grow brutally. This great chaos drew the attention of bigger companies, especially with the help of companies like Yahoo and others, who began to define the first CSS development methodologies, such as OOCSS (Object Oriented CSS), ACSS (Atomic CSS), BEM (Block, Element, Modifier), or SMACSS (Scalable and Modular Architecture for CSS), among others. These methodologies helped make developers work in an orderly fashion, but they did not reduce the size of the files that much. On the contrary, many of these methodologies ended up increasing the final size of the files, as you can see in this graphic:

average css file size Created with Sketch. Average CSS file size (KB) for Spanish newspapers 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 0 100 200 300

In the fourth stage of the era of web development, around the end of 2012, if we need to name this period, I would say "The Dominion of Methodologies and Frameworks" is the best title I could think of. It is an era where almost all developers use either a framework or a methodology. Here we can see two disastrous patterns.

The first one is because, when developers use frameworks, they not only increase the size of the CSS file by default (as they use all the components by default), but they also add more code on top of it to overwrite the default styles that the frameworks offer at first. This can be seen without problems on many of the analyzed sites, where they use entire libraries for a few necessary styles.

In the second case, the use of methodologies, the developers commit the sin of atomizing each component until it becomes useless, creating more and more components as the project grows. No matter how well-thought-out the architecture is, it shows that it does not work over time, creating more redundant code. It is not a matter of the incompetence of the developer: it is the methodology that encourages the creation of components, modifiers, and more modifiers to cover all unthinkable cases.

This era is characterized by providing developers with tools to develop more comfortably instead of developing with better performance.

The importance of the CSS file size

In order to understand the impact of CSS on our lives, we need to take a good example of projects that have lasted since 1995 —most of them died after a couple of years or after a decade. For this research, I have found newspapers to be the perfect example group. When I got the first data of the research, I saw that the trend was very clear: each year —with some highs and lows— the size increased significantly and in a very similar pattern for each of the group subjects, but after a year of activity, the trend continued every single year, including in 2019.

I already know exactly why that happened. First, developers moved all the logic of building the UI to CSS, hoping their CSS components would cover all the needs of their websites. But over time, they started to stack up more and more code. As the business and activity of these projects grew, so did the CSS file. Second, developers —no longer having the Browser Wars in their minds— began to use new methodologies (such as BEM or OOCSS) and frameworks (such as YUI, Bootstrap, Foundation, etc.) by increasing the base code of each project. Partly because the methodologies are very verbose, the tools offered in the preprocessors, and all the constraints that frameworks bring to the scene, making developers go into technical debt unconsciously and with ease. Third, there was an explosion of libraries that offered functionalities, such as the YUI or jQuery UI libraries, which allowed developers to easily include calendars and other components. These libraries inflated the CSS size, as I could check on more than one occasion.

By the end of 2018, we continue to see the same pattern of problems. But at this point, what I mostly see is the collateral effect of overturning all the responsibility of building the CSS architectures. In fact, developers have spared no effort in reducing the code but rather in expanding it. They ended up with a kind of testament of all the structures that cannot be changed due to the amount of necessary refactoring on every new design. Thus, they repeat thousands of times the same properties and values, as I can see in the most read newspaper of all Spain, MARCA.

Times a property appears in the same CSS file
display color height font-size display padding margin
2029 1464 1416 1308 1249 942 902

In the previous table, we can smell fire: the unnecessary repetition of classes and properties, which significantly increases the CSS file size. With the internet connection speeds we have today, it may be a minor problem, but the problem lies not only in the transfer itself (which is partly the issue) but also in the amount of code that has to be created and maintained, as well as the reuse of all those classes in future cases.

When I said "the amount of code that has to be created," I didn't mean that most developers write color: #ff0000 manually all the time. Of course, this repetition comes thanks to the wonderful features of most CSS preprocessors, such as mixins and extensions, among others.

Most of the projects analyzed fell into these dilemmas: use what has been done or create more classes to avoid conflicts. In general, what I see is developers creating more and more CSS architecture, leading to a clear technical debt problem by thinking their architecture truly solves their problems. If you want to modify MARCA's website, for example, you need to refactor over nine thousand lines of CSS code, which means that you also have to go through each component in their CMS platform and apply new redesigned classes, fixes, and the list goes on.

That's why these projects are really titanic and probably will never be fully redesigned and refactored properly, as the amount of stones in the backpack is too damn high, so is the responsibility to take care of it. Over these years, I've been thinking about how this problem can be solved, and I have found the solution under the wonderful Utilitarian CSS Methodology.

Utilitarian CSS methodology

Designed to be useful rather than decorative.

The Utilitarian CSS Methodology, from now on referred to as "UCSS," is a functional approach I established to solve the problems of programming, scaling, and maintaining CSS projects. It is not a new concept; in fact, some people also call it "functional CSS" or "immutable CSS." UCSS is based on the creation of single-class property utility rather than a collection of classes that define entire components with some base styles that you will probably never use. Each of these CSS properties represents a unique CSS property and its possible values, such as font-weight--bold or display--block. Every single CSS property can be built into our main CSS file, but instead of doing that, we just generate the needed properties and values for our projects, maintaining strict control over the weight of our CSS files. Here's an easy example of how the code would look like:

Let's say we have a hero component:

<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>

In UCSS this JS component would be:

<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>

If we analyze both examples, we can see that in the first example, all the classes are descriptive, but they are relative to their form, not their true CSS properties. We do not know for sure what .hero or hero--homepage does. We can guess something, but we are not quite sure. We also don't know if any of the classes present there are overwritten by another rule. We have little information.

In this first example, we can already imagine the problems that will arise once the project advances in development. The use of classes to describe components causes us to forget the very nature of each one. Soon, we will start creating new classes to do the same things that we had already defined at the beginning. This is a common pattern in web development. It happens a lot: we create a class nav with its initial modifiers (like --principal, --aside, or --categories), but as the project grows, we realize that not all modifiers can do the job, and we end up creating different types of nav classes using synonyms (like buttons, options, etc.) because it does not make sense to overwrite 100% of the navigation rules to create a new thing from scratch, and because if we start reusing classes for other purposes, we may encounter problems the day we want to change something. Doing so not only involves creating more instructions but also leads to problems of inheritance. Therefore, we end up creating new classes from scratch again to avoid problems in the future and to get a cleaner code with the right instructions to create other structures of navigation.

In the second example, which uses functional CSS, everything is separated and clearly defined in purpose. This means that we can make changes in the JS module without having to edit a single line of our CSS file, and the changes will be implemented instantly. We have a complete understanding of the behavior, and there are no constraints or problems related to overwritten rules or inheritance. This is utilitarianism at its best. In the first example, the classes share properties with other structures defined in the CSS, leading to a bloated CSS file and increasing technical debt over time. In contrast, the CSS file in the second example is not bloated, and we simply re-use the required properties in our JS module whenever necessary.

Then the next question is, why would you choose to use a utility-based approach like UCSS instead of using inline CSS? My answer is simple: while inline CSS can be useful in certain scenarios, it has several limitations:

  • It can be difficult to create responsive designs with inline CSS.
  • Inline CSS lacks the power of selectors and pseudo-selectors.
  • If you want to use an external CSS file with inline CSS, you may end up using !important declarations to override existing styles.
  • It can become difficult to read and maintain inline CSS once you have more than a few properties.
  • Inline CSS cannot be pre-processed or post-processed.
  • It can be difficult to modify inline CSS using other languages or JavaScript due to its strict nature.
  • Applying vendor prefixes to inline CSS can be problematic.
  • If you end up using both inline CSS and CSS files, it can complicate your project's architecture.

UCSS allows you to have the best of both worlds: the power of inline CSS to apply whatever rule you need, and the flexibility of 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, we can observe that sm-display--none is designed to work exclusively for mobile devices, while md-display--grid will override the previous class for larger screens. Additionally, we notice a new class called c-warning, which we identify as a custom class by the c- prefix. Custom classes are used to trigger actions or behaviors that cannot be achieved with pure UCSS. Whenever we encounter a custom class, we know that a change in behavior or property is taking place outside the realm of JS. In this instance, the c-warning class defined in our custom.scss file performs the following action:

.c-warning:hover {
  background: map-get($colors, 1);
}

By specifying the behavior, such as :hover, we can see that our custom class exists and is stored in a single file, making it easy to access and modify. This approach offers numerous benefits:

  • Superior performance, as the values for each property can be defined in CSS.
  • No fear of breaking other parts of the project.
  • Elimination of the need for !important.
  • No conflicts with class names over time.
  • Usage of only the necessary properties, avoiding repetition of code.
  • No need to extend the architecture, as the JS module can be built immediately.
  • Minimal maintenance required, as only one file needs to be updated.
  • Reduction in code, resulting in faster loading times.
  • Excellent legacy support, as the same CSS can be reused across multiple modules without requiring a complete overhaul of the code. This allows for easier and faster module changes.

While utility classes in CSS are not a new concept, the approach taken by UCSS or functional CSS is quite innovative. Although you may have used utility classes before, UCSS offers a unique philosophy and architectural design that focuses on allowing developers to concentrate on the logic of the real components, such as JS or other programming languages, rather than creating a separate set of .css files.

Although some projects may have similar approaches or naming conventions, none translate CSS as accurately and strictly as UCSS. The ultimate goal of UCSS is to streamline the development process by reducing the amount of code required for styling and enabling developers to focus on creating functional components.

UCSS is designed to be compatible with any existing codebase and can be used partially, ensuring that only the minimum CSS is needed. It can also be used in conjunction with components such as forms or buttons, making it a versatile tool for developers of all levels.

I encourage you to explore other projects that follow the same philosophy, such as Basscss, Tachyons or Tailwind CSS. These projects also emphasize the use of utility classes to simplify the development process and allow developers to create functional components more efficiently.

Performance

As a general rule, any request to the server can delay the compilation of a website. Since HTML is the first document served and processed by the browser, inline CSS (or styles in the HEAD) can be faster in performance than serving external CSS files. However, in some cases, inline CSS is not feasible or does not scale as needed, and external CSS files with caching rules are used instead. Without proper caching, the page may display a white screen for a few seconds while the browser waits for the CSS to be processed into a CSSOM. Therefore, delivering the CSS file to the browser as quickly as possible is essential for faster page rendering.

UCSS offers a faster and more efficient way to develop CSS. The files generated using the UCSS framework are typically small enough to be placed in the HEAD section of the HTML document, rather than being served through external CSS files. Even if an external file is used, UCSS will still deliver the CSS to the browser more quickly than conventional CSS development methods. Most UCSS files are less than 15KB in size when uncompressed, making them incredibly lightweight and efficient.

One frequently ignored aspect of web development is resource loading in the browser, which refers to how much time it takes for the browser to understand the HTML, JS, CSS, and other resources provided by the server. While this time is typically measured in milliseconds, it can sometimes exceed a second, causing the browser to become stuck and unable to render or paint the webpage.

CSS files with excessive selectors and properties can significantly slow down loading times. Due to the nature of methodologies such as BEM, CSS files can end up with an overwhelming number of rules, sometimes exceeding 9,000 or even more, as previously mentioned. This adds extra time to load and process the CSS, further delaying the rendering process.

To test the loading performance of UCSS compared to other CSS files, several tests were conducted using different types of CSS files and their equivalent in UCSS. The results were shocking. For example, after loading the compiled CSS resources of MARCA 100 times, the loading times were analyzed, and the difference was significant.

CSS Processing speed comparison
Compiled Marca.com Compiled UCSS
84,3ms 8,4ms

The last and most important point to mention in this performance section is rendering time. Once the browser has built the CSSOM –in the loading job–, the rendering instructions begins its job to deliver the painting process. Lots of things can affect the rendering time: JS code and webfonts (specially), CSS effects (like box-shadow, filters, background images, fonts, etc.) amount of resources to load, slow selectors and pseudo selectors, etc. UCSS outperforms any other methodology: it is so explicit that render times are greatly improved. In all tests with different projects in complexity, I've got performance gains from an average of 175ms to a mere 17ms. That's insanely fast. This is given because of the explicit nature of the single class CSS and the lack of all the rules in play at that moment. In a test in the lab, we have found that even un-styled pages aren't that faster than the same HTML styled with UCSS due the nature of the CSS provided on the default browser's CSS stylesheets. So amazing as that.

The framework

UCSS has a framework of my own. It is written in SCSS, so it can be practically adopted in any project, even on those with PostCSS. The major differences of this framework are:

  • Configurable Normalizer.
  • Configurable set of properties.
  • Configurable variables: colors, scales, properties.
  • CSS 1, 2 and 3 support of most of the properties.

One of the dilemmas that has always bothered me is the use of normalizer. Everyone installs normalizer, but few comment on the sections they will never use, therefore, each project already dedicates 6 KB to styles that will never be used. The UCSS framework has a normalizer module, which complies with all normalizer rules, but these are activated according to what you need. To start using it, you need to go to the config_normalizer.scss file and start changing the variables to true so that it automatically takes effect. No more cost of KBs without impact on the site. You can have your customizer, as I recommend as a philosophy to have the best CSS code: only the classes that are needed.

The most important part of the framework is the property configuration file. In order to have the perfect CSS –or the closest thing to this concept– you have to configure the properties file so that it only builds the necessary properties. The default framework has all the properties configured as false. That means that, throughout your development, if you want for example to have the possibility of having a class that brings the color, you must first go to the file of config_css.scss and look in the configuration for the line config-color. In this way, the preprocessor in the next construction will build the class .color - that you need, with the color that you specify in the variables file file, of course. In this way, you will always have strict control of what is produced and not what is not. If you stop using the color property, then you can go to the configuration file and turn the property to false. The idea of UCSS is that you always have the necessary classes, no more, no less. As an example, this website, was built 100% entirely with UCSS framework and the final size compressed is 1.142 bytes. That is almost nothing, nothing as 4 KBs of code that I directly put in the HEAD of the each document. No delays. We go from 55ms processing to 5ms.

Once we know which CSS property we want to use, for example: display, word-break, etc. now we only need to finish configuring the values that we will need for each of these properties. To do this, we need to open the _vars.scss file where we will find the Sass maps with the possible values for each CSS property. For example, for display we will see:

$displays: (
  // none,
  block,
  // inline,
  // inline-block,
  // flex,
  grid
  );

In the variable file, we will find the map displays with these values. In this example, displays has the values none, inline, inline-block, flex commented and has block, grid enabled. If we uncomment any of the display property in the configuration file, the framework will process everything and generate these classes:

.display--block {
  display: block
}

.display--grid {
  display: grid
}

If we want to enable flex, you simply need to remove the comment from the //flex line, and the Sass generator will compile it in the next build. It's that simple: in the variable file you can also create your own values, both for the colors and for the scales of padding and margin among other properties. It is a convenient way to activate and deactivate property values and have total control of them.

This framework doesn't output nice forms, or headers or hero sections. You have to build them using the set of classes on your own. This is freedom. You will never have to overwrite dozens of lines of preset CSS to achieve your design, in fact, you will be astonish how tiny the CSS will become and how easy to mantain your project will be.

Were we are now

Creating this methodology requires data, a lot of data to be sure of its effectiveness. In the last 6 months, I have created code with UCSS both in projects for clients and as examples to measure the performance between the real example and my example of UCSS. I would like developers to use UCSS in their projects so that this project continues to grow and become more solid over time. The more examples we have of UCSS, the more we can understand the possible problems that it may have (although I do not find too many). If you have a project that is using UCSS, let me know.