Friday, March 29, 2024

Brief Introduction to Functional CSS

If you haven’t heard about Functional CSS (or Atomic CSS/utility classes/Immutable CSS… it really doesn’t have a defined name), it’s the idea that instead of writing large monolithic chunks of CSS, you write small, unique, immutable property classes that can be assembled to form large components in HTML.

Your CSS most likely resembles the code below:

.p1 { padding: 0.5rem; }
.flex { display: flex }
.red { color: red; }

Which will build your HTML something like this:

<div class="flex p1 red">
  Flexbox div with 1 padding unit and red text!
</div>

I love writing CSS classes with those smart and powerful properties. I argue for this because it’s simple for the developer to use. My goal is that the developer can add a single class to the element and it automatically transforms without it having to do anything.

This is simply the opposite of Functional CSS.

In this [monolithic] model, you will never stop writing CSS. Refactoring CSS is difficult and often time consuming, as is deleting unused CSS. And it’s just not a job that people are excited to do. So, what happens? Everyone keeps writing more CSS.

It’s nice to start a new project and write all those component-based planned CSS declarations. But deep down, I know I won’t always be there, and in monolithic mode, the team will never stop writing CSS.

Raise your hand if you’ve worked with any CSS code base that didn’t give you a headache? Usually, the issue is not because the code base started out wrong. It’s because, to write CSS, we are taught to write more code to fix problems. And by extracting another sentence from the text, we have reached a point in our career that, “Today, I don’t really care what I can do with CSS. I’m more interested in knowing and helping groups of people to do CSS.”

Great examples of this approach are Basscss and Tachyons.

I was already convinced to try this new paradigm, and I had a chance to start a new project for a client using this approach.

After 3 months of writing Functional CSS to architect the project, I need to say it’s addicting! And during this project, I also had to work on other projects that used the monolithic idea, which was becoming tedious and boring, skipping from file to file often,S and so on.

I think I was convinced, but I’m still trying to visualize the scalability and issues that Functional CSS brings to the code base, especially as the code — and the team — grows. If you have already tried, please leave your thoughts below.

Velocity

I was always one of those who said, “I can design in code” and always preferred to leave the design document blank (either from Sketch or PS). I joked about it and I think it involves two parts of my brain that don’t communicate well.

What I realized using Functional CSS is that it was the context change that killed my creativity. I could have a nice design idea, at this point I would have to change my context to the CSS file, start imagining the element, name it, think of the box-model, DOM implications, etc. It’s as if my creativity went downhill.

Now, I browse HTML, writing my components and quickly changing their structure. Using Basscss and some product-specific declarations of around 75 lines, I was able to build the homepage with the necessary components in less than an hour. Let’s say this approach passed the time test! That alone gives me peace of mind to continue using this approach. It’s kind of addictive, and it’s hard to want to go back. As Jon Gold said, “The best CSS is the smallest CSS possible.”

From a design perspective, Functional CSS frees you from making code-related decisions while you are designing. By the way, the decisions have already been made, and you’re simply mixing and finding patterns to achieve the style you want, just as you do with shapes, colors, and spaces in Sketch.

Transferability

Usually in the projects today, the design and development teams have an agreement that every design has to have an HTML/CSS prototype and the development team will port it to the real environment/product.

A prototype gives the design team enough feedback to improve interface details without the hassle of learning JavaScript or frameworks like React and Angular. The problem we encountered in this process is more related to HTML. For example, a directive might wrap its component in another HTML tag and the declared CSS doesn’t work as expected.

In the past, this has resulted in maintaining app-specific declarations to override definitions, which over time only generated more bugs (and poor-quality CSS). By using Functional CSS, adjustments can be made by simply changing a class in HTML. This allows the team to fix bugs without creating more CSS.

Writing more CSS to fix your CSS bugs is the wrong way to fix your CSS!

Stop making decisions — at least unnecessary ones! Basscss offers standard spacing and size utilities. Deleting options is liberating. Only allowing 8px, 16px, 26px, etc., line spacing, you simply set the strategies to small/medium and large, and you’re done.

But you might say, “Oh, that takes away my creativity.” But I assure you, it will make your life much easier as a designer or developer. You can then focus on the real problem.

Cascade Loss

Since we are using small specific classes directly in HTML, this means that we will lose all the benefits of the ripple effect. It’s amazing when you create your first component but updating styles on an existing system can be tricky, it’s a mix of “search and replace” and other shortcuts.

A simple way to update styles that are close to each other in the same file is to use your editor’s multi-cursor option. As with Sublime Text and Atom, you can press ?-D (on Mac) to select multiple texts.

Using Multi-cursor in Atom

This assumes that you have created similar components and that you are following an equal naming order. This is not even important, especially for searching and replacing in multiple files. Other than that, it is not simple to search multiple files within your application to find similar components.

This was one of — if not the only — major pain points when implementing Functional CSS in a large app. Try to imagine a common component, such as a box, that is made of up to 710 classes. If you want to update the font size of all the boxes, you will have to look for all the statements within your app. This leaves room for error.

Component Reusability

With Functional CSS, creating a “component” is simple, a matter of just joining several classes. Reusing these components means using these same classes in different places. Once again, leaving open a space for errors.

The long-term solution would be to implement some kind of style guide to document all the components and make it centrally available. Documenting them still has the benefit of being able to describe the required options, class types to be able to mix and result in variations of the same component, etc. For example, a Card component may have different background colors if we simply replace the bg-color class.

Combine this with the loss of the ripple effect and the quest to upgrade components. These were some of the challenges I encountered while implementing Functional CSS.

A simple way to fix this would be to add a class name to your component, with the unique mission of serving as an anchor for when you look for instances of that component in your code.

<div class="box-component flex p2 bg-blue white h4 bold">
 The .box-component class exists only as an anchor for naming all instances of this component.
</div>

These class types are simple to add here and there. But be absolutely sure that you are not applying any CSS to them.

Responsive Design

If your design changes a lot during breakpoints, your class name will be big and verbose for sure. If possible, start early by declaring the units responsive. An example class=”m2 md-m0″, this element will receive 2 units of space until it reaches breakpoint md, where it will compute zero from there onwards.

A situation could be, for example, applying these ideas to navigation that turned into a mobile slide menu, and desktop was a horizontal list. This component can quickly get out of control:

<nav class="fixed top-0 right-0 bottom-0 left-0 z4 bg-red flex-start md-relative md-flex-auto md-min-width-0">
 <! -- more code here -- >
</nav>

When your design varies widely across breakpoints, it can be challenging to implement the required classes (and as we talked about above, the order of your classes starts to be a problem too  — let’s talk more about that now).

To counter this, we set a standard for responsiveness  — naming convention, breakpoints, and min-width and max-width standards.

Controlling State

A common situation in which you have a component hidden by default and clicking on something shows it. Writing in the monolithic CSS standard, we would have something like:

.nav { display: none; }
.nav.is-open { display: block; }

One JavaScript class that would be responsible for toggle is the is-open class. Now instead, my JavaScript will do the toggle of the .block (or similar) utility class:

<nav class="hide block">
 .block will be toggled via JavaScript to show/hide this element.
</nav>

It’s not too complicated in a small component for demo questions. However, even in this case, you have to make sure that .block will overwrite .hide or remove .hide completely via JavaScript. In a more complicated component, let’s say, where the positions and styles change too, is a big list to remember to toggle in JavaScript.

I didn’t see a big problem here, but it’s certainly easier to define your component in CSS and just swap one class.

Class Order Pattern

Any project with more than one developer will have some kind of pattern around how the classes should be placed. Otherwise, you will struggle with any class definition to know what is being declared.

Personally, I’m a fan of Concentric CSS. Not only for the order of the classes, but your team must define whether to group all breakpoints or not:

<div class="flex m0 p0 md-m2 md-p2">
 Breakpoints are grouped
</div>

or in order of priority:

<div class="flex m0 md-m2 p0 md-p2">
 The props are grouped
</div>

Conclusion

Overall, I’m pretty happy using a functional approach to CSS. It’s one of those things that when you visualize, you start paying attention, and every time I start writing CSS monolithically, my brain already signals a lack of interest in this model. Sometimes I find myself wishing I didn’t write CSS anymore. I want to write some classes at the beginning of the project and form the design from the union of these blocks. Having to make decisions in the middle of the project gives you the feeling of being out of place. Sometimes we spend a lot more time writing CSS than fixing usability issues (in this case).

About the Author

Diogo Souza works as a Java Developer at PagSeguro and has worked for companies such as Indra Company, Atlantic Institute and Ebix LA. He is also an Android trainer, speaker at events on Java and mobile world.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured