There has been controversy about Atomic CSS (or Functional CSS if you prefer). Much has been written, but what about some cold hard numbers? What happens when you refactor your CSS architecture, then build on top of it in the months and years that follow?
At Gesture, we have created a mobile fundraising platform that nonprofits use at charity events. Most people who interact with our product are donors at these events, and do so via their phones. Delivering a performant web experience is essential when a fast connection is not guaranteed.
When I joined our company as its first full-time front-end developer almost 4 years ago, we were using a traditional “semantic” CSS approach. Let’s look at the stats as our platform continued to grow, starting from way back when.
Number of Commits: 575
Test Suite: 702
Repo Size: 445MB
CSS File Size: 109.4kb* (41 css files)
*Note: CSS file size stats are prior to gzip compression
My first task was to implement responsive web design into our product so our layouts would adapt for all screen sizes.
Number of Commits: 925
Test Suite: 743 tests
Repo Size: 465MB
CSS File Size: 123.1kb (41 css files)
Our CSS was spread out over a number of files. So my next task was to combine those many stylesheets into one that would have less duplication and be cached for faster page loads as people navigate our fundraising sites.
Number of Commits: 1500
Test Suite: 813 tests
Repo Size: 467MB
CSS File Size: 105.6kb (1 file)
Over time, we added more functionality to our platform, like integrated ticketing, responsive sponsorship ad units, dashboard reporting and many more features. As we did so, our CSS continued to grow as well.
Number of Commits: 4812
Test Suite: 1088 tests
Repo Size: 482MB
CSS File Size: 151.2kb
As you can see above, one year later using a traditional semantic CSS approach, our CSS grew by 43% compared to a 3% growth in our repo size.
Over the next few months, in addition to our regular product development, our company underwent a rebrand. The look and feel of our product made a leap forward, but our core CSS continued to grow.
Number of Commits: 7726
Test Suite: 1373 tests
Repo Size: 485MB
CSS File Size: 183.2kb
Our CSS was growing at an unsustainable pace. I culled unused styles, optimizing where I could. I separated the admin styles from our core customer-facing product. By October, I had made some gains.
Number of Commits: 9692
Test Suite: 1505 tests
Repo Size: 487MB
CSS File Size: 116.8kb
Not bad, but I wanted to get below 100kb.
I looked through our stylesheet, I saw the same property declarations over and over again. DRY is one of the core principles of software development that has always led me in the right direction.
We were using simple grid and utility spacing classes to handle the structure of our pages, making it easy to do responsive layouts. That approach also reduced the number of margin, padding and width declarations in our CSS. Could we not apply this same strategy to the rest of our styling?
I researched the idea of using utility classes based on visual design patterns instead of traditional “semantic” CSS. There were a few proponents of the technique, but it has become so ingrained in us that our class names have to be semantic that many reject the idea outright.
One by one, I replaced common style declarations across various classes with a single atomic class. It was actually fairly easy. “Why isn’t everyone doing this?” I thought.
Number of Commits: 9830
Test Suite: 1508 tests
Repo Size: 491MB
CSS File Size: 81.3kb
The results speak for themselves. Refactoring our CSS to the functional approach led to a 30% decrease in size. It could have been even smaller, but we left some legacy styles in place to refactor at a later time.
It is fairly simple to create small, performant CSS at the beginning of a project. The true test is what happens at scale, after new features and views are added, designs evolve, business pressures mount, team members come and go and so on.
Number of Commits: 20257
Test Suite: 2046 tests
Repo Size: 593MB
CSS File Size: 72.7kb
Over a year and a half later, despite shipping new features and functionality every 2 weeks, our CSS has actually shrunk by 10% as we phase out legacy styles.
For example, we added a new feature, seating management, which allows our clients to drag and drop guests into table assignments for their event. It was a new view with new UI. There was no new CSS. Our design system already had the styles we needed.
This is the power of Atomic CSS. Despite being contrary to supposed best practices, its popularity continues to grow because it is uniquely suited to building web applications that scale.
Nicolas Gallagher said it best back in 2012:
For individuals weaned on an ideology where “semantic HTML” means using content-derived class names (and even then, only as a last resort), it usually requires you to work on a large application before you can become acutely aware of the impractical nature of that approach. You have to be prepared to discard old ideas, look at alternatives, and even revisit ways that you may have previously dismissed.
It is an exciting time to work on the web. The pace of change is daunting, but there is great opportunity for those with open, curious minds.