minid.net: Diego Lafuente’s personal blog

August 12, 2019

In defense of Functional CSS

Summary:

Functional CSS is a relatively new concept in the frontend development world, which some developers are against. However, this may be because they do not fully understand its advantages and how it can improve their code. In this article, I will describe some of the arguments in defense of Functional CSS and explain why it may be a better methodology for some projects.

In the frontend development world, there are currently two recent trends that people are discussing: those who believe that programming with encoding structural annotations in string names (BEM, object-oriented approach, etc) is the best and those that use the functional form of CSS as a way of development (single-class utility purpose). Both methodologies have their pros and cons. However, when analyzing both, these articles never make a fair analysis of Functional CSS, leaving the impression that the current popular way of writing CSS is the only effective way to do it.

When analyzing and giving judgment on both methodologies in articles, we must recognize the following problems of current web development as the biggest trade-offs to have in mind:

  • Code recycling is an urban legend.
  • People always forget the Technical Debt.
  • People never really talk seriously and deeply about performance.
  • People assume that everyone will know how to build good CSS architectures.
  • People forget that employees come and go in companies.
  • People forget that it is complicated to retake up projects.
  • Some people believe that it is only a problem of communication between employees.
  • There is an absurd fear to increase the HTML size.

It is my belief that Functional CSS is the correct way forward, at least until empirical evidence suggests otherwise. The volatility of the internet means that investing excessive time and effort in creating the "perfect architecture" may not be the most efficient use of resources. In fact, being explicit in intentions in the same code can be more effective. I am so convinced of this that I even disagree with Jeffrey Zeldman's position on this subject, despite admiring him as a professional. I will comment on Jeffrey's points, as we only have a difference of 2 years of professional experience on the internet.

Recycling code is an urban legend

One of the arguments against Functional CSS is that it does not allow for code recycling. However, in my 25 years of experience as a developer and product manager, I have never seen code recycled to a significant level. Despite having worked on more than 100 website creations and over 25 native platforms for smartphones, I have never witnessed a project where developers simply touched the CSS without changing the HTML structure. Instead, what I usually see is developers starting from scratch every time. When asked about this, most developers say that it is faster to start from scratch than to undo countless lines of legacy code. While developers may import some parts of the code, the idea of only developing in CSS is somewhat of an urban legend. This bias may have started when examples such as CSS Zen Garden preached that CSS was powerful because it allowed you to change the entire appearance without touching the HTML. However, this bias is far from reality. Every web project that can be redesigned mutates all its HTML code from scratch, as well as its CSS code. My research on CSS demonstrates this fact: all the internet projects that I have researched since 1996 have always made drastic changes, and the code has continued to grow. This growth affects the loading, rendering, and painting performance of each web document, despite maintaining a style of development.

CSS Zen Garden was, in my opinion, one of the best experiments on web development to demonstrate the flexibility of development that existed in HTML and CSS, but not to demonstrate that you would never again need to touch up your HTML code whatever the project. In 2003 –when this project was born– the average weight of the CSS files was 6KB. Today (2019) we are at an average of ~500KB, so using the CSS Garden argument card is, in my opinion, wrong. First, because it never adapts to the reality of developments, second because the difference in code size required is higher when new development parameters are taken, based mostly on philosophies such as BEM or others. CSS Garden is a web document, with just 54 CSS classes, against more than 2000 classes that can be found in current projects.

The argument that Functional CSS does not allow for code recycling has failed. No one recycles code to the extent that some detractors of FCSS preach, including Jeffrey Zeldman. This is an absurd argument because since CSS was implemented, the argument of not doing everything in HTML has lost strength. Today, web development is dominated by content generators, JS frameworks, and other tools. The problem now is to serve things beyond HTML, as it increases the rendering time and total painting of each page.

Site-wide changes can be managed perfectly in the Functional CSS world. Since we edit the templates, we don't have the feeling that we need to do extra work anymore, and we also get the security of site-wide changes being explicit changes that impact our work according to our strategy. In the OOCSS world, changing the contents of one class will impact the entire website, creating more problems. However, you can still use site-wide CSS rules that can affect everything, and these can be easily managed in a separate file where you can only find "special rules". This is much better than inspecting 500KB of possible rules.

Functional CSS is a methodology that can help reduce technical debt

Technical debt is a recurring problem in development, and no methodology is entirely immune to it. However, it's important to recognize which methodologies are more prone to suffering from it than others. In CSS, technical debt can occur when the architecture is left to the mental capacity of each developer, leading to the creation of redundant and slow code over time. This can happen due to pressure to do new things, lack of definitions, the need for new abstractions, employees recycling within the company, or the change of service providers. Technical debt can manifest itself in the form of slow selectors, property overwriting, and repetition of code, ultimately affecting everyone.

Functional CSS is a methodology that can help reduce technical debt by implementing a more explicit and intentional approach to writing CSS. Unlike other CSS methodologies, it is more explicit in context, which reduces the chances of technical debt accumulating over time. With Functional CSS, you don't need to think about the context and existing CSS architecture to create a new structure in your project. You also don't need to think about new forms of nomenclatures or other variants. Instead, you can build explicitly and functionally on the components of JS, and your CSS file will hardly grow. The only exception is when you need to radically change the design as the size of the browser screen changes, which requires a different type of strategy. By being more intentional and explicit in writing CSS, Functional CSS can help reduce technical debt and make code maintenance easier over time.

Technical debt is a significant problem that can affect codebases for years, causing them to become unwieldy and difficult to maintain. In many projects, fixing technical debt in both HTML templates and CSS can be time-consuming, resulting in suboptimal code that persists for extended periods. However, with Utilitarian CSS, this issue is less likely to arise. Utilitarian CSS employs explicit instructions of CSS properties, such as display--block and align-items--center, rather than a collection of custom class names, which can simplify the codebase and reduce technical debt. Additionally, Functional CSS can be written by hand, without the need to use the original framework, as long as the methodology's strictness is maintained (i.e., writing the CSS property name using the original syntax). By reducing technical debt, Utilitarian CSS can help ensure that codebases remain manageable and maintainable over the long term.

Improving Performance and Overcoming HTML File Size Concerns

This is a concern that I always have after reading comments written by critics of Functional CSS: they never fully discuss its performance benefits. They only acknowledge that functional CSS is better because its files are significantly smaller, but they fail to recognize its other advantages. Instead, they mostly express fear that switching to functional CSS will increase HTML size, which they see as a major problem. Their argument is that the solution is to "write good CSS" which will make files smaller. However, Functional CSS is infinitely superior for various reasons, including:

FCSS is:

  • More reusable
  • More testable
  • More maintainable

As developers, it's important to understand that increasing the HTML file size slightly by using more class names is not a significant trade-off in performance. In fact, you may find that your website performs much faster in various ways. Firstly, most projects use HTML caching, meaning only a few parts of the screens are updated, especially with technologies like React and Vue. HTML is, by default, the first resource to download and load, making it faster by nature. HTML is the first and most prioritized resource that will be downloaded, and the average HTML load time is around 52msec compared to ~600msec of CSS files.

When a browser requests more than 6 resources (styles, fonts, images, etc.), it may result in STALLED blocking, which can be checked in Google Chrome's Inspector. This occurs when too many TCP packets are requested, and the limit of 6 connections is exceeded. In HTTP 1.0 and 1.1, this causes the STALLED state, which can add countless milliseconds (and even seconds) to the process of loading resources into the browser. Once you acknowledge this, you will realize how much time is spent on downloading, parsing, and loading the CSSOM on the first visit to a page.

While caching can work in some situations, loading and rendering performance metrics may still come up, and "the magic" may disappear. Therefore, it's essential to consider using more class names in your HTML to improve website performance.

It's worth noting that even though writing CSS with a beautiful semantic architecture can be an enjoyable experience, it does not necessarily mean that CSS is the best solution. While it may be understood among developers, this does not guarantee that it will help the web page load, render, and paint everything faster. As Jeffrey Zeldman has pointed out, if the focus is solely on how well-written the CSS is, it becomes clear that performance is no longer a priority for these individuals. This assumes a trade-off between readability and performance, placing the ego or the happiness of the developers before the interests of the users. However, it's important to remember that the ultimate goal of any web page is to provide the best experience for the user, and therefore, the focus should always be on finding a balance between readability, maintainability, and performance.

The harsh reality is that traditional CSS methodologies will never be better in terms of performance. For example, OOCSS methodology already repeats CSS properties, which increases the file size and is considered anti-performant. I've seen projects with over 1.5MB of CSS code, which linearly increases the loading time of resources. A 15KB file of UCSS rules generates CSSOM x10 faster than a 500KB of rules. Traditional methodologies also encourage the use of slow selectors and various pseudo-selectors, including generalists, inherited, and attributed. This means that developers are always working in inheritance mode and creating selectors that are slow by default.

In contrast, functional CSS selectors are direct and efficient, using a single class. For example, the class .display--none { display: none } will be much faster than the selector .header .nav .item span { display: none }. When our methodology encourages us to write nested or conditional rules, we increase the time it takes to render the page. This affects every page visited, and the time to render is always random and may be affected by other resources and computer conditions, such as CPU priorities and memory rewriting.

On the other hand, FCSS starts from the philosophical point of always focusing on performance first, encouraging reuse, and when it is no longer possible, extending functionality by adding more single-purpose classes. This philosophy is pro-user, ensuring that the smallest and most optimized file in terms of rules is always offered, as well as pro-developer, since it encourages the use of architectures with an easy-to-understand and easy-to-maintain system. However, some developers believe they would never understand a site made with functional CSS, despite its benefits.

To achieve these benefits, UCSS uses various strategies, including creating classes for common properties, reducing unnecessary properties, and using functional classes. These strategies make the CSS files smaller, more maintainable, and faster to load. UCSS also encourages developers to use HTML and CSS semantics to write code that is easy to read and understand.

Overall, UCSS offers a more effective approach to writing CSS that prioritizes performance while still maintaining readability and maintainability.

On the semantics of the classes

Most people assume that everyone will eventually learn how to build good CSS architectures, including choosing the right names for each component. However, this argument has two main issues. Firstly, it assumes that everyone has the same common sense when it comes to choosing names, which is rarely the case, especially outside of typical layout structures like headers and footers. As you move away from these standard zones, naming conventions become less clear and more subjective. Secondly, this argument assumes that the developer or development team will remain the same for a long period of time and that they will always make conscious decisions when creating new components. In reality, employee turnover in the IT industry is immense, and the retention of the original architecture is not guaranteed when new team members are added. Studies show that up to 44% of employees would consider taking a job with a different company for a raise of 20% or less, and 65% are confident they can find a better position that pays more. This turnover and lack of continuity can result in multiple developers adding their own architecture and creating multiple architectures in the same CSS file, leading to confusion and potential errors.

This is where functional CSS shines. By using a pre-defined set of classes that describe specific properties, developers can avoid the subjective process of naming and focus on creating efficient and maintainable code. Functional CSS provides a common language that is easily understood by all team members, regardless of their background or experience. This makes it easier to maintain consistency in the codebase, even when team members come and go.

In large projects, it is not uncommon to see multiple coding styles in the same CSS file. This can create confusion, increase the file size, and slow down the rendering process. In contrast, functional CSS offers a standardized approach that prioritizes performance, maintainability, and consistency. This is not only beneficial for developers but also for the end-user, who will enjoy a faster, more efficient website or application.

Of course, one can argue that everything can be solved by writing a well-done style guide. Unfortunately, documentation about CSS in a company is like an urban legend. Style guides are so rare to find that when I come across a document that explains CSS, I find it has been written hastily, as if it were an unfortunate task with no choice. In my 25 years of experience working on projects, I have never found well-maintained documents. Instead, it was always a matter of not finding any documents at all. Landing on a project already involves wasting a lot of time understanding how the architecture was made and how classes can be utilized in our development tasks. The existence of a style guide does not imply that the architecture will be respected or that there is no abuse in the code. Guides without someone to enforce them are plainly useless. They are like speed signals on the road while cruising in the middle of nowhere: people don't even respect them.

One of the advantages of UCSS is its ease of use when making changes. You can simply open the JS module or HTML file and modify the explicit CSS right there, as if it were inline CSS but with the added power of classes. There's no need to worry about class nomenclatures or dependencies, as the context is already explicit. This makes the process much more efficient and straightforward.

This is not solely about team communication

Twenty-five years ago, the concept of code review was not yet a part of web development. Changes were simply uploaded to the servers, and relevant adjustments were made only when it was too late. Today, the workflow is different. We have access to tools that can perform hundreds of tasks automatically, and in addition to that, we have code reviews. If your company does not perform code reviews, you may be in a difficult position. Code reviews are an important part of the modern web development process, and failing to implement them can lead to serious consequences.

Communication between teams today is more straightforward and direct, thanks to tools like Slack channels, Git, and sprint meetings. However, the challenge lies in reaching agreements quickly and efficiently. It can be difficult to come to a consensus on class names, reuse of existing styles, and modifications to the design. The list of issues can seem endless, and it's easy to get bogged down in the details. That's where functional programming in CSS comes in. By making the code more explicit, it removes friction when composing a component. You don't have to ask a coworker which class name to use or what modifiers would work best, or refer to outdated or poorly written style guidelines. Instead, you can simply write the necessary CSS classes to achieve the design, without unnecessary delays or complications.

Functional programming in CSS removes much of the mystery and concern associated with traditional CSS development. Developers no longer have to worry about the impact of their changes on other parts of the site, or whether their modifications will increase the product's technical debt. This simplifies the development process, reduces stress, and increases the speed and efficiency of development. By making the code more explicit, functional CSS programming makes it easier for employees to focus on their work without worrying about unintended consequences or conflicts with existing code.

It's often overlooked that taking over existing projects can be a complicated and challenging process

It's easy to assume that we'll always remember the code we've written. We tend to feel secure because we wrote the code ourselves, thinking that we can pick up a project in the future and continue working on it as if it were done today. However, in reality, this hasn't always been the case in my career, and I've noticed the same with students. We might have a better idea of what's been done, but we may not have a complete understanding of it. We tend to use the same names and structures over and over again, which can make us feel familiar with our code, but there are always more specific cases that can be difficult to remember.

Recently, I rewrote a large personal project from BEM to FCSS, and it was surprising to see how lost one can become and the mistakes one can find when reading old code. The original file, uncompressed, was 42.9KB, but the final FCSS file was only 12.6KB. Every ten minutes of code analysis, I would find myself thinking "I would have done this differently." Sometimes, I even pulled my hair out when I realized how complicated it was when I originally coded something. However, with FCSS, I no longer have to worry about relearning how I made the grid in a project. The architecture is abstracted from the CSS, so I can focus on making relevant changes where they're needed. I can come back to a personal project I've been porting to UCSS after two months and feel like I was coding it today.

Why is it possible to work with Functional CSS?

Some people on Hacker News and Twitter have expressed concerns when working on projects with functional CSS. Their worries stem from the comfort of development, project complexity (can I achieve X with functional CSS?), speed, learning curve, and more. All of these concerns can be resolved by starting with a small personal project and seeing the results before scaling up to larger projects. Perhaps at first, you may feel awkward, but after experiencing the benefits of functional CSS, you will never want to go back.

In my case, CSS programming has reduced the amount of time used to build and deliver the product by at least 3/4. Regarding complexity, this is where I have noticed the most significant benefits: I no longer have to think about the architecture, but rather what properties my component needs to match the given design 100%. The speed of composition using one-use classes is incredibly fast. Although the speed may vary from person to person, in general, there is a noticeable increase in working speed once you become accustomed to it.

Like all methodologies, it requires practice until it becomes the default option in your workflow. It will take less time to learn how to code with UCSS than to understand the proper way of doing CSS architecture for your projects.